From 18256b024ea232d5e6d5050ec3e193b6b6c57d7b Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 16 Mar 2024 16:08:10 +0100 Subject: [PATCH] Forbid jQuery `.prop` and fix related issues (#29832) The issue checkbox code received a few more cleanups and I specifically tested it. The other changes are trivial. Also, I checked the cases for how many elements match the jQuery selection to determine querySelector vs. querySelectorAll. --------- Co-authored-by: Giteabot (cherry picked from commit 21fe512aac42c9ce3440b8eaae6b2cb2116a0e50) --- .eslintrc.yaml | 4 +-- web_src/js/features/admin/common.js | 2 +- web_src/js/features/comp/LabelEdit.js | 6 ++--- web_src/js/features/repo-editor.js | 14 +++++----- web_src/js/features/repo-issue-list.js | 36 ++++++++++++++++---------- web_src/js/features/repo-legacy.js | 2 +- 6 files changed, 37 insertions(+), 27 deletions(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 0003ba95e1..b62b13cefe 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -315,7 +315,7 @@ rules: jquery/no-parent: [0] jquery/no-parents: [0] jquery/no-parse-html: [2] - jquery/no-prop: [0] + jquery/no-prop: [2] jquery/no-proxy: [2] jquery/no-ready: [2] jquery/no-serialize: [2] @@ -466,7 +466,7 @@ rules: no-jquery/no-parse-html: [2] no-jquery/no-parse-json: [2] no-jquery/no-parse-xml: [2] - no-jquery/no-prop: [0] + no-jquery/no-prop: [2] no-jquery/no-proxy: [2] no-jquery/no-ready-shorthand: [2] no-jquery/no-ready: [2] diff --git a/web_src/js/features/admin/common.js b/web_src/js/features/admin/common.js index 5354216e3d..31d840c3e1 100644 --- a/web_src/js/features/admin/common.js +++ b/web_src/js/features/admin/common.js @@ -49,7 +49,7 @@ export function initAdminCommon() { } function onUsePagedSearchChange() { - if ($('#use_paged_search').prop('checked')) { + if (document.getElementById('use_paged_search').checked) { showElem('.search-page-size'); $('.search-page-size').find('input').attr('required', 'required'); } else { diff --git a/web_src/js/features/comp/LabelEdit.js b/web_src/js/features/comp/LabelEdit.js index 2e7e1df669..26800ae05c 100644 --- a/web_src/js/features/comp/LabelEdit.js +++ b/web_src/js/features/comp/LabelEdit.js @@ -14,7 +14,7 @@ function updateExclusiveLabelEdit(form) { if (isExclusiveScopeName($nameInput.val())) { $exclusiveField.removeClass('muted'); $exclusiveField.removeAttr('aria-disabled'); - if ($exclusiveCheckbox.prop('checked') && $exclusiveCheckbox.data('exclusive-warn')) { + if ($exclusiveCheckbox[0].checked && $exclusiveCheckbox.data('exclusive-warn')) { $exclusiveWarning.removeClass('gt-hidden'); } else { $exclusiveWarning.addClass('gt-hidden'); @@ -50,10 +50,10 @@ export function initCompLabelEdit(selector) { $nameInput.val($(this).data('title')); const $isArchivedCheckbox = $('.edit-label .label-is-archived-input'); - $isArchivedCheckbox.prop('checked', this.hasAttribute('data-is-archived')); + $isArchivedCheckbox[0].checked = this.hasAttribute('data-is-archived'); const $exclusiveCheckbox = $('.edit-label .label-exclusive-input'); - $exclusiveCheckbox.prop('checked', this.hasAttribute('data-exclusive')); + $exclusiveCheckbox[0].checked = this.hasAttribute('data-exclusive'); // Warn when label was previously not exclusive and used in issues $exclusiveCheckbox.data('exclusive-warn', $(this).data('num-issues') > 0 && diff --git a/web_src/js/features/repo-editor.js b/web_src/js/features/repo-editor.js index fea98e2df8..ba00573c07 100644 --- a/web_src/js/features/repo-editor.js +++ b/web_src/js/features/repo-editor.js @@ -67,10 +67,10 @@ export function initRepoEditor() { $('.js-quick-pull-choice-option').on('change', function () { if ($(this).val() === 'commit-to-new-branch') { showElem($('.quick-pull-branch-name')); - $('.quick-pull-branch-name input').prop('required', true); + document.querySelector('.quick-pull-branch-name input').required = true; } else { hideElem($('.quick-pull-branch-name')); - $('.quick-pull-branch-name input').prop('required', false); + document.querySelector('.quick-pull-branch-name input').required = false; } $('#commit-button').text($(this).attr('button_text')); }); @@ -135,13 +135,13 @@ export function initRepoEditor() { // Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage // to enable or disable the commit button - const $commitButton = $('#commit-button'); + const commitButton = document.getElementById('commit-button'); const $editForm = $('.ui.edit.form'); const dirtyFileClass = 'dirty-file'; // Disabling the button at the start if ($('input[name="page_has_posted"]').val() !== 'true') { - $commitButton.prop('disabled', true); + commitButton.disabled = true; } // Registering a custom listener for the file path and the file content @@ -151,7 +151,7 @@ export function initRepoEditor() { fieldSelector: ':input:not(.commit-form-wrapper :input)', change() { const dirty = $(this).hasClass(dirtyFileClass); - $commitButton.prop('disabled', !dirty); + commitButton.disabled = !dirty; }, }); @@ -163,7 +163,7 @@ export function initRepoEditor() { editor.setValue(value); } - $commitButton.on('click', (event) => { + commitButton?.addEventListener('click', (e) => { // A modal which asks if an empty file should be committed if ($editArea.val().length === 0) { $('#edit-empty-content-modal').modal({ @@ -171,7 +171,7 @@ export function initRepoEditor() { $('.edit.form').trigger('submit'); }, }).modal('show'); - event.preventDefault(); + e.preventDefault(); } }); })(); diff --git a/web_src/js/features/repo-issue-list.js b/web_src/js/features/repo-issue-list.js index 21f1865732..48b1555c89 100644 --- a/web_src/js/features/repo-issue-list.js +++ b/web_src/js/features/repo-issue-list.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import {updateIssuesMeta} from './repo-issue.js'; -import {toggleElem, hideElem} from '../utils/dom.js'; +import {toggleElem, hideElem, isElemHidden} from '../utils/dom.js'; import {htmlEscape} from 'escape-goat'; import {confirmModal} from './comp/ConfirmModal.js'; import {showErrorToast} from '../modules/toast.js'; @@ -8,32 +8,42 @@ import {createSortable} from '../modules/sortable.js'; import {DELETE, POST} from '../modules/fetch.js'; function initRepoIssueListCheckboxes() { - const $issueSelectAll = $('.issue-checkbox-all'); - const $issueCheckboxes = $('.issue-checkbox'); + const issueSelectAll = document.querySelector('.issue-checkbox-all'); + const issueCheckboxes = document.querySelectorAll('.issue-checkbox'); const syncIssueSelectionState = () => { - const $checked = $issueCheckboxes.filter(':checked'); - const anyChecked = $checked.length !== 0; - const allChecked = anyChecked && $checked.length === $issueCheckboxes.length; + const checkedCheckboxes = Array.from(issueCheckboxes).filter((el) => el.checked); + const anyChecked = Boolean(checkedCheckboxes.length); + const allChecked = anyChecked && checkedCheckboxes.length === issueCheckboxes.length; if (allChecked) { - $issueSelectAll.prop({'checked': true, 'indeterminate': false}); + issueSelectAll.checked = true; + issueSelectAll.indeterminate = false; } else if (anyChecked) { - $issueSelectAll.prop({'checked': false, 'indeterminate': true}); + issueSelectAll.checked = false; + issueSelectAll.indeterminate = true; } else { - $issueSelectAll.prop({'checked': false, 'indeterminate': false}); + issueSelectAll.checked = false; + issueSelectAll.indeterminate = false; } // if any issue is selected, show the action panel, otherwise show the filter panel toggleElem($('#issue-filters'), !anyChecked); toggleElem($('#issue-actions'), anyChecked); // there are two panels but only one select-all checkbox, so move the checkbox to the visible panel - $('#issue-filters, #issue-actions').filter(':visible').find('.issue-list-toolbar-left').prepend($issueSelectAll); + const panels = document.querySelectorAll('#issue-filters, #issue-actions'); + const visiblePanel = Array.from(panels).find((el) => !isElemHidden(el)); + const toolbarLeft = visiblePanel.querySelector('.issue-list-toolbar-left'); + toolbarLeft.prepend(issueSelectAll); }; - $issueCheckboxes.on('change', syncIssueSelectionState); + for (const el of issueCheckboxes) { + el.addEventListener('change', syncIssueSelectionState); + } - $issueSelectAll.on('change', () => { - $issueCheckboxes.prop('checked', $issueSelectAll.is(':checked')); + issueSelectAll.addEventListener('change', () => { + for (const el of issueCheckboxes) { + el.checked = issueSelectAll.checked; + } syncIssueSelectionState(); }); diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 10c25bf28b..96cfa78d0b 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -533,7 +533,7 @@ export function initRepository() { const gitignores = $('input[name="gitignores"]').val(); const license = $('input[name="license"]').val(); if (gitignores || license) { - $('input[name="auto_init"]').prop('checked', true); + document.querySelector('input[name="auto_init"]').checked = true; } }); }