mirror of
https://github.com/koloml/furbooru-tagging-assistant.git
synced 2025-12-23 23:02:58 +00:00
@@ -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"
|
||||
@@ -47,6 +47,9 @@
|
||||
],
|
||||
"js": [
|
||||
"src/content/tags-editor.ts"
|
||||
],
|
||||
"css": [
|
||||
"src/styles/content/tags-editor.scss"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "furbooru-tagging-assistant",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -2,21 +2,52 @@ import { amdLite } from "amd-lite";
|
||||
|
||||
const originalDefine = amdLite.define;
|
||||
|
||||
/**
|
||||
* Set of already defined modules. Used for deduplication.
|
||||
*/
|
||||
const definedModules = new Set<string>();
|
||||
|
||||
/**
|
||||
* 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 () {
|
||||
// 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);
|
||||
|
||||
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))
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
23
src/styles/content/tags-editor.scss
Normal file
23
src/styles/content/tags-editor.scss
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user