-
-
Notifications
You must be signed in to change notification settings - Fork 3k
refactor(modals): remove jquery in ts/modals (@fcasibu) #7292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
refactor(modals): remove jquery in ts/modals (@fcasibu) #7292
Conversation
e92798c to
d0997c2
Compare
| const action = qsr("#editPresetModal .modal").getAttribute("data-action"); | ||
| const propPresetName = qsa<HTMLInputElement>( | ||
| "#editPresetModal .modal input", | ||
| )[0]?.getValue() as string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can likely just query for a specific selector, but uncertain. Same for line 237
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, query the specific one instead.
c45226a to
83a24cb
Compare
83a24cb to
e2f2cc7
Compare
e2f2cc7 to
937446c
Compare
Miodec
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In files that use AnimatedModal, (for example in edit-preset) instead of constantly querying for "#editPresetModal .modal, i think i would prefer using modal.getModal().
So:
qsr("#editPresetModal .modal").setAttribute("data-action", "edit");
becomes:
modal.getModal().setAttribute("data-action", "edit");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors modal files in frontend/ts/modals/* to remove jQuery dependencies and replace them with custom DOM utility methods. The changes add a setValue method for ElementsWithUtils<ElementWithValue> instances and modify toggleClass to accept an optional force parameter.
Key changes:
- Replaced jQuery selectors (
$()) with custom DOM utilities (qs,qsr,qsa) - Replaced jQuery methods like
.val(),.prop(),.attr()with custom wrappers (.getValue(),.setValue(),.isChecked(),.setAttribute(), etc.) - Added event delegation support using
.onChild()for dynamically generated content
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 21 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/ts/utils/dom.ts | Added setValue method to ElementsWithUtils class and optional force parameter to toggleClass |
| frontend/src/ts/modals/word-filter.ts | Removed jQuery selectors and methods, replaced with custom DOM utilities |
| frontend/src/ts/modals/version-history.ts | Replaced jQuery with qsr() for modal content manipulation |
| frontend/src/ts/modals/user-report.ts | Converted jQuery selectors to qsr() for form input retrieval |
| frontend/src/ts/modals/simple-modals.ts | Refactored event handlers from jQuery delegation to .onChild() pattern |
| frontend/src/ts/modals/share-test-settings.ts | Replaced jQuery with custom DOM utilities for checkbox and input handling |
| frontend/src/ts/modals/share-custom-theme.ts | Converted jQuery color input retrieval to qsr().getValue() |
| frontend/src/ts/modals/saved-texts.ts | Replaced jQuery with qs, qsr for list manipulation and event handling |
| frontend/src/ts/modals/save-custom-text.ts | Converted checkbox manipulation from jQuery to custom utilities |
| frontend/src/ts/modals/quote-submit.ts | Replaced jQuery form input retrieval with qsr().getValue() |
| frontend/src/ts/modals/quote-search.ts | Refactored dropdown handling and result list manipulation |
| frontend/src/ts/modals/quote-report.ts | Converted form input retrieval to custom DOM utilities |
| frontend/src/ts/modals/quote-rate.ts | Replaced jQuery text/star manipulation with qsr().setText() |
| frontend/src/ts/modals/quote-approve.ts | Major refactor using createElementWithUtils and custom event handling |
| frontend/src/ts/modals/practise-words.ts | Converted button state management to custom utilities |
| frontend/src/ts/modals/mobile-test-config.ts | Replaced jQuery mode/config button handling |
| frontend/src/ts/modals/last-signed-out-result.ts | Converted result display to custom DOM utilities |
| frontend/src/ts/modals/google-sign-up.ts | Replaced jQuery input retrieval and button state management |
| frontend/src/ts/modals/edit-result-tags.ts | Converted tag button iteration to qsa() |
| frontend/src/ts/modals/edit-profile.ts | Refactored badge selection event handling |
| frontend/src/ts/modals/edit-preset.ts | Complex refactor of preset checkbox and input management |
| frontend/src/ts/modals/dev-options.ts | Replaced jQuery .prepend() with .prependHtml() |
| frontend/src/ts/modals/custom-text.ts | Major refactor of custom text UI state management |
| frontend/src/ts/modals/custom-test-duration.ts | Converted input parsing to custom utilities |
| frontend/src/ts/modals/custom-generator.ts | Replaced jQuery input retrieval with qs().getValue() |
Comments suppressed due to low confidence (1)
frontend/src/ts/modals/saved-texts.ts:109
- Event delegation issue. Same problem - event handlers for dynamically generated content need event delegation.
qs("#savedTextsModal .list .savedText .button.name")?.on("click", (e) => {
const name = (e.target as HTMLElement).textContent;
CustomTextState.setCustomTextName(name, false);
const text = getSavedText(name, false);
hide({ modalChainData: { text, long: false } });
});
qs("#savedTextsModal .listLong .savedLongText .button.name")?.on(
"click",
(e) => {
const name = (e.target as HTMLElement)?.textContent;
CustomTextState.setCustomTextName(name, true);
const text = getSavedText(name, true);
hide({ modalChainData: { text, long: true } });
},
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $("wordFilterModal .presetInput").empty(); | ||
| qsr("#wordFilterModal .languageInput").empty(); | ||
| qsr("#wordFilterModal .layoutInput").empty(); | ||
| qsr("wordFilterModal .presetInput").empty(); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing '#' selector prefix. The selector should be "#wordFilterModal .presetInput" instead of "wordFilterModal .presetInput".
| qsr("wordFilterModal .presetInput").empty(); | |
| qsr("#wordFilterModal .presetInput").empty(); |
| $("#wordFilterModal button.addButton").on("click", () => { | ||
| $("#wordFilterModal .loadingIndicator").removeClass("hidden"); | ||
| qsr("#wordFilterModal button.addButton").on("click", () => { | ||
| qsr("#wordFilterModal .loadingIndicator").show(); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of removeClass("hidden") versus show(). Line 315 uses show() while line 139 uses removeClass("hidden"). These should be consistent - either always use show()/hide() or removeClass("hidden")/addClass("hidden").
| qsr("#versionHistoryModal .modal").setHtml( | ||
| `<div class="releases"></div`, | ||
| ); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setHtml call is missing a closing tag. The HTML string "<div class="releases"></div should be "<div class="releases"></div>" with a closing angle bracket.
| qsr("#versionHistoryModal .modal").setHtml( | ||
| `<div class="releases">${msg}</div`, | ||
| ); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setHtml call is missing a closing tag. The HTML string "<div class="releases">${msg}</div should be "<div class="releases">${msg}</div>" with a closing angle bracket.
| console.log({ updateConfig, propPresetName }); | ||
|
|
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debugging console.log statement should be removed before merging to production.
| console.log({ updateConfig, propPresetName }); |
| $("#savedTextsModal .list .savedText .button.name").on("click", (e) => { | ||
| const name = $(e.target).text(); | ||
| qs("#savedTextsModal .list .savedText .button.name")?.on("click", (e) => { | ||
| const name = (e.target as HTMLElement).textContent; |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential issue with textContent returning null. The textContent property can return null if the element has no text. This should be handled with a null check or use a fallback value to prevent passing null to setCustomTextName.
| "click", | ||
| (e) => { | ||
| const name = $(e.target).text(); | ||
| const name = (e.target as HTMLElement)?.textContent; |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential issue with textContent returning null. The textContent property can return null if the element has no text. This should be handled with a null check or use a fallback value to prevent passing null to setCustomTextName.
| if (state.checkboxes.get(settingGroup)) { | ||
| qsr( | ||
| `#editPresetModal .modal .checkboxList .checkboxTitlePair[data-id="${settingGroup}"] input`, | ||
| ).setAttribute("checked", "true"); | ||
| } else { | ||
| qsr( | ||
| `#editPresetModal .modal .checkboxList .checkboxTitlePair[data-id="${settingGroup}"] input`, | ||
| ).removeAttribute("checked"); | ||
| } |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect implementation for setting checkbox checked state. Using setAttribute/removeAttribute for the "checked" attribute only affects the initial state in the HTML, not the actual checked property. This should use a method that sets the checked property (e.g., .setChecked()) or directly manipulate .native.checked to properly control checkbox state.
| $("#saveCustomTextModal .isLongText").prop("checked", false); | ||
| $("#saveCustomTextModal button.save").prop("disabled", true); | ||
| qsr<HTMLInputElement>("#saveCustomTextModal .textName").setValue(""); | ||
| qsr("#saveCustomTextModal .isLongText").removeAttribute("checked"); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using removeAttribute("checked") to uncheck a checkbox is incorrect. This only removes the HTML attribute but doesn't change the actual checked state of the checkbox. Use a method like .setChecked(false) or directly set .native.checked = false.
| qsr("#saveCustomTextModal .isLongText").removeAttribute("checked"); | |
| qsr<HTMLInputElement>("#saveCustomTextModal .isLongText").setChecked(false); |
| qsa(`${popup} .inputs .group[data-id="limit"] input.sections`)?.show(); | ||
| qsa(`${popup} .inputs .group[data-id="limit"] input.words`)?.hide(); | ||
| } else { | ||
| $(`${popup} .inputs .group[data-id="limit"] input.words`).removeClass( | ||
| "hidden", | ||
| ); | ||
| $(`${popup} .inputs .group[data-id="limit"] input.sections`).addClass( | ||
| "hidden", | ||
| ); | ||
| qsa(`${popup} .inputs .group[data-id="limit"] input.words`)?.show(); | ||
| qsa(`${popup} .inputs .group[data-id="limit"] input.sections`)?.hide(); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect use of qsa on elements. Lines 83-84 and 86-87 use qsa() which returns multiple elements, but then call show()/hide() directly on the result. Since these selectors likely match multiple elements, this is correct usage. However, the inconsistency with lines 63-64 which use qs() for .group elements should be reviewed - if multiple .section elements exist, qsa should be used consistently.
Description
Refactor
frontend/ts/modals/*to replace jQuery (some still TODO). I've also modifieddom.tsto addsetValueforElementsWithUtils<ElementWithValue>instance. Still trying to grep the whole flow/codebase, so usage ofqsrorqsis uncertain (Probably useqsralways? Can find non-existing elements that way or developer error). There are a lot of atomic commits in this PR, feel free to squash.While doing the refactor, also stumbled upon things that I have questions for (didn't made any changes to them), which I thought can be improved:
custom-generator.ts:146: The user is able to write minLength > maxLength. Is this behavior correct?custom-test-duration.ts:99: It seems likeparseInput, always expects a non nullable string, and we seem to always expect that#customTestDurationModal inputto always exist (so I usedqsr), which makes the conditionsval !== null,!isNaN(val)seem to be unnecessary (val is never null or NaN, tbh also isFinite, and val >= 0 is the only valid condition)custom-text.ts:169: These elements does not seem exist.randomWordsCheckbox,.replaceNewlineWithSpace,.typographyCheck, and.delimiterCheck(last two is just in a challenge file). Are they good to remove?edit-preset.ts:146: Noticed that we're not updaitng the DOM, since for the most part, in the logic, we mostly usestate.checkboxes, so no problem happens, but I think it is also a good idea to update the DOM to match current state? Either callingupdateUI()here or just changing the checked value inline.quote-rate.ts:89:getQuoteStatsexpects aquotebut we're not really passing anything to it, so this essentially does nothing, since it returns immediately on!quoteChecks
qs,qsaorqsrinstead of JQuery selectors.Related #7186
#7186