diff --git a/src/content/components/BlockCommunication.ts b/src/content/components/BlockCommunication.ts index 852a80b..217170d 100644 --- a/src/content/components/BlockCommunication.ts +++ b/src/content/components/BlockCommunication.ts @@ -1,7 +1,7 @@ import { BaseComponent } from "$content/components/base/BaseComponent"; import TagSettings from "$lib/extension/settings/TagSettings"; import { getComponent } from "$content/components/base/component-utils"; -import { decodeTagNameFromLink, resolveTagCategoryFromTagName } from "$lib/booru/tag-utils"; +import { resolveTagNameFromLink, resolveTagCategoryFromTagName } from "$lib/booru/tag-utils"; export class BlockCommunication extends BaseComponent { #contentSection: HTMLElement | null = null; @@ -35,8 +35,8 @@ export class BlockCommunication extends BaseComponent { } if (haveToReplaceLinks) { - const maybeDecodedTagName = decodeTagNameFromLink(linkElement.pathname) ?? ''; - linkElement.dataset.tagCategory = resolveTagCategoryFromTagName(maybeDecodedTagName) ?? ''; + const tagName = resolveTagNameFromLink(new URL(linkElement.href)) ?? ''; + linkElement.dataset.tagCategory = resolveTagCategoryFromTagName(tagName) ?? ''; } else { linkElement.dataset.tagCategory = ''; } @@ -48,7 +48,14 @@ export class BlockCommunication extends BaseComponent { #findAllTagLinks(): HTMLAnchorElement[] { return Array .from(this.#contentSection?.querySelectorAll('a') || []) - .filter(link => link.pathname.startsWith('/tags/')) + .filter( + link => + // Support links pointing to the tag page. + link.pathname.startsWith('/tags/') + // Also capture link which point to the search results with single tag. + || link.pathname.startsWith('/search') + && link.search.includes('q=') + ); } static #tagSettings = new TagSettings(); diff --git a/src/lib/booru/tag-utils.ts b/src/lib/booru/tag-utils.ts index c7cb0ae..ca110b7 100644 --- a/src/lib/booru/tag-utils.ts +++ b/src/lib/booru/tag-utils.ts @@ -1,4 +1,5 @@ import { namespaceCategories } from "$config/tags"; +import { QueryLexer, QuotedTermToken, TermToken } from "$lib/booru/search/QueryLexer"; /** * Build the map containing both real tags and their aliases. @@ -51,16 +52,48 @@ const slugEncodedCharacters: Map = new Map([ ]); /** - * Decode the tag name from its link path. + * Try to parse the tag name from the search query URL. It uses the same tokenizer as the booru. It only returns the + * tag name if query contains only one single tag without any additional conditions. * - * @param tagLink Full or partial link to the tag. + * @param searchLink Link with search query. * - * @return Tag name or NULL if function is failed to recognize the link as tag-related link. + * @return Tag name or NULL if query contains more than 1 tag or doesn't have any tags at all. */ -export function decodeTagNameFromLink(tagLink: string): string | null { +function parseTagNameFromSearchQuery(searchLink: URL): string | null { + const lexer = new QueryLexer(searchLink.searchParams.get('q') || ''); + const parsedQuery = lexer.parse(); + + if (parsedQuery.length !== 1) { + return null; + } + + const [token] = parsedQuery; + + switch (true) { + case token instanceof TermToken: + return token.value; + case token instanceof QuotedTermToken: + return token.decodedValue; + } + + return null; +} + +/** + * Decode the tag name from the following link. + * + * @param tagLink Search link or link to the tag to parse the tag name from. + * + * @return Tag name or NULL if function is failed to parse the name of the tag. + */ +export function resolveTagNameFromLink(tagLink: URL): string | null { + if (tagLink.pathname.startsWith('/search') && tagLink.searchParams.has('q')) { + return parseTagNameFromSearchQuery(tagLink); + } + tagLinkRegExp.lastIndex = 0; - const result = tagLinkRegExp.exec(tagLink); + const result = tagLinkRegExp.exec(tagLink.pathname); const encodedTagName = result?.groups?.encodedTagName; if (!encodedTagName) {