From 9445b1e862b5486780f799f42390960bb56217c6 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sat, 7 Mar 2026 17:22:13 +0400 Subject: [PATCH] Restructuring and renaming content components and their initialization --- .../{ => extension}/FullscreenViewer.ts | 0 .../ImageShowFullscreenButton.ts | 22 ++--- .../{ => extension}/MediaBoxTools.ts | 44 ++++----- .../profiles/TaggingProfilePopup.ts} | 44 ++++----- .../profiles/TaggingProfileStatusIcon.ts} | 22 ++--- .../{ => philomena}/BlockCommunication.ts | 0 .../MediaBox.ts} | 72 +++++++------- .../TagDropdown.ts} | 95 ++++++++++--------- .../components/{ => philomena}/TagsForm.ts | 0 .../{ => philomena}/TagsListBlock.ts | 48 +++++----- .../listing/ImageListContainer.ts | 12 ++- .../{ => philomena}/listing/ImageListInfo.ts | 0 src/content/listing.ts | 32 +++---- src/content/posts.ts | 2 +- src/content/tags-editor.ts | 8 +- src/content/tags.ts | 9 +- src/lib/extension/CustomCategoriesResolver.ts | 12 +-- 17 files changed, 214 insertions(+), 208 deletions(-) rename src/content/components/{ => extension}/FullscreenViewer.ts (100%) rename src/content/components/{ => extension}/ImageShowFullscreenButton.ts (85%) rename src/content/components/{ => extension}/MediaBoxTools.ts (58%) rename src/content/components/{MaintenancePopup.ts => extension/profiles/TaggingProfilePopup.ts} (90%) rename src/content/components/{MaintenanceStatusIcon.ts => extension/profiles/TaggingProfileStatusIcon.ts} (81%) rename src/content/components/{ => philomena}/BlockCommunication.ts (100%) rename src/content/components/{MediaBoxWrapper.ts => philomena/MediaBox.ts} (58%) rename src/content/components/{TagDropdownWrapper.ts => philomena/TagDropdown.ts} (77%) rename src/content/components/{ => philomena}/TagsForm.ts (100%) rename src/content/components/{ => philomena}/TagsListBlock.ts (90%) rename src/content/components/{ => philomena}/listing/ImageListContainer.ts (58%) rename src/content/components/{ => philomena}/listing/ImageListInfo.ts (100%) diff --git a/src/content/components/FullscreenViewer.ts b/src/content/components/extension/FullscreenViewer.ts similarity index 100% rename from src/content/components/FullscreenViewer.ts rename to src/content/components/extension/FullscreenViewer.ts diff --git a/src/content/components/ImageShowFullscreenButton.ts b/src/content/components/extension/ImageShowFullscreenButton.ts similarity index 85% rename from src/content/components/ImageShowFullscreenButton.ts rename to src/content/components/extension/ImageShowFullscreenButton.ts index e50ce09..25422a8 100644 --- a/src/content/components/ImageShowFullscreenButton.ts +++ b/src/content/components/extension/ImageShowFullscreenButton.ts @@ -1,8 +1,8 @@ import { BaseComponent } from "$content/components/base/BaseComponent"; import { getComponent } from "$content/components/base/component-utils"; import MiscPreferences from "$lib/extension/preferences/MiscPreferences"; -import { FullscreenViewer } from "$content/components/FullscreenViewer"; -import type { MediaBoxTools } from "$content/components/MediaBoxTools"; +import { FullscreenViewer } from "$content/components/extension/FullscreenViewer"; +import type { MediaBoxTools } from "$content/components/extension/MediaBoxTools"; export class ImageShowFullscreenButton extends BaseComponent { #mediaBoxTools: MediaBoxTools | null = null; @@ -56,6 +56,15 @@ export class ImageShowFullscreenButton extends BaseComponent { ?.show(imageLinks); } + static create(): HTMLElement { + const element = document.createElement('div'); + element.classList.add('media-box-show-fullscreen'); + + new ImageShowFullscreenButton(element); + + return element; + } + static #viewer: FullscreenViewer | null = null; static #resolveViewer(): FullscreenViewer { @@ -76,12 +85,3 @@ export class ImageShowFullscreenButton extends BaseComponent { static #preferences = new MiscPreferences(); } - -export function createImageShowFullscreenButton() { - const element = document.createElement('div'); - element.classList.add('media-box-show-fullscreen'); - - new ImageShowFullscreenButton(element); - - return element; -} diff --git a/src/content/components/MediaBoxTools.ts b/src/content/components/extension/MediaBoxTools.ts similarity index 58% rename from src/content/components/MediaBoxTools.ts rename to src/content/components/extension/MediaBoxTools.ts index 86d9aef..0c05ee5 100644 --- a/src/content/components/MediaBoxTools.ts +++ b/src/content/components/extension/MediaBoxTools.ts @@ -1,14 +1,14 @@ import { BaseComponent } from "$content/components/base/BaseComponent"; import { getComponent } from "$content/components/base/component-utils"; -import { MaintenancePopup } from "$content/components/MaintenancePopup"; +import { TaggingProfilePopup } from "$content/components/extension/profiles/TaggingProfilePopup"; import { on } from "$content/components/events/comms"; import { EVENT_ACTIVE_PROFILE_CHANGED } from "$content/components/events/maintenance-popup-events"; -import type { MediaBoxWrapper } from "$content/components/MediaBoxWrapper"; +import type { MediaBox } from "$content/components/philomena/MediaBox"; import type TaggingProfile from "$entities/TaggingProfile"; export class MediaBoxTools extends BaseComponent { - #mediaBox: MediaBoxWrapper | null = null; - #maintenancePopup: MaintenancePopup | null = null; + #mediaBox: MediaBox | null = null; + #maintenancePopup: TaggingProfilePopup | null = null; init() { const mediaBoxElement = this.container.closest('.media-box'); @@ -34,7 +34,7 @@ export class MediaBoxTools extends BaseComponent { component.initialize(); } - if (!this.#maintenancePopup && component instanceof MaintenancePopup) { + if (!this.#maintenancePopup && component instanceof TaggingProfilePopup) { this.#maintenancePopup = component; } } @@ -46,29 +46,29 @@ export class MediaBoxTools extends BaseComponent { this.container.classList.toggle('has-active-profile', profileChangedEvent.detail !== null); } - get maintenancePopup(): MaintenancePopup | null { + get maintenancePopup(): TaggingProfilePopup | null { return this.#maintenancePopup; } - get mediaBox(): MediaBoxWrapper | null { + get mediaBox(): MediaBox | null { return this.#mediaBox; } -} -/** - * Create a maintenance popup element. - * @param childrenElements List of children elements to append to the component. - * @return The maintenance popup element. - */ -export function createMediaBoxTools(...childrenElements: HTMLElement[]): HTMLElement { - const mediaBoxToolsContainer = document.createElement('div'); - mediaBoxToolsContainer.classList.add('media-box-tools'); + /** + * Create a maintenance popup element. + * @param childrenElements List of children elements to append to the component. + * @return The maintenance popup element. + */ + static create(...childrenElements: HTMLElement[]): HTMLElement { + const mediaBoxToolsContainer = document.createElement('div'); + mediaBoxToolsContainer.classList.add('media-box-tools'); - if (childrenElements.length) { - mediaBoxToolsContainer.append(...childrenElements); + if (childrenElements.length) { + mediaBoxToolsContainer.append(...childrenElements); + } + + new MediaBoxTools(mediaBoxToolsContainer); + + return mediaBoxToolsContainer; } - - new MediaBoxTools(mediaBoxToolsContainer); - - return mediaBoxToolsContainer; } diff --git a/src/content/components/MaintenancePopup.ts b/src/content/components/extension/profiles/TaggingProfilePopup.ts similarity index 90% rename from src/content/components/MaintenancePopup.ts rename to src/content/components/extension/profiles/TaggingProfilePopup.ts index 1f3c886..0a504f3 100644 --- a/src/content/components/MaintenancePopup.ts +++ b/src/content/components/extension/profiles/TaggingProfilePopup.ts @@ -10,7 +10,7 @@ import { EVENT_MAINTENANCE_STATE_CHANGED, EVENT_TAGS_UPDATED } from "$content/components/events/maintenance-popup-events"; -import type { MediaBoxTools } from "$content/components/MediaBoxTools"; +import type { MediaBoxTools } from "$content/components/extension/MediaBoxTools"; import { resolveTagCategoryFromTagName } from "$lib/booru/tag-utils"; class BlackListedTagsEncounteredError extends Error { @@ -21,7 +21,7 @@ class BlackListedTagsEncounteredError extends Error { } } -export class MaintenancePopup extends BaseComponent { +export class TaggingProfilePopup extends BaseComponent { #tagsListElement: HTMLElement = document.createElement('div'); #tagsList: HTMLElement[] = []; #suggestedInvalidTags: Map = new Map(); @@ -66,7 +66,7 @@ export class MaintenancePopup extends BaseComponent { this.#mediaBoxTools = mediaBoxTools; - MaintenancePopup.#watchActiveProfile(this.#onActiveProfileChanged.bind(this)); + TaggingProfilePopup.#watchActiveProfile(this.#onActiveProfileChanged.bind(this)); this.#tagsListElement.addEventListener('click', this.#handleTagClick.bind(this)); const mediaBox = this.#mediaBoxTools.mediaBox; @@ -110,7 +110,7 @@ export class MaintenancePopup extends BaseComponent { activeProfileTagsList .sort((a, b) => a.localeCompare(b)) .forEach((tagName, index) => { - const tagElement = MaintenancePopup.#buildTagElement(tagName); + const tagElement = TaggingProfilePopup.#buildTagElement(tagName); this.#tagsList[index] = tagElement; this.#tagsListElement.appendChild(tagElement); @@ -122,10 +122,10 @@ export class MaintenancePopup extends BaseComponent { // Just to prevent duplication, we need to include this tag to the map of suggested invalid tags if (tagsBlacklist.includes(tagName)) { - MaintenancePopup.#markTagElementWithCategory(tagElement, 'error'); + TaggingProfilePopup.#markTagElementWithCategory(tagElement, 'error'); this.#suggestedInvalidTags.set(tagName, tagElement); } else { - MaintenancePopup.#markTagElementWithCategory( + TaggingProfilePopup.#markTagElementWithCategory( tagElement, resolveTagCategoryFromTagName(tagName) ?? '', ); @@ -179,7 +179,7 @@ export class MaintenancePopup extends BaseComponent { if (this.#tagsToAdd.size || this.#tagsToRemove.size) { // Notify only once, when first planning to submit if (!this.#isPlanningToSubmit) { - MaintenancePopup.#notifyAboutPendingSubmission(true); + TaggingProfilePopup.#notifyAboutPendingSubmission(true); } this.#isPlanningToSubmit = true; @@ -197,7 +197,7 @@ export class MaintenancePopup extends BaseComponent { if (this.#isPlanningToSubmit && !this.#isSubmitting) { this.#tagsSubmissionTimer = setTimeout( this.#onSubmissionTimerPassed.bind(this), - MaintenancePopup.#delayBeforeSubmissionMs + TaggingProfilePopup.#delayBeforeSubmissionMs ); } } @@ -214,10 +214,10 @@ export class MaintenancePopup extends BaseComponent { let maybeTagsAndAliasesAfterUpdate; - const shouldAutoRemove = await MaintenancePopup.#preferences.stripBlacklistedTags.get(); + const shouldAutoRemove = await TaggingProfilePopup.#preferences.stripBlacklistedTags.get(); try { - maybeTagsAndAliasesAfterUpdate = await MaintenancePopup.#scrapedAPI.updateImageTags( + maybeTagsAndAliasesAfterUpdate = await TaggingProfilePopup.#scrapedAPI.updateImageTags( this.#mediaBoxTools.mediaBox.imageId, tagsList => { for (let tagName of this.#tagsToRemove) { @@ -250,7 +250,7 @@ export class MaintenancePopup extends BaseComponent { console.warn('Tags submission failed:', e); } - MaintenancePopup.#notifyAboutPendingSubmission(false); + TaggingProfilePopup.#notifyAboutPendingSubmission(false); this.#emitter.emit(EVENT_MAINTENANCE_STATE_CHANGED, 'failed'); this.#isSubmitting = false; @@ -268,7 +268,7 @@ export class MaintenancePopup extends BaseComponent { this.#tagsToRemove.clear(); this.#refreshTagsList(); - MaintenancePopup.#notifyAboutPendingSubmission(false); + TaggingProfilePopup.#notifyAboutPendingSubmission(false); this.#isSubmitting = false; } @@ -292,8 +292,8 @@ export class MaintenancePopup extends BaseComponent { continue; } - const tagElement = MaintenancePopup.#buildTagElement(tagName); - MaintenancePopup.#markTagElementWithCategory(tagElement, 'error'); + const tagElement = TaggingProfilePopup.#buildTagElement(tagName); + TaggingProfilePopup.#markTagElementWithCategory(tagElement, 'error'); tagElement.classList.add('is-present'); this.#suggestedInvalidTags.set(tagName, tagElement); @@ -311,6 +311,14 @@ export class MaintenancePopup extends BaseComponent { return this.container.classList.contains('is-active'); } + static create(): HTMLElement { + const container = document.createElement('div'); + + new this(container); + + return container; + } + static #buildTagElement(tagName: string): HTMLElement { const tagElement = document.createElement('span'); tagElement.classList.add('tag'); @@ -414,11 +422,3 @@ export class MaintenancePopup extends BaseComponent { */ static #pendingSubmissionCount: number|null = null; } - -export function createMaintenancePopup() { - const container = document.createElement('div'); - - new MaintenancePopup(container); - - return container; -} diff --git a/src/content/components/MaintenanceStatusIcon.ts b/src/content/components/extension/profiles/TaggingProfileStatusIcon.ts similarity index 81% rename from src/content/components/MaintenanceStatusIcon.ts rename to src/content/components/extension/profiles/TaggingProfileStatusIcon.ts index 9c67830..6e5ab8b 100644 --- a/src/content/components/MaintenanceStatusIcon.ts +++ b/src/content/components/extension/profiles/TaggingProfileStatusIcon.ts @@ -2,9 +2,9 @@ import { BaseComponent } from "$content/components/base/BaseComponent"; import { getComponent } from "$content/components/base/component-utils"; import { on } from "$content/components/events/comms"; import { EVENT_MAINTENANCE_STATE_CHANGED } from "$content/components/events/maintenance-popup-events"; -import type { MediaBoxTools } from "$content/components/MediaBoxTools"; +import type { MediaBoxTools } from "$content/components/extension/MediaBoxTools"; -export class MaintenanceStatusIcon extends BaseComponent { +export class TaggingProfileStatusIcon extends BaseComponent { #mediaBoxTools: MediaBoxTools | null = null; build() { @@ -52,13 +52,13 @@ export class MaintenanceStatusIcon extends BaseComponent { this.container.innerText = '❓'; } } -} - -export function createMaintenanceStatusIcon() { - const element = document.createElement('div'); - element.classList.add('maintenance-status-icon'); - - new MaintenanceStatusIcon(element); - - return element; + + static create(): HTMLElement { + const element = document.createElement('div'); + element.classList.add('maintenance-status-icon'); + + new TaggingProfileStatusIcon(element); + + return element; + } } diff --git a/src/content/components/BlockCommunication.ts b/src/content/components/philomena/BlockCommunication.ts similarity index 100% rename from src/content/components/BlockCommunication.ts rename to src/content/components/philomena/BlockCommunication.ts diff --git a/src/content/components/MediaBoxWrapper.ts b/src/content/components/philomena/MediaBox.ts similarity index 58% rename from src/content/components/MediaBoxWrapper.ts rename to src/content/components/philomena/MediaBox.ts index a694f70..28eacec 100644 --- a/src/content/components/MediaBoxWrapper.ts +++ b/src/content/components/philomena/MediaBox.ts @@ -4,7 +4,7 @@ import { buildTagsAndAliasesMap } from "$lib/booru/tag-utils"; import { on } from "$content/components/events/comms"; import { EVENT_TAGS_UPDATED } from "$content/components/events/maintenance-popup-events"; -export class MediaBoxWrapper extends BaseComponent { +export class MediaBox extends BaseComponent { #thumbnailContainer: HTMLElement | null = null; #imageLinkElement: HTMLAnchorElement | null = null; #tagsAndAliases: Map | null = null; @@ -60,40 +60,44 @@ export class MediaBoxWrapper extends BaseComponent { return JSON.parse(jsonUris); } -} -/** - * Wrap the media box element into the special wrapper. - */ -export function initializeMediaBox(mediaBoxContainer: HTMLElement, childComponentElements: HTMLElement[]) { - new MediaBoxWrapper(mediaBoxContainer) - .initialize(); + /** + * Wrap the media box element into the special wrapper. + */ + static initialize(mediaBoxContainer: HTMLElement, childComponentElements: HTMLElement[]) { + new MediaBox(mediaBoxContainer) + .initialize(); - for (let childComponentElement of childComponentElements) { - mediaBoxContainer.appendChild(childComponentElement); - getComponent(childComponentElement)?.initialize(); + for (let childComponentElement of childComponentElements) { + mediaBoxContainer.appendChild(childComponentElement); + getComponent(childComponentElement)?.initialize(); + } + } + + static findElements(): NodeListOf { + return document.querySelectorAll('.media-box'); + } + + static initializePositionCalculation(mediaBoxesList: NodeListOf) { + window.addEventListener('resize', () => { + let lastMediaBox: HTMLElement | null = null; + let lastMediaBoxPosition: number | null = null; + + for (const mediaBoxElement of mediaBoxesList) { + const yPosition = mediaBoxElement.getBoundingClientRect().y; + const isOnTheSameLine = yPosition === lastMediaBoxPosition; + + mediaBoxElement.classList.toggle('media-box--first', !isOnTheSameLine); + lastMediaBox?.classList.toggle('media-box--last', !isOnTheSameLine); + + lastMediaBox = mediaBoxElement; + lastMediaBoxPosition = yPosition; + } + + // Last-ever media box is checked separately + if (lastMediaBox && !lastMediaBox.nextElementSibling) { + lastMediaBox.classList.add('media-box--last'); + } + }) } } - -export function calculateMediaBoxesPositions(mediaBoxesList: NodeListOf) { - window.addEventListener('resize', () => { - let lastMediaBox: HTMLElement | null = null; - let lastMediaBoxPosition: number | null = null; - - for (const mediaBoxElement of mediaBoxesList) { - const yPosition = mediaBoxElement.getBoundingClientRect().y; - const isOnTheSameLine = yPosition === lastMediaBoxPosition; - - mediaBoxElement.classList.toggle('media-box--first', !isOnTheSameLine); - lastMediaBox?.classList.toggle('media-box--last', !isOnTheSameLine); - - lastMediaBox = mediaBoxElement; - lastMediaBoxPosition = yPosition; - } - - // Last-ever media box is checked separately - if (lastMediaBox && !lastMediaBox.nextElementSibling) { - lastMediaBox.classList.add('media-box--last'); - } - }) -} diff --git a/src/content/components/TagDropdownWrapper.ts b/src/content/components/philomena/TagDropdown.ts similarity index 77% rename from src/content/components/TagDropdownWrapper.ts rename to src/content/components/philomena/TagDropdown.ts index 0a64ec3..8719281 100644 --- a/src/content/components/TagDropdownWrapper.ts +++ b/src/content/components/philomena/TagDropdown.ts @@ -8,9 +8,7 @@ import { EVENT_FORM_EDITOR_UPDATED } from "$content/components/events/tags-form- import { EVENT_TAG_GROUP_RESOLVED } from "$content/components/events/tag-dropdown-events"; import type TagGroup from "$entities/TagGroup"; -const categoriesResolver = new CustomCategoriesResolver(); - -export class TagDropdownWrapper extends BaseComponent { +export class TagDropdown extends BaseComponent { /** * Container with dropdown elements to insert options into. */ @@ -46,7 +44,7 @@ export class TagDropdownWrapper extends BaseComponent { this.on('mouseenter', this.#onDropdownEntered.bind(this)); this.on('mouseleave', this.#onDropdownLeft.bind(this)); - TagDropdownWrapper.#watchActiveProfile(activeProfileOrNull => { + TagDropdown.#watchActiveProfile(activeProfileOrNull => { this.#activeProfile = activeProfileOrNull; if (this.#isEntered) { @@ -122,7 +120,7 @@ export class TagDropdownWrapper extends BaseComponent { #updateButtons() { if (!this.#activeProfile) { - this.#addToNewButton ??= TagDropdownWrapper.#createDropdownLink( + this.#addToNewButton ??= TagDropdown.#createDropdownLink( 'Add to new tagging profile', this.#onAddToNewClicked.bind(this) ); @@ -135,7 +133,7 @@ export class TagDropdownWrapper extends BaseComponent { } if (this.#activeProfile) { - this.#toggleOnExistingButton ??= TagDropdownWrapper.#createDropdownLink( + this.#toggleOnExistingButton ??= TagDropdown.#createDropdownLink( 'Add to existing tagging profile', this.#onToggleInExistingClicked.bind(this) ); @@ -179,7 +177,7 @@ export class TagDropdownWrapper extends BaseComponent { }); await profile.save(); - await TagDropdownWrapper.#preferences.activeProfile.set(profile.id); + await TagDropdown.#preferences.activeProfile.set(profile.id); } async #onToggleInExistingClicked() { @@ -263,58 +261,65 @@ export class TagDropdownWrapper extends BaseComponent { return dropdownLink; } -} -export function wrapTagDropdown(element: HTMLElement) { - // Skip initialization when tag component is already wrapped - if (getComponent(element)) { - return; + static #categoriesResolver = new CustomCategoriesResolver(); + static #processedElements: WeakSet = new WeakSet(); + + static #findAll(parentNode: ParentNode = document): NodeListOf { + return parentNode.querySelectorAll('.tag.dropdown'); } - const tagDropdown = new TagDropdownWrapper(element); - tagDropdown.initialize(); + static #initialize(element: HTMLElement) { + // Skip initialization when tag component is already wrapped + if (getComponent(element)) { + return; + } - categoriesResolver.addElement(tagDropdown); -} + const tagDropdown = new TagDropdown(element); + tagDropdown.initialize(); -const processedElementsSet = new WeakSet(); - -export function watchTagDropdownsInTagsEditor() { - // We only need to watch for new editor elements if there is a tag editor present on the page - if (!document.querySelector('#image_tags_and_source')) { - return; + this.#categoriesResolver.addElement(tagDropdown); } - document.body.addEventListener('mouseover', event => { - const targetElement = event.target; + static findAllAndInitialize(parentNode: ParentNode = document) { + for (const element of this.#findAll(parentNode)) { + this.#initialize(element); + } + } - if (!(targetElement instanceof HTMLElement)) { + static watch() { + // We only need to watch for new editor elements if there is a tag editor present on the page + if (!document.querySelector('#image_tags_and_source')) { return; } - if (processedElementsSet.has(targetElement)) { - return; - } + document.body.addEventListener('mouseover', event => { + const targetElement = event.target; - const closestTagEditor = targetElement.closest('#image_tags_and_source'); + if (!(targetElement instanceof HTMLElement)) { + return; + } - if (!closestTagEditor || processedElementsSet.has(closestTagEditor)) { - processedElementsSet.add(targetElement); - return; - } + if (this.#processedElements.has(targetElement)) { + return; + } - processedElementsSet.add(targetElement); - processedElementsSet.add(closestTagEditor); + const closestTagEditor = targetElement.closest('#image_tags_and_source'); - for (const tagDropdownElement of closestTagEditor.querySelectorAll('.tag.dropdown')) { - wrapTagDropdown(tagDropdownElement); - } - }); + if (!closestTagEditor || this.#processedElements.has(closestTagEditor)) { + this.#processedElements.add(targetElement); + return; + } - // When form is submitted, its DOM is completely updated. We need to fetch those tags in this case. - on(document.body, EVENT_FORM_EDITOR_UPDATED, event => { - for (const tagDropdownElement of event.detail.querySelectorAll('.tag.dropdown')) { - wrapTagDropdown(tagDropdownElement); - } - }); + this.#processedElements.add(targetElement); + this.#processedElements.add(closestTagEditor); + + this.findAllAndInitialize(closestTagEditor); + }); + + // When form is submitted, its DOM is completely updated. We need to fetch those tags in this case. + on(document.body, EVENT_FORM_EDITOR_UPDATED, event => { + this.findAllAndInitialize(event.detail); + }); + } } diff --git a/src/content/components/TagsForm.ts b/src/content/components/philomena/TagsForm.ts similarity index 100% rename from src/content/components/TagsForm.ts rename to src/content/components/philomena/TagsForm.ts diff --git a/src/content/components/TagsListBlock.ts b/src/content/components/philomena/TagsListBlock.ts similarity index 90% rename from src/content/components/TagsListBlock.ts rename to src/content/components/philomena/TagsListBlock.ts index 1f2557e..0b2cead 100644 --- a/src/content/components/TagsListBlock.ts +++ b/src/content/components/philomena/TagsListBlock.ts @@ -1,6 +1,6 @@ import { BaseComponent } from "$content/components/base/BaseComponent"; import type TagGroup from "$entities/TagGroup"; -import type { TagDropdownWrapper } from "$content/components/TagDropdownWrapper"; +import type { TagDropdown } from "$content/components/philomena/TagDropdown"; import { on } from "$content/components/events/comms"; import { EVENT_FORM_EDITOR_UPDATED } from "$content/components/events/tags-form-events"; import { getComponent } from "$content/components/base/component-utils"; @@ -21,7 +21,7 @@ export class TagsListBlock extends BaseComponent { #separatedGroups = new Map(); #separatedHeaders = new Map(); #groupsCount = new Map(); - #lastTagGroup = new WeakMap; + #lastTagGroup = new WeakMap; #isReorderingPlanned = false; @@ -80,7 +80,7 @@ export class TagsListBlock extends BaseComponent { return; } - const tagDropdown = getComponent(maybeDropdownElement); + const tagDropdown = getComponent(maybeDropdownElement); if (!tagDropdown) { return; @@ -146,7 +146,7 @@ export class TagsListBlock extends BaseComponent { heading.innerText = group.settings.name; } - #handleResolvedTagGroup(resolvedGroup: TagGroup | null, tagComponent: TagDropdownWrapper) { + #handleResolvedTagGroup(resolvedGroup: TagGroup | null, tagComponent: TagDropdown) { const previousGroupId = this.#lastTagGroup.get(tagComponent)?.id; const currentGroupId = resolvedGroup?.id; const isDifferentId = currentGroupId !== previousGroupId; @@ -217,28 +217,28 @@ export class TagsListBlock extends BaseComponent { static #iconGroupingDisabled = 'fa-folder'; static #iconGroupingEnabled = 'fa-folder-tree'; -} -export function initializeAllTagsLists() { - for (let element of document.querySelectorAll('#image_tags_and_source')) { - if (getComponent(element)) { - return; + static initializeAll() { + for (let element of document.querySelectorAll('#image_tags_and_source')) { + if (getComponent(element)) { + return; + } + + new TagsListBlock(element) + .initialize(); } + } - new TagsListBlock(element) - .initialize(); + static watchUpdatedLists() { + on(document, EVENT_FORM_EDITOR_UPDATED, event => { + const tagsListElement = event.detail.closest('#image_tags_and_source'); + + if (!tagsListElement || getComponent(tagsListElement)) { + return; + } + + new TagsListBlock(tagsListElement) + .initialize(); + }) } } - -export function watchForUpdatedTagLists() { - on(document, EVENT_FORM_EDITOR_UPDATED, event => { - const tagsListElement = event.detail.closest('#image_tags_and_source'); - - if (!tagsListElement || getComponent(tagsListElement)) { - return; - } - - new TagsListBlock(tagsListElement) - .initialize(); - }); -} diff --git a/src/content/components/listing/ImageListContainer.ts b/src/content/components/philomena/listing/ImageListContainer.ts similarity index 58% rename from src/content/components/listing/ImageListContainer.ts rename to src/content/components/philomena/listing/ImageListContainer.ts index 3f07bdc..20e4798 100644 --- a/src/content/components/listing/ImageListContainer.ts +++ b/src/content/components/philomena/listing/ImageListContainer.ts @@ -1,5 +1,5 @@ import { BaseComponent } from "$content/components/base/BaseComponent"; -import { ImageListInfo } from "$content/components/listing/ImageListInfo"; +import { ImageListInfo } from "$content/components/philomena/listing/ImageListInfo"; export class ImageListContainer extends BaseComponent { #info: ImageListInfo | null = null; @@ -12,8 +12,12 @@ export class ImageListContainer extends BaseComponent { this.#info.initialize(); } } -} -export function initializeImageListContainer(element: HTMLElement) { - new ImageListContainer(element).initialize(); + static findAndInitialize() { + const imageListContainer = document.querySelector('#imagelist-container'); + + if (imageListContainer) { + new ImageListContainer(imageListContainer).initialize(); + } + } } diff --git a/src/content/components/listing/ImageListInfo.ts b/src/content/components/philomena/listing/ImageListInfo.ts similarity index 100% rename from src/content/components/listing/ImageListInfo.ts rename to src/content/components/philomena/listing/ImageListInfo.ts diff --git a/src/content/listing.ts b/src/content/listing.ts index 5f20635..21e240e 100644 --- a/src/content/listing.ts +++ b/src/content/listing.ts @@ -1,19 +1,18 @@ -import { createMaintenancePopup } from "$content/components/MaintenancePopup"; -import { createMediaBoxTools } from "$content/components/MediaBoxTools"; -import { calculateMediaBoxesPositions, initializeMediaBox } from "$content/components/MediaBoxWrapper"; -import { createMaintenanceStatusIcon } from "$content/components/MaintenanceStatusIcon"; -import { createImageShowFullscreenButton } from "$content/components/ImageShowFullscreenButton"; -import { initializeImageListContainer } from "$content/components/listing/ImageListContainer"; +import { TaggingProfilePopup } from "$content/components/extension/profiles/TaggingProfilePopup"; +import { MediaBoxTools } from "$content/components/extension/MediaBoxTools"; +import { MediaBox } from "$content/components/philomena/MediaBox"; +import { TaggingProfileStatusIcon } from "$content/components/extension/profiles/TaggingProfileStatusIcon"; +import { ImageShowFullscreenButton } from "$content/components/extension/ImageShowFullscreenButton"; +import { ImageListContainer } from "$content/components/philomena/listing/ImageListContainer"; -const mediaBoxes = document.querySelectorAll('.media-box'); -const imageListContainer = document.querySelector('#imagelist-container'); +const mediaBoxes = MediaBox.findElements(); mediaBoxes.forEach(mediaBoxElement => { - initializeMediaBox(mediaBoxElement, [ - createMediaBoxTools( - createMaintenancePopup(), - createMaintenanceStatusIcon(), - createImageShowFullscreenButton(), + MediaBox.initialize(mediaBoxElement, [ + MediaBoxTools.create( + TaggingProfilePopup.create(), + TaggingProfileStatusIcon.create(), + ImageShowFullscreenButton.create(), ) ]); @@ -23,8 +22,5 @@ mediaBoxes.forEach(mediaBoxElement => { }) }); -calculateMediaBoxesPositions(mediaBoxes); - -if (imageListContainer) { - initializeImageListContainer(imageListContainer); -} +MediaBox.initializePositionCalculation(mediaBoxes); +ImageListContainer.findAndInitialize(); diff --git a/src/content/posts.ts b/src/content/posts.ts index a331a58..1028377 100644 --- a/src/content/posts.ts +++ b/src/content/posts.ts @@ -1,3 +1,3 @@ -import { BlockCommunication } from "$content/components/BlockCommunication"; +import { BlockCommunication } from "$content/components/philomena/BlockCommunication"; BlockCommunication.findAndInitializeAll(); diff --git a/src/content/tags-editor.ts b/src/content/tags-editor.ts index e12559d..afda8a4 100644 --- a/src/content/tags-editor.ts +++ b/src/content/tags-editor.ts @@ -1,6 +1,6 @@ -import { TagsForm } from "$content/components/TagsForm"; -import { initializeAllTagsLists, watchForUpdatedTagLists } from "$content/components/TagsListBlock"; +import { TagsForm } from "$content/components/philomena/TagsForm"; +import { TagsListBlock } from "$content/components/philomena/TagsListBlock"; -initializeAllTagsLists(); -watchForUpdatedTagLists(); +TagsListBlock.initializeAll(); +TagsListBlock.watchUpdatedLists(); TagsForm.watchForEditors(); diff --git a/src/content/tags.ts b/src/content/tags.ts index b012167..3a8b992 100644 --- a/src/content/tags.ts +++ b/src/content/tags.ts @@ -1,7 +1,4 @@ -import { watchTagDropdownsInTagsEditor, wrapTagDropdown } from "$content/components/TagDropdownWrapper"; +import { TagDropdown } from "$content/components/philomena/TagDropdown"; -for (let tagDropdownElement of document.querySelectorAll('.tag.dropdown')) { - wrapTagDropdown(tagDropdownElement); -} - -watchTagDropdownsInTagsEditor(); +TagDropdown.findAllAndInitialize(); +TagDropdown.watch(); diff --git a/src/lib/extension/CustomCategoriesResolver.ts b/src/lib/extension/CustomCategoriesResolver.ts index 560cc77..74d67b7 100644 --- a/src/lib/extension/CustomCategoriesResolver.ts +++ b/src/lib/extension/CustomCategoriesResolver.ts @@ -1,4 +1,4 @@ -import type { TagDropdownWrapper } from "$content/components/TagDropdownWrapper"; +import type { TagDropdown } from "$content/components/philomena/TagDropdown"; import TagGroup from "$entities/TagGroup"; import { escapeRegExp } from "$lib/utils"; import { emit } from "$content/components/events/comms"; @@ -7,7 +7,7 @@ import { EVENT_TAG_GROUP_RESOLVED } from "$content/components/events/tag-dropdow export default class CustomCategoriesResolver { #exactGroupMatches = new Map(); #regExpGroupMatches = new Map(); - #tagDropdowns: TagDropdownWrapper[] = []; + #tagDropdowns: TagDropdown[] = []; #nextQueuedUpdate: Timeout | null = null; constructor() { @@ -15,7 +15,7 @@ export default class CustomCategoriesResolver { TagGroup.readAll().then(this.#onTagGroupsReceived.bind(this)); } - public addElement(tagDropdown: TagDropdownWrapper): void { + public addElement(tagDropdown: TagDropdown): void { this.#tagDropdowns.push(tagDropdown); if (!this.#exactGroupMatches.size && !this.#regExpGroupMatches.size) { @@ -49,7 +49,7 @@ export default class CustomCategoriesResolver { * @return {boolean} Will return false when tag is processed and true when it is not found. * @private */ - #applyCustomCategoryForExactMatches(tagDropdown: TagDropdownWrapper): boolean { + #applyCustomCategoryForExactMatches(tagDropdown: TagDropdown): boolean { const tagName = tagDropdown.tagName!; if (!this.#exactGroupMatches.has(tagName)) { @@ -65,7 +65,7 @@ export default class CustomCategoriesResolver { return false; } - #matchCustomCategoryByRegExp(tagDropdown: TagDropdownWrapper) { + #matchCustomCategoryByRegExp(tagDropdown: TagDropdown) { const tagName = tagDropdown.tagName!; for (const targetRegularExpression of this.#regExpGroupMatches.keys()) { @@ -117,7 +117,7 @@ export default class CustomCategoriesResolver { this.#queueUpdatingTags(); } - static #resetToOriginalCategory(tagDropdown: TagDropdownWrapper): void { + static #resetToOriginalCategory(tagDropdown: TagDropdown): void { emit( tagDropdown, EVENT_TAG_GROUP_RESOLVED,