From 91610a987e4c805a9305d4ee951963f80dbeb9ee Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 12 Mar 2025 02:35:05 +0800 Subject: [PATCH] Fix various Fomantic UI and htmx problems (#33851) Also fix #31328, fix #33854 --- .dockerignore | 1 - web_src/fomantic/build/components/api.js | 14 ++----- web_src/fomantic/build/components/dropdown.js | 15 +++---- web_src/fomantic/build/fomantic.js | 6 +-- web_src/js/features/repo-diff.ts | 4 +- web_src/js/globals.d.ts | 1 + web_src/js/modules/fomantic.ts | 2 - web_src/js/modules/fomantic/api.ts | 41 ------------------- 8 files changed, 16 insertions(+), 68 deletions(-) delete mode 100644 web_src/js/modules/fomantic/api.ts diff --git a/.dockerignore b/.dockerignore index 37525e02ae..94aca6b8d3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -79,7 +79,6 @@ cpu.out /public/assets/fonts /public/assets/img/avatar /vendor -/web_src/fomantic /VERSION /.air /.go-licenses diff --git a/web_src/fomantic/build/components/api.js b/web_src/fomantic/build/components/api.js index 845046b0d5..a104cfbc1b 100644 --- a/web_src/fomantic/build/components/api.js +++ b/web_src/fomantic/build/components/api.js @@ -754,17 +754,9 @@ $.api = $.fn.api = function(parameters) { ; }, urlEncodedValue: function(value) { - var - decodedValue = window.decodeURIComponent(value), - encodedValue = window.encodeURIComponent(value), - alreadyEncoded = (decodedValue !== value) - ; - if(alreadyEncoded) { - module.debug('URL value is already encoded, avoiding double encoding', value); - return value; - } - module.verbose('Encoding value using encodeURIComponent', value, encodedValue); - return encodedValue; + // GITEA-PATCH: always encode the value. + // Old code does "decodeURIComponent" first to guess whether the value is encoded, it is not right. + return window.encodeURIComponent(value); }, defaultData: function() { var diff --git a/web_src/fomantic/build/components/dropdown.js b/web_src/fomantic/build/components/dropdown.js index 9edd33d11c..d3a1f7dc24 100644 --- a/web_src/fomantic/build/components/dropdown.js +++ b/web_src/fomantic/build/components/dropdown.js @@ -31,9 +31,9 @@ $.fn.dropdown = function(parameters) { moduleSelector = $allModules.selector || '', hasTouch = ('ontouchstart' in document.documentElement), - clickEvent = hasTouch - ? 'touchstart' - : 'click', + // GITEA-PATCH: always "click" as clickEvent, old code used "touchstart" as clickEvent, it is wrong, + // because "touchstart" caused problems when users try to scroll and the touch point is in the dropdown. + clickEvent = 'click', time = new Date().getTime(), performance = [], @@ -768,7 +768,7 @@ $.fn.dropdown = function(parameters) { preSelected = preSelected && preSelected!=="" ? preSelected.split(settings.delimiter) : []; } $.each(preSelected,function(index,value){ - $item.filter('[data-value="'+value+'"]') + $item.filter('[data-value="'+CSS.escape(value)+'"]') // GITEA-PATCH: use "CSS.escape" for query selector .addClass(className.filtered) ; }); @@ -1027,7 +1027,7 @@ $.fn.dropdown = function(parameters) { $input.append(''); $.each(values, function(index, item) { var - value = settings.templates.deQuote(item[fields.value]), + value = settings.templates.escape(item[fields.value]), // GITEA-PATCH: use "escape" for attribute value name = settings.templates.escape( item[fields.name] || '', settings.preserveHTML @@ -4180,13 +4180,14 @@ $.fn.dropdown.settings.templates = { if( itemType === 'item' ) { var maybeText = (option[fields.text]) - ? ' data-text="' + deQuote(option[fields.text]) + '"' + ? ' data-text="' + escape(option[fields.text]) + '"' // GITEA-PATCH: use "escape" for attribute value : '', maybeDisabled = (option[fields.disabled]) ? className.disabled+' ' : '' ; - html += '
'; + // GITEA-PATCH: use "escape" for attribute value + html += '
'; if(option[fields.image]) { html += ''; } diff --git a/web_src/fomantic/build/fomantic.js b/web_src/fomantic/build/fomantic.js index 81a3487492..c903fd1633 100644 --- a/web_src/fomantic/build/fomantic.js +++ b/web_src/fomantic/build/fomantic.js @@ -3,8 +3,4 @@ import './components/dropdown.js'; import './components/modal.js'; import './components/search.js'; -// Hard forked from Fomantic 2.8.7 - -// TODO: need to apply the patch from Makefile -// # fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event -// $(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js +// Hard-forked from Fomantic UI 2.8.7, patches are commented with "GITEA-PATCH" diff --git a/web_src/js/features/repo-diff.ts b/web_src/js/features/repo-diff.ts index 1ecd00f1af..ad1da5c2fa 100644 --- a/web_src/js/features/repo-diff.ts +++ b/web_src/js/features/repo-diff.ts @@ -196,7 +196,9 @@ function initRepoDiffShowMore() { const resp = await response.text(); const respDoc = parseDom(resp, 'text/html'); const respFileBody = respDoc.querySelector('#diff-file-boxes .diff-file-body .file-body'); - el.parentElement.replaceWith(...Array.from(respFileBody.children)); + const respFileBodyChildren = Array.from(respFileBody.children); // respFileBody.children will be empty after replaceWith + el.parentElement.replaceWith(...respFileBodyChildren); + for (const el of respFileBodyChildren) window.htmx.process(el); // FIXME: calling onShowMoreFiles is not quite right here. // But since onShowMoreFiles mixes "init diff box" and "init diff body" together, // so it still needs to call it to make the "ImageDiff" and something similar work. diff --git a/web_src/js/globals.d.ts b/web_src/js/globals.d.ts index 2f8cd98878..9e97ec0492 100644 --- a/web_src/js/globals.d.ts +++ b/web_src/js/globals.d.ts @@ -64,6 +64,7 @@ interface Window { jQuery: typeof import('@types/jquery'), htmx: Omit & { config?: Writable, + process?: (elt: Element | string) => void, }, _globalHandlerErrors: Array & { _inited: boolean, diff --git a/web_src/js/modules/fomantic.ts b/web_src/js/modules/fomantic.ts index d110ac7d97..4b1dbc4f62 100644 --- a/web_src/js/modules/fomantic.ts +++ b/web_src/js/modules/fomantic.ts @@ -1,5 +1,4 @@ import $ from 'jquery'; -import {initFomanticApiPatch} from './fomantic/api.ts'; import {initAriaCheckboxPatch} from './fomantic/checkbox.ts'; import {initAriaFormFieldPatch} from './fomantic/form.ts'; import {initAriaDropdownPatch} from './fomantic/dropdown.ts'; @@ -27,7 +26,6 @@ export function initGiteaFomantic() { initFomanticTransition(); initFomanticDimmer(); initFomanticTab(); - initFomanticApiPatch(); // Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future. initAriaCheckboxPatch(); diff --git a/web_src/js/modules/fomantic/api.ts b/web_src/js/modules/fomantic/api.ts deleted file mode 100644 index 97430450e2..0000000000 --- a/web_src/js/modules/fomantic/api.ts +++ /dev/null @@ -1,41 +0,0 @@ -import $ from 'jquery'; -import type {FomanticInitFunction} from '../../types.ts'; - -export function initFomanticApiPatch() { - // - // Fomantic API module has some very buggy behaviors: - // - // If encodeParameters=true, it calls `urlEncodedValue` to encode the parameter. - // However, `urlEncodedValue` just tries to "guess" whether the parameter is already encoded, by decoding the parameter and encoding it again. - // - // There are 2 problems: - // 1. It may guess wrong, and skip encoding a parameter which looks like encoded. - // 2. If the parameter can't be decoded, `decodeURIComponent` will throw an error, and the whole request will fail. - // - // This patch only fixes the second error behavior at the moment. - // - const patchKey = '_giteaFomanticApiPatch'; - const oldApi = $.api; - $.api = $.fn.api = function(...args: Parameters) { - const apiCall = oldApi.bind(this); - const ret = oldApi.apply(this, args); - - if (typeof args[0] !== 'string') { - const internalGet = apiCall('internal', 'get'); - if (!internalGet.urlEncodedValue[patchKey]) { - const oldUrlEncodedValue = internalGet.urlEncodedValue; - internalGet.urlEncodedValue = function (value: any) { - try { - return oldUrlEncodedValue(value); - } catch { - // if Fomantic API module's `urlEncodedValue` throws an error, we encode it by ourselves. - return encodeURIComponent(value); - } - }; - internalGet.urlEncodedValue[patchKey] = true; - } - } - return ret; - }; - $.api.settings = oldApi.settings; -}