From 3888f6e2c1c3dc25a0274a77fdefed52a26220d0 Mon Sep 17 00:00:00 2001 From: "R. Mamet" Date: Wed, 30 Sep 2026 20:02:17 -0400 Subject: [PATCH 1/3] Add localStorage saving to majorProjectForm --- .../javascript/modules/majorProjectForm.js | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/frontend/javascript/modules/majorProjectForm.js b/frontend/javascript/modules/majorProjectForm.js index 36250529..2ac1c7ec 100644 --- a/frontend/javascript/modules/majorProjectForm.js +++ b/frontend/javascript/modules/majorProjectForm.js @@ -1,13 +1,20 @@ import FetchUtil from "../utils/fetchUtil"; -export default class MajorProjectForm { +const CACHE_KEY = "majorProjectCache" +export default class MajorProjectForm { constructor(form) { this.form = form; this.endpoint = '/major_project/submit'; this.tags_written = false; this.tag_keys = ["Enter", "Comma", "Tab"]; + this.saveState; + try { + this.saveState = JSON.parse(localStorage.getItem(CACHE_KEY)); + } catch (e) { + console.error(e) + } this.render(); } @@ -18,8 +25,28 @@ export default class MajorProjectForm { .addEventListener('focusout', e => this.onWriteSkill(e)); this.form.querySelector('input[id=skill-input]') .addEventListener('keypress', e => this.onKeyPress(e)); + this.form.addEventListener('input', e => this.onInput()); + if (this.saveState) { + for (const [key, value] of Object.entries(this.saveState)) { + if (key === 'skill-list') { + value.forEach((skill) => this.addSkill(skill)); + this.tags_written = true; + continue; + } + this.form.querySelector(`*[name=${key}]`).value = value; + } + } + } + + onInput() { + const formData = new FormData(this.form); + const cachedSkills = JSON.parse(localStorage.getItem(CACHE_KEY))["skill-list"]; + const formDataObject = Object.fromEntries(formData.entries()); + formDataObject['skill-list'] = this.getSkills(); + localStorage.setItem(CACHE_KEY, JSON.stringify(formDataObject)); } + onKeyPress(e) { if (this.tag_keys.includes(e.code)) { e.preventDefault(); @@ -28,6 +55,24 @@ export default class MajorProjectForm { return false; } + getSkills() { + let skills = []; + + for (const tag of this.form.getElementsByClassName('skill-tag')) { + skills.push(tag.textContent); + } + + return skills; + } + + addSkill(skill) { + let input = document.getElementById("skill-input") + let txt = skill.replaceAll(/[^a-zA-Z0-9\+\-\.\# ]/g, ''); // allowed characters Skillslist + if (txt) input.insertAdjacentHTML("beforebegin", '' + txt + ''); + let skills = this.form.getElementsByClassName("skill-tag") + skills.item(skills.length - 1).addEventListener('click', e => this.onRemoveTag(e)); + } + onWriteSkill(e) { let input = document.getElementById("skill-input") if (!this.tags_written) { @@ -36,27 +81,23 @@ export default class MajorProjectForm { const firstTag = document.getElementsByClassName("skill-tag").item(0); if (firstTag) firstTag.remove(); } - - let txt = input.value.replaceAll(/[^a-zA-Z0-9\+\-\.\# ]/g, ''); // allowed characters list - if (txt) input.insertAdjacentHTML("beforebegin", '' + txt + ''); - let skills = this.form.getElementsByClassName("skill-tag") - skills.item(skills.length - 1).addEventListener('click', e => this.onRemoveTag(e)); + this.addSkill(input.value); input.value = ""; + this.onInput() + } onRemoveTag(e) { e.target.remove(); + this.onInput(); } _submitForm(e) { e.preventDefault(); - let skills = []; + const skills = this.getSkills(); + - for (const tag of this.form.getElementsByClassName('skill-tag')) { - skills.push(tag.textContent); - } - let projectName = this.form.querySelector('input[name=name]').value; let projectTldr = this.form.querySelector('input[name=tldr]').value; let projectTimeSpent = this.form.querySelector('textarea[name=time-commitment]').value; @@ -92,4 +133,4 @@ export default class MajorProjectForm { successText: "Your project has been submitted." }); } -} \ No newline at end of file +} From 48593d0ab126546a3925d6d9c4455cd9085e71a9 Mon Sep 17 00:00:00 2001 From: "R. Mamet" Date: Wed, 30 Sep 2026 20:54:31 -0400 Subject: [PATCH 2/3] Delete form contents on submittion --- .../javascript/modules/majorProjectForm.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/frontend/javascript/modules/majorProjectForm.js b/frontend/javascript/modules/majorProjectForm.js index 2ac1c7ec..b56098da 100644 --- a/frontend/javascript/modules/majorProjectForm.js +++ b/frontend/javascript/modules/majorProjectForm.js @@ -40,7 +40,6 @@ export default class MajorProjectForm { onInput() { const formData = new FormData(this.form); - const cachedSkills = JSON.parse(localStorage.getItem(CACHE_KEY))["skill-list"]; const formDataObject = Object.fromEntries(formData.entries()); formDataObject['skill-list'] = this.getSkills(); localStorage.setItem(CACHE_KEY, JSON.stringify(formDataObject)); @@ -92,6 +91,21 @@ export default class MajorProjectForm { this.onInput(); } + clearForm() { + const skills = this.form.getElementsByClassName("skill-tag"); + Array.from(skills).forEach(tag => tag.remove()); + for (const [key, value] of Object.entries(this.saveState)) { + if (key === 'skill-list') { + // We already cleaned the skills ^^ + continue; + } + this.form.querySelector(`*[name=${key}]`).value = ""; + } + this.tags_written = false; + localStorage.removeItem(CACHE_KEY); + } + + _submitForm(e) { e.preventDefault(); @@ -131,6 +145,6 @@ export default class MajorProjectForm { warningText: "You will not be able to edit your " + "project once it has been submitted.", successText: "Your project has been submitted." - }); + }, () => this.clearForm()); } } From 76b693751a62df3b48bc01b069728b31d580a097 Mon Sep 17 00:00:00 2001 From: "R. Mamet" Date: Thu, 1 Oct 2026 09:41:29 -0400 Subject: [PATCH 3/3] Fix indentation, change this.saveState definition --- .../javascript/modules/majorProjectForm.js | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/frontend/javascript/modules/majorProjectForm.js b/frontend/javascript/modules/majorProjectForm.js index b56098da..a46f102d 100644 --- a/frontend/javascript/modules/majorProjectForm.js +++ b/frontend/javascript/modules/majorProjectForm.js @@ -9,12 +9,12 @@ export default class MajorProjectForm { this.endpoint = '/major_project/submit'; this.tags_written = false; this.tag_keys = ["Enter", "Comma", "Tab"]; - this.saveState; - try { - this.saveState = JSON.parse(localStorage.getItem(CACHE_KEY)); - } catch (e) { - console.error(e) - } + try { + this.saveState = JSON.parse(localStorage.getItem(CACHE_KEY)); + } catch (e) { + console.error(e); + this.saveState = {}; + } this.render(); } @@ -25,24 +25,24 @@ export default class MajorProjectForm { .addEventListener('focusout', e => this.onWriteSkill(e)); this.form.querySelector('input[id=skill-input]') .addEventListener('keypress', e => this.onKeyPress(e)); - this.form.addEventListener('input', e => this.onInput()); - if (this.saveState) { - for (const [key, value] of Object.entries(this.saveState)) { - if (key === 'skill-list') { - value.forEach((skill) => this.addSkill(skill)); - this.tags_written = true; - continue; - } - this.form.querySelector(`*[name=${key}]`).value = value; - } - } + this.form.addEventListener('input', e => this.onInput()); + if (this.saveState) { + for (const [key, value] of Object.entries(this.saveState)) { + if (key === 'skill-list') { + value.forEach((skill) => this.addSkill(skill)); + this.tags_written = true; + continue; + } + this.form.querySelector(`*[name=${key}]`).value = value; + } + } } onInput() { const formData = new FormData(this.form); const formDataObject = Object.fromEntries(formData.entries()); - formDataObject['skill-list'] = this.getSkills(); - localStorage.setItem(CACHE_KEY, JSON.stringify(formDataObject)); + formDataObject['skill-list'] = this.getSkills(); + localStorage.setItem(CACHE_KEY, JSON.stringify(formDataObject)); } @@ -55,13 +55,13 @@ export default class MajorProjectForm { } getSkills() { - let skills = []; + let skills = []; for (const tag of this.form.getElementsByClassName('skill-tag')) { skills.push(tag.textContent); } - return skills; + return skills; } addSkill(skill) { @@ -82,7 +82,7 @@ export default class MajorProjectForm { } this.addSkill(input.value); input.value = ""; - this.onInput() + this.onInput() } @@ -95,13 +95,13 @@ export default class MajorProjectForm { const skills = this.form.getElementsByClassName("skill-tag"); Array.from(skills).forEach(tag => tag.remove()); for (const [key, value] of Object.entries(this.saveState)) { - if (key === 'skill-list') { - // We already cleaned the skills ^^ - continue; - } - this.form.querySelector(`*[name=${key}]`).value = ""; - } - this.tags_written = false; + if (key === 'skill-list') { + // We already cleaned the skills ^^ + continue; + } + this.form.querySelector(`*[name=${key}]`).value = ""; + } + this.tags_written = false; localStorage.removeItem(CACHE_KEY); }