From cf28d2d131146fc9180323bc6140578923e3a828 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 13 Aug 2025 15:27:25 +0400 Subject: [PATCH 1/6] AMD Loader: Ignore duplicated module definitions This fixes an error appearing when chunk is mention multiple times for different entry content scripts. --- src/content/deps/amd.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/content/deps/amd.ts b/src/content/deps/amd.ts index 9f4f525..5c408fd 100644 --- a/src/content/deps/amd.ts +++ b/src/content/deps/amd.ts @@ -2,7 +2,21 @@ import { amdLite } from "amd-lite"; const originalDefine = amdLite.define; +/** + * Set of already defined modules. Used for deduplication. + */ +const definedModules = new Set(); + amdLite.define = (name, dependencies, originalCallback) => { + // Chrome doesn't run the same content script multiple times, while Firefox does. Since each content script and their + // chunks are intended to be run only once, we should just ignore any attempts of running the same module more than + // once. Names of the modules are assumed to be unique. + if (definedModules.has(name)) { + return; + } + + definedModules.add(name); + return originalDefine(name, dependencies, function () { const callbackResult = originalCallback(...arguments); From 79cd9bc44d861544069b21dda57e26b62284c565 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 13 Aug 2025 15:56:31 +0400 Subject: [PATCH 2/6] Reduced the space used by the tag category headline This is mainly affecting the Derpibooru version of the extension. Tags list on Derpibooru is using flex with gaps instead of flex with margins appearing like gaps (what currently Furbooru uses). This change would likely be applied to the Furbooru as well. --- manifest.json | 3 +++ src/lib/components/TagsListBlock.ts | 1 + src/styles/booru-vars.scss | 3 +++ src/styles/content/tags-editor.scss | 23 +++++++++++++++++++++++ 4 files changed, 30 insertions(+) create mode 100644 src/styles/content/tags-editor.scss diff --git a/manifest.json b/manifest.json index f61bc04..0a8c657 100644 --- a/manifest.json +++ b/manifest.json @@ -47,6 +47,9 @@ ], "js": [ "src/content/tags-editor.ts" + ], + "css": [ + "src/styles/content/tags-editor.scss" ] }, { diff --git a/src/lib/components/TagsListBlock.ts b/src/lib/components/TagsListBlock.ts index 01e9a78..d63edd5 100644 --- a/src/lib/components/TagsListBlock.ts +++ b/src/lib/components/TagsListBlock.ts @@ -134,6 +134,7 @@ export class TagsListBlock extends BaseComponent { heading.style.display = 'none'; heading.style.order = `var(${TagsListBlock.#orderCssVariableForGroup(group.id)}, 0)`; heading.style.flexBasis = '100%'; + heading.classList.add('tag-category-headline'); // We're inserting heading to the top just to make sure that heading is always in front of the tags related to // this category. diff --git a/src/styles/booru-vars.scss b/src/styles/booru-vars.scss index 1db638d..462d9c5 100644 --- a/src/styles/booru-vars.scss +++ b/src/styles/booru-vars.scss @@ -1,6 +1,9 @@ $background-color: var(--background-color); $media-border: var(--media-border); $media-box-color: var(--media-box-color); +$padding-small: var(--padding-small); +$padding-normal: var(--padding-normal); +$padding-large: var(--padding-large); // These variables are defined dynamically based on the category of the tag $resolved-tag-background: var(--tag-background); diff --git a/src/styles/content/tags-editor.scss b/src/styles/content/tags-editor.scss new file mode 100644 index 0000000..07a79a9 --- /dev/null +++ b/src/styles/content/tags-editor.scss @@ -0,0 +1,23 @@ +@use '$styles/booru-vars'; +@use '$styles/environment'; + +h2.tag-category-headline { + // Basic margin top and bottom values gathered from Chrome. + $base-margin-top: .83em; + $base-margin-bottom: .62em; + + // Tag List element was updated to use flex & gaps. This should be applied to Furbooru later, once updates will be + // applied from the base Philomena version. + @if environment.$current-site == 'derpibooru' { + margin: { + top: calc(#{$base-margin-top} - #{booru-vars.$padding-small}); + bottom: calc(#{$base-margin-bottom} - #{booru-vars.$padding-small}); + } + } + @else { + margin: { + top: $base-margin-top; + bottom: $base-margin-bottom; + } + } +} From df61c812fe32cec76ee67811e18d94f9f89d6866 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 13 Aug 2025 16:48:27 +0400 Subject: [PATCH 3/6] Updated autorun logic to resolve issues with loading modules on Firefox Sometimes Firefox decides to load different groups of content scripts asynchronously, causing our trick with `requestAnimationFrame` to miss everything. To prevent this, I decided to just attempt to autorun everything on each definition using `setTimeout`. I've also tried to use `queueMicrotask` to put autorun logic right between different groups of modules, but this trick was only working on Firefox and completely breaking on Chromium. I sure love browsers! --- src/content/deps/amd.ts | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/content/deps/amd.ts b/src/content/deps/amd.ts index 9f4f525..759f4d5 100644 --- a/src/content/deps/amd.ts +++ b/src/content/deps/amd.ts @@ -2,21 +2,38 @@ import { amdLite } from "amd-lite"; const originalDefine = amdLite.define; +/** + * Throttle timer to make sure only one attempt at loading modules will run for a batch of loaded scripts. + */ +let throttledAutoRunTimer: NodeJS.Timeout | number | undefined; + +/** + * Schedule the automatic resolving of all waiting modules on the next available frame. + */ +function scheduleModulesAutoRun() { + clearTimeout(throttledAutoRunTimer); + + throttledAutoRunTimer = setTimeout(() => { + amdLite.resolveDependencies(Object.keys(amdLite.waitingModules)); + }); +} + amdLite.define = (name, dependencies, originalCallback) => { - return originalDefine(name, dependencies, function () { + originalDefine(name, dependencies, function () { const callbackResult = originalCallback(...arguments); // Workaround for the entry script not returning anything causing AMD-Lite to send warning about modules not // being loaded/not existing. return typeof callbackResult !== 'undefined' ? callbackResult : {}; - }) + }); + + // Schedule the auto run on the next available frame. Firefox and Chromium have a lot of differences in how they + // decide to execute content scripts. For example, Firefox might decide to skip a frame before attempting to load + // different groups of them. Chromium on the other hand doesn't have that issue, but it doesn't allow us to, for + // example, schedule a microtask to run the modules. + scheduleModulesAutoRun(); } amdLite.init({ publicScope: window }); - -// We don't have anything asynchronous, so it's safe to execute everything on the next frame. -requestAnimationFrame(() => { - amdLite.resolveDependencies(Object.keys(amdLite.waitingModules)) -}); From c330aa303aa7c8024832968ff983f0ed93cdc1d4 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 13 Aug 2025 17:24:36 +0400 Subject: [PATCH 4/6] Derpibooru: Added icon to the tag dropdown option --- src/lib/components/TagDropdownWrapper.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lib/components/TagDropdownWrapper.ts b/src/lib/components/TagDropdownWrapper.ts index 7340854..2b60171 100644 --- a/src/lib/components/TagDropdownWrapper.ts +++ b/src/lib/components/TagDropdownWrapper.ts @@ -148,7 +148,13 @@ export class TagDropdownWrapper extends BaseComponent { profileSpecificButtonText = `Remove from profile "${profileName}"`; } - this.#toggleOnExistingButton.innerText = profileSpecificButtonText; + // Derpibooru has icons in dropdown. Make sure to only edit text and keep the icon untouched. Also, add the space + // before the text to make space between text and icon. + if (__CURRENT_SITE__ === 'derpibooru' && this.#toggleOnExistingButton.lastChild instanceof Text) { + this.#toggleOnExistingButton.lastChild.textContent = ` ${profileSpecificButtonText}`; + } else { + this.#toggleOnExistingButton.textContent = profileSpecificButtonText; + } if (!this.#toggleOnExistingButton.isConnected) { this.#dropdownContainer?.append(this.#toggleOnExistingButton); @@ -243,9 +249,19 @@ export class TagDropdownWrapper extends BaseComponent { static #createDropdownLink(text: string, onClickHandler: (event: MouseEvent) => void): HTMLAnchorElement { const dropdownLink = document.createElement('a'); dropdownLink.href = '#'; - dropdownLink.innerText = text; dropdownLink.className = 'tag__dropdown__link'; + // Derpibooru has an icon in dropdown item. Create the icon and place the text with additional space in front of it. + if (__CURRENT_SITE__ === 'derpibooru') { + const dropdownLinkIcon = document.createElement('i'); + dropdownLinkIcon.classList.add('fa', 'fa-tags'); + + dropdownLink.textContent = ` ${text}`; + dropdownLink.insertAdjacentElement('afterbegin', dropdownLinkIcon); + } else { + dropdownLink.textContent = text; + } + dropdownLink.addEventListener('click', event => { event.preventDefault(); onClickHandler(event); From 4907efdaab5eaa2cbd341facdeba912bea5a3ac2 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 13 Aug 2025 17:50:31 +0400 Subject: [PATCH 5/6] Bumped version to 0.5.1 --- manifest.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 0a8c657..d04d455 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "Furbooru Tagging Assistant", "description": "Small experimental extension for slightly quicker tagging experience. Furbooru Edition.", - "version": "0.5.0", + "version": "0.5.1", "browser_specific_settings": { "gecko": { "id": "furbooru-tagging-assistant@thecore.city" diff --git a/package-lock.json b/package-lock.json index 2acab45..6e95786 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "furbooru-tagging-assistant", - "version": "0.5.0", + "version": "0.5.1", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index ef887c7..35d2735 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "furbooru-tagging-assistant", - "version": "0.5.0", + "version": "0.5.1", "private": true, "scripts": { "build": "npm run build:popup && npm run build:extension", From e4322b3021c16d8c0d851c759283d7dd8c193f48 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 13 Aug 2025 17:54:40 +0400 Subject: [PATCH 6/6] Derpibooru: Making tags slightly smaller inside popup --- src/styles/injectable/tag.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/styles/injectable/tag.scss b/src/styles/injectable/tag.scss index bbec107..db105d4 100644 --- a/src/styles/injectable/tag.scss +++ b/src/styles/injectable/tag.scss @@ -3,7 +3,6 @@ .tag { background: colors.$tag-background; - line-height: 28px; color: colors.$tag-text; font-weight: 700; font-size: 14px; @@ -12,6 +11,10 @@ @if environment.$current-site == 'derpibooru' { border: 1px solid colors.$tag-border; + line-height: 24px; + } + @else { + line-height: 28px; } .remove {