From 69a991da727a80af84d4c5b261e1606f482e8168 Mon Sep 17 00:00:00 2001 From: Keegan Leary Date: Fri, 10 Jan 2025 11:03:15 -0800 Subject: [PATCH] refactor FOUC strategy with wf-cloak attribute --- dist/index.js | 88 ++++++++++++++++++++++++++++++- dist/index.js.map | 4 +- src/components/mc-quiz/mc-quiz.ts | 10 ++-- 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/dist/index.js b/dist/index.js index 2d0a078..b34c1d1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1,87 @@ -"use strict";(()=>{var o=Object.defineProperty;var c=(i,e,r)=>e in i?o(i,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):i[e]=r;var t=(i,e,r)=>c(i,typeof e!="symbol"?e+"":e,r);var n=class n{constructor(e){t(this,"quizElement");t(this,"answer");t(this,"inputElements");t(this,"submitButton");t(this,"questionWrapperElement");t(this,"correctWrapperElement");t(this,"incorrectWrapperElement");t(this,"quizParentElement");this.quizElement=e;let r=e.getAttribute(n.ANSWER_ATTRIBUTE_NAME);this.answer=r?parseInt(r,10):NaN,this.inputElements=e.querySelectorAll("input"),this.submitButton=e.querySelector("button"),this.questionWrapperElement=e.children[0],this.correctWrapperElement=e.children[1],this.incorrectWrapperElement=e.children[2],this.quizParentElement=e.parentElement,this.setup()}setup(){if(!this.isValidQuiz()){console.error(`Quiz ${this.quizElement.getAttribute(n.ATTRIBUTE_NAME)} is invalid.`);return}this.correctWrapperElement.style.display="none",this.incorrectWrapperElement.style.display="none",this.submitButton?.addEventListener("click",()=>this.checkAnswer())}isValidQuiz(){return!(isNaN(this.answer)||this.inputElements.length===0||!this.submitButton||!this.correctWrapperElement||!this.incorrectWrapperElement)}checkAnswer(){let e=-1;this.inputElements.forEach((l,a)=>{l.checked&&(e=a)}),e+1===this.answer?this.showFeedback(!0):this.showFeedback(!1)}showFeedback(e){this.questionWrapperElement.style.display="none",this.correctWrapperElement.style.display=e?"block":"none",this.incorrectWrapperElement.style.display=e?"none":"block",this.quizParentElement&&(e?this.quizParentElement.classList.add(n.CORRECT_ANSWER_CLASS_COMBO):this.quizParentElement.classList.add(n.INCORRECT_ANSWER_CLASS_COMBO))}static initializeAll(){document.querySelectorAll(`[${n.ATTRIBUTE_NAME}]`).forEach(r=>new n(r))}};t(n,"ATTRIBUTE_NAME","wf-quiz-mc"),t(n,"ANSWER_ATTRIBUTE_NAME","wf-quiz-mc-answer"),t(n,"CORRECT_ANSWER_CLASS_COMBO","is-correct"),t(n,"INCORRECT_ANSWER_CLASS_COMBO","is-wrong");var s=n;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{s.initializeAll()});})(); +"use strict"; +(() => { + // bin/live-reload.js + new EventSource(`${"http://localhost:3000"}/esbuild`).addEventListener("change", () => location.reload()); + + // src/components/mc-quiz/mc-quiz.ts + var MultipleChoiceQuiz = class _MultipleChoiceQuiz { + static ATTRIBUTE_NAME = "wf-quiz-mc"; + static ANSWER_ATTRIBUTE_NAME = "wf-quiz-mc-answer"; + static CORRECT_ANSWER_CLASS_COMBO = "is-correct"; + static INCORRECT_ANSWER_CLASS_COMBO = "is-wrong"; + quizElement; + answer; + inputElements; + submitButton; + questionWrapperElement; + correctWrapperElement; + incorrectWrapperElement; + quizParentElement; + constructor(quizElement) { + this.quizElement = quizElement; + const answerAttribute = quizElement.getAttribute(_MultipleChoiceQuiz.ANSWER_ATTRIBUTE_NAME); + this.answer = answerAttribute ? parseInt(answerAttribute, 10) : NaN; + this.inputElements = quizElement.querySelectorAll("input"); + this.submitButton = quizElement.querySelector("button"); + this.questionWrapperElement = quizElement.children[0]; + this.correctWrapperElement = quizElement.children[1]; + this.incorrectWrapperElement = quizElement.children[2]; + this.quizParentElement = quizElement.parentElement; + this.setup(); + } + setup() { + if (!this.isValidQuiz()) { + console.error( + `Quiz ${this.quizElement.getAttribute(_MultipleChoiceQuiz.ATTRIBUTE_NAME)} is invalid.` + ); + return; + } + this.submitButton?.addEventListener("click", () => this.checkAnswer()); + } + isValidQuiz() { + if (isNaN(this.answer) || this.inputElements.length === 0 || !this.submitButton || !this.correctWrapperElement || !this.incorrectWrapperElement) { + return false; + } + return true; + } + checkAnswer() { + let selectedAnswerIndex = -1; + this.inputElements.forEach((input, index) => { + if (input.checked) { + selectedAnswerIndex = index; + } + }); + const oneIndexedSelectedAnswer = selectedAnswerIndex + 1; + if (oneIndexedSelectedAnswer === this.answer) { + this.showFeedback(true); + } else { + this.showFeedback(false); + } + } + showFeedback(isCorrect) { + this.questionWrapperElement.setAttribute("wf-cloak", "1"); + if (this.quizParentElement) { + if (isCorrect) { + this.correctWrapperElement.removeAttribute("wf-cloak"); + this.quizParentElement.classList.add(_MultipleChoiceQuiz.CORRECT_ANSWER_CLASS_COMBO); + } else { + this.incorrectWrapperElement.removeAttribute("wf-cloak"); + this.quizParentElement.classList.add(_MultipleChoiceQuiz.INCORRECT_ANSWER_CLASS_COMBO); + } + } + } + static initializeAll() { + const quizzes = document.querySelectorAll( + `[${_MultipleChoiceQuiz.ATTRIBUTE_NAME}]` + ); + quizzes.forEach((quizElement) => new _MultipleChoiceQuiz(quizElement)); + } + }; + + // src/index.ts + window.Webflow ||= []; + window.Webflow.push(() => { + MultipleChoiceQuiz.initializeAll(); + }); +})(); +//# sourceMappingURL=index.js.map diff --git a/dist/index.js.map b/dist/index.js.map index a4a9b6c..c80b099 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../bin/live-reload.js", "../src/components/mc-quiz/mc-quiz.ts", "../src/index.ts"], - "sourcesContent": ["new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener('change', () => location.reload());\n", "export class MultipleChoiceQuiz {\n static ATTRIBUTE_NAME: string = 'wf-quiz-mc';\n static ANSWER_ATTRIBUTE_NAME: string = 'wf-quiz-mc-answer';\n static CORRECT_ANSWER_CLASS_COMBO: string = 'is-correct';\n static INCORRECT_ANSWER_CLASS_COMBO: string = 'is-wrong';\n\n private quizElement: HTMLElement;\n private answer: number;\n private inputElements: NodeListOf;\n private submitButton: HTMLButtonElement | null;\n private questionWrapperElement: HTMLElement;\n private correctWrapperElement: HTMLElement;\n private incorrectWrapperElement: HTMLElement;\n private quizParentElement: HTMLElement | null;\n\n constructor(quizElement: HTMLElement) {\n this.quizElement = quizElement;\n\n const answerAttribute = quizElement.getAttribute(MultipleChoiceQuiz.ANSWER_ATTRIBUTE_NAME);\n this.answer = answerAttribute ? parseInt(answerAttribute, 10) : NaN;\n\n this.inputElements = quizElement.querySelectorAll('input');\n this.submitButton = quizElement.querySelector('button');\n this.questionWrapperElement = quizElement.children[0] as HTMLElement;\n this.correctWrapperElement = quizElement.children[1] as HTMLElement;\n this.incorrectWrapperElement = quizElement.children[2] as HTMLElement;\n this.quizParentElement = quizElement.parentElement;\n\n // Initialize the quiz\n this.setup();\n }\n\n private setup(): void {\n if (!this.isValidQuiz()) {\n console.error(\n `Quiz ${this.quizElement.getAttribute(MultipleChoiceQuiz.ATTRIBUTE_NAME)} is invalid.`\n );\n return;\n }\n\n // Hide feedback elements initially\n this.correctWrapperElement.style.display = 'none';\n this.incorrectWrapperElement.style.display = 'none';\n\n // Attach event listener\n this.submitButton?.addEventListener('click', () => this.checkAnswer());\n }\n\n private isValidQuiz(): boolean {\n if (\n isNaN(this.answer) ||\n this.inputElements.length === 0 ||\n !this.submitButton ||\n !this.correctWrapperElement ||\n !this.incorrectWrapperElement\n ) {\n return false;\n }\n return true;\n }\n\n private checkAnswer(): void {\n let selectedAnswerIndex = -1;\n\n this.inputElements.forEach((input, index) => {\n if (input.checked) {\n selectedAnswerIndex = index;\n }\n });\n\n const oneIndexedSelectedAnswer = selectedAnswerIndex + 1;\n\n if (oneIndexedSelectedAnswer === this.answer) {\n this.showFeedback(true);\n } else {\n this.showFeedback(false);\n }\n }\n\n private showFeedback(isCorrect: boolean): void {\n // Show the correct or incorrect wrapper based on the answer\n this.questionWrapperElement.style.display = 'none';\n this.correctWrapperElement.style.display = isCorrect ? 'block' : 'none';\n this.incorrectWrapperElement.style.display = isCorrect ? 'none' : 'block';\n\n if (this.quizParentElement) {\n if (isCorrect) {\n this.quizParentElement.classList.add(MultipleChoiceQuiz.CORRECT_ANSWER_CLASS_COMBO);\n } else {\n this.quizParentElement.classList.add(MultipleChoiceQuiz.INCORRECT_ANSWER_CLASS_COMBO);\n }\n }\n }\n\n static initializeAll(): void {\n const quizzes = document.querySelectorAll(\n `[${MultipleChoiceQuiz.ATTRIBUTE_NAME}]`\n );\n quizzes.forEach((quizElement) => new MultipleChoiceQuiz(quizElement));\n }\n}\n", "import { MultipleChoiceQuiz } from '$components/mc-quiz/mc-quiz';\n\nwindow.Webflow ||= [];\nwindow.Webflow.push(() => {\n // Initialize all quizzes on the page\n MultipleChoiceQuiz.initializeAll();\n});\n"], - "mappings": ";;;AAAA,MAAI,YAAY,GAAG,uBAAY,UAAU,EAAE,iBAAiB,UAAU,MAAM,SAAS,OAAO,CAAC;;;ACAtF,MAAM,qBAAN,MAAM,oBAAmB;AAAA,IAC9B,OAAO,iBAAyB;AAAA,IAChC,OAAO,wBAAgC;AAAA,IACvC,OAAO,6BAAqC;AAAA,IAC5C,OAAO,+BAAuC;AAAA,IAEtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAER,YAAY,aAA0B;AACpC,WAAK,cAAc;AAEnB,YAAM,kBAAkB,YAAY,aAAa,oBAAmB,qBAAqB;AACzF,WAAK,SAAS,kBAAkB,SAAS,iBAAiB,EAAE,IAAI;AAEhE,WAAK,gBAAgB,YAAY,iBAAmC,OAAO;AAC3E,WAAK,eAAe,YAAY,cAAiC,QAAQ;AACzE,WAAK,yBAAyB,YAAY,SAAS,CAAC;AACpD,WAAK,wBAAwB,YAAY,SAAS,CAAC;AACnD,WAAK,0BAA0B,YAAY,SAAS,CAAC;AACrD,WAAK,oBAAoB,YAAY;AAGrC,WAAK,MAAM;AAAA,IACb;AAAA,IAEQ,QAAc;AACpB,UAAI,CAAC,KAAK,YAAY,GAAG;AACvB,gBAAQ;AAAA,UACN,QAAQ,KAAK,YAAY,aAAa,oBAAmB,cAAc,CAAC;AAAA,QAC1E;AACA;AAAA,MACF;AAGA,WAAK,sBAAsB,MAAM,UAAU;AAC3C,WAAK,wBAAwB,MAAM,UAAU;AAG7C,WAAK,cAAc,iBAAiB,SAAS,MAAM,KAAK,YAAY,CAAC;AAAA,IACvE;AAAA,IAEQ,cAAuB;AAC7B,UACE,MAAM,KAAK,MAAM,KACjB,KAAK,cAAc,WAAW,KAC9B,CAAC,KAAK,gBACN,CAAC,KAAK,yBACN,CAAC,KAAK,yBACN;AACA,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEQ,cAAoB;AAC1B,UAAI,sBAAsB;AAE1B,WAAK,cAAc,QAAQ,CAAC,OAAO,UAAU;AAC3C,YAAI,MAAM,SAAS;AACjB,gCAAsB;AAAA,QACxB;AAAA,MACF,CAAC;AAED,YAAM,2BAA2B,sBAAsB;AAEvD,UAAI,6BAA6B,KAAK,QAAQ;AAC5C,aAAK,aAAa,IAAI;AAAA,MACxB,OAAO;AACL,aAAK,aAAa,KAAK;AAAA,MACzB;AAAA,IACF;AAAA,IAEQ,aAAa,WAA0B;AAE7C,WAAK,uBAAuB,MAAM,UAAU;AAC5C,WAAK,sBAAsB,MAAM,UAAU,YAAY,UAAU;AACjE,WAAK,wBAAwB,MAAM,UAAU,YAAY,SAAS;AAElE,UAAI,KAAK,mBAAmB;AAC1B,YAAI,WAAW;AACb,eAAK,kBAAkB,UAAU,IAAI,oBAAmB,0BAA0B;AAAA,QACpF,OAAO;AACL,eAAK,kBAAkB,UAAU,IAAI,oBAAmB,4BAA4B;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,OAAO,gBAAsB;AAC3B,YAAM,UAAU,SAAS;AAAA,QACvB,IAAI,oBAAmB,cAAc;AAAA,MACvC;AACA,cAAQ,QAAQ,CAAC,gBAAgB,IAAI,oBAAmB,WAAW,CAAC;AAAA,IACtE;AAAA,EACF;;;AClGA,SAAO,YAAY,CAAC;AACpB,SAAO,QAAQ,KAAK,MAAM;AAExB,uBAAmB,cAAc;AAAA,EACnC,CAAC;", + "sourcesContent": ["new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener('change', () => location.reload());\n", "export class MultipleChoiceQuiz {\n static ATTRIBUTE_NAME: string = 'wf-quiz-mc';\n static ANSWER_ATTRIBUTE_NAME: string = 'wf-quiz-mc-answer';\n static CORRECT_ANSWER_CLASS_COMBO: string = 'is-correct';\n static INCORRECT_ANSWER_CLASS_COMBO: string = 'is-wrong';\n\n private quizElement: HTMLElement;\n private answer: number;\n private inputElements: NodeListOf;\n private submitButton: HTMLButtonElement | null;\n private questionWrapperElement: HTMLElement;\n private correctWrapperElement: HTMLElement;\n private incorrectWrapperElement: HTMLElement;\n private quizParentElement: HTMLElement | null;\n\n constructor(quizElement: HTMLElement) {\n this.quizElement = quizElement;\n\n const answerAttribute = quizElement.getAttribute(MultipleChoiceQuiz.ANSWER_ATTRIBUTE_NAME);\n this.answer = answerAttribute ? parseInt(answerAttribute, 10) : NaN;\n\n this.inputElements = quizElement.querySelectorAll('input');\n this.submitButton = quizElement.querySelector('button');\n this.questionWrapperElement = quizElement.children[0] as HTMLElement;\n this.correctWrapperElement = quizElement.children[1] as HTMLElement;\n this.incorrectWrapperElement = quizElement.children[2] as HTMLElement;\n this.quizParentElement = quizElement.parentElement;\n\n // Initialize the quiz\n this.setup();\n }\n\n private setup(): void {\n if (!this.isValidQuiz()) {\n console.error(\n `Quiz ${this.quizElement.getAttribute(MultipleChoiceQuiz.ATTRIBUTE_NAME)} is invalid.`\n );\n return;\n }\n\n // Attach event listener\n this.submitButton?.addEventListener('click', () => this.checkAnswer());\n }\n\n private isValidQuiz(): boolean {\n if (\n isNaN(this.answer) ||\n this.inputElements.length === 0 ||\n !this.submitButton ||\n !this.correctWrapperElement ||\n !this.incorrectWrapperElement\n ) {\n return false;\n }\n return true;\n }\n\n private checkAnswer(): void {\n let selectedAnswerIndex = -1;\n\n this.inputElements.forEach((input, index) => {\n if (input.checked) {\n selectedAnswerIndex = index;\n }\n });\n\n const oneIndexedSelectedAnswer = selectedAnswerIndex + 1;\n\n if (oneIndexedSelectedAnswer === this.answer) {\n this.showFeedback(true);\n } else {\n this.showFeedback(false);\n }\n }\n\n private showFeedback(isCorrect: boolean): void {\n // Show the correct or incorrect wrapper based on the answer\n this.questionWrapperElement.setAttribute('wf-cloak', '1');\n\n if (this.quizParentElement) {\n if (isCorrect) {\n this.correctWrapperElement.removeAttribute('wf-cloak');\n this.quizParentElement.classList.add(MultipleChoiceQuiz.CORRECT_ANSWER_CLASS_COMBO);\n } else {\n this.incorrectWrapperElement.removeAttribute('wf-cloak');\n this.quizParentElement.classList.add(MultipleChoiceQuiz.INCORRECT_ANSWER_CLASS_COMBO);\n }\n }\n }\n\n static initializeAll(): void {\n const quizzes = document.querySelectorAll(\n `[${MultipleChoiceQuiz.ATTRIBUTE_NAME}]`\n );\n quizzes.forEach((quizElement) => new MultipleChoiceQuiz(quizElement));\n }\n}\n", "import { MultipleChoiceQuiz } from '$components/mc-quiz/mc-quiz';\n\nwindow.Webflow ||= [];\nwindow.Webflow.push(() => {\n // Initialize all quizzes on the page\n MultipleChoiceQuiz.initializeAll();\n});\n"], + "mappings": ";;;AAAA,MAAI,YAAY,GAAG,uBAAY,UAAU,EAAE,iBAAiB,UAAU,MAAM,SAAS,OAAO,CAAC;;;ACAtF,MAAM,qBAAN,MAAM,oBAAmB;AAAA,IAC9B,OAAO,iBAAyB;AAAA,IAChC,OAAO,wBAAgC;AAAA,IACvC,OAAO,6BAAqC;AAAA,IAC5C,OAAO,+BAAuC;AAAA,IAEtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAER,YAAY,aAA0B;AACpC,WAAK,cAAc;AAEnB,YAAM,kBAAkB,YAAY,aAAa,oBAAmB,qBAAqB;AACzF,WAAK,SAAS,kBAAkB,SAAS,iBAAiB,EAAE,IAAI;AAEhE,WAAK,gBAAgB,YAAY,iBAAmC,OAAO;AAC3E,WAAK,eAAe,YAAY,cAAiC,QAAQ;AACzE,WAAK,yBAAyB,YAAY,SAAS,CAAC;AACpD,WAAK,wBAAwB,YAAY,SAAS,CAAC;AACnD,WAAK,0BAA0B,YAAY,SAAS,CAAC;AACrD,WAAK,oBAAoB,YAAY;AAGrC,WAAK,MAAM;AAAA,IACb;AAAA,IAEQ,QAAc;AACpB,UAAI,CAAC,KAAK,YAAY,GAAG;AACvB,gBAAQ;AAAA,UACN,QAAQ,KAAK,YAAY,aAAa,oBAAmB,cAAc,CAAC;AAAA,QAC1E;AACA;AAAA,MACF;AAGA,WAAK,cAAc,iBAAiB,SAAS,MAAM,KAAK,YAAY,CAAC;AAAA,IACvE;AAAA,IAEQ,cAAuB;AAC7B,UACE,MAAM,KAAK,MAAM,KACjB,KAAK,cAAc,WAAW,KAC9B,CAAC,KAAK,gBACN,CAAC,KAAK,yBACN,CAAC,KAAK,yBACN;AACA,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEQ,cAAoB;AAC1B,UAAI,sBAAsB;AAE1B,WAAK,cAAc,QAAQ,CAAC,OAAO,UAAU;AAC3C,YAAI,MAAM,SAAS;AACjB,gCAAsB;AAAA,QACxB;AAAA,MACF,CAAC;AAED,YAAM,2BAA2B,sBAAsB;AAEvD,UAAI,6BAA6B,KAAK,QAAQ;AAC5C,aAAK,aAAa,IAAI;AAAA,MACxB,OAAO;AACL,aAAK,aAAa,KAAK;AAAA,MACzB;AAAA,IACF;AAAA,IAEQ,aAAa,WAA0B;AAE7C,WAAK,uBAAuB,aAAa,YAAY,GAAG;AAExD,UAAI,KAAK,mBAAmB;AAC1B,YAAI,WAAW;AACb,eAAK,sBAAsB,gBAAgB,UAAU;AACrD,eAAK,kBAAkB,UAAU,IAAI,oBAAmB,0BAA0B;AAAA,QACpF,OAAO;AACL,eAAK,wBAAwB,gBAAgB,UAAU;AACvD,eAAK,kBAAkB,UAAU,IAAI,oBAAmB,4BAA4B;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,OAAO,gBAAsB;AAC3B,YAAM,UAAU,SAAS;AAAA,QACvB,IAAI,oBAAmB,cAAc;AAAA,MACvC;AACA,cAAQ,QAAQ,CAAC,gBAAgB,IAAI,oBAAmB,WAAW,CAAC;AAAA,IACtE;AAAA,EACF;;;AC9FA,SAAO,YAAY,CAAC;AACpB,SAAO,QAAQ,KAAK,MAAM;AAExB,uBAAmB,cAAc;AAAA,EACnC,CAAC;", "names": [] } diff --git a/src/components/mc-quiz/mc-quiz.ts b/src/components/mc-quiz/mc-quiz.ts index b43cd18..ccee513 100644 --- a/src/components/mc-quiz/mc-quiz.ts +++ b/src/components/mc-quiz/mc-quiz.ts @@ -38,10 +38,6 @@ export class MultipleChoiceQuiz { return; } - // Hide feedback elements initially - this.correctWrapperElement.style.display = 'none'; - this.incorrectWrapperElement.style.display = 'none'; - // Attach event listener this.submitButton?.addEventListener('click', () => this.checkAnswer()); } @@ -79,14 +75,14 @@ export class MultipleChoiceQuiz { private showFeedback(isCorrect: boolean): void { // Show the correct or incorrect wrapper based on the answer - this.questionWrapperElement.style.display = 'none'; - this.correctWrapperElement.style.display = isCorrect ? 'block' : 'none'; - this.incorrectWrapperElement.style.display = isCorrect ? 'none' : 'block'; + this.questionWrapperElement.setAttribute('wf-cloak', '1'); if (this.quizParentElement) { if (isCorrect) { + this.correctWrapperElement.removeAttribute('wf-cloak'); this.quizParentElement.classList.add(MultipleChoiceQuiz.CORRECT_ANSWER_CLASS_COMBO); } else { + this.incorrectWrapperElement.removeAttribute('wf-cloak'); this.quizParentElement.classList.add(MultipleChoiceQuiz.INCORRECT_ANSWER_CLASS_COMBO); } }