diff options
| -rw-r--r-- | src/common-util/sugar.js | 25 | ||||
| -rw-r--r-- | src/common-util/wiki-data.js | 88 | ||||
| -rw-r--r-- | src/content/dependencies/generateTrackArtworkColumn.js | 2 | ||||
| -rw-r--r-- | src/static/css/miscellany.css | 2 | ||||
| -rw-r--r-- | src/static/css/search.css | 2 | ||||
| -rw-r--r-- | src/static/css/tooltips.css | 8 | ||||
| -rw-r--r-- | src/static/js/client/index.js | 2 | ||||
| -rw-r--r-- | src/static/js/client/sidebar-search.js | 85 |
8 files changed, 141 insertions, 73 deletions
diff --git a/src/common-util/sugar.js b/src/common-util/sugar.js index 354cf5cc..c988156c 100644 --- a/src/common-util/sugar.js +++ b/src/common-util/sugar.js @@ -417,6 +417,31 @@ export function escapeRegex(string) { return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); } +// Adapted from here: https://emnudge.dev/notes/multiline-regex/ +// ...with a lot of changes +export function re(...args) { + let flags, parts; + if (args.length === 2) { + flags = args[0]; + parts = args[1]; + } else if (args.length === 1) { + flags = ''; + parts = args[0]; + } else { + throw new Error(`Expected 1 or 2 arguments`); + } + + const source = parts + .flat(Infinity) + .map(item => + (item instanceof RegExp + ? item.source + : item.toString())) + .join(''); + + return new RegExp(source, flags); +} + export function splitKeys(key) { return key.split(/(?<=(?<!\\)(?:\\\\)*)\./); } diff --git a/src/common-util/wiki-data.js b/src/common-util/wiki-data.js index 4c7f66f4..ff325b7a 100644 --- a/src/common-util/wiki-data.js +++ b/src/common-util/wiki-data.js @@ -1,6 +1,6 @@ // Utility functions for interacting with wiki data. -import {accumulateSum, chunkByConditions, empty, unique} from './sugar.js'; +import {accumulateSum, chunkByConditions, empty, re, unique} from './sugar.js'; import {sortByDate} from './sort.js'; // This is a duplicate binding of filterMultipleArrays that's included purely @@ -76,42 +76,48 @@ export function compareKebabCase(name1, name2) { // by slashes or dashes (only valid orders are MM/DD/YYYY and YYYY/MM/DD) // const dateRegex = groupName => - String.raw`(?<${groupName}>` + - String.raw`[a-zA-Z]+ [0-9]{1,2}, [0-9]{4,4}|` + - String.raw`[0-9]{1,2} [^,]*[0-9]{4,4}|` + - String.raw`[0-9]{1,4}[-/][0-9]{1,4}[-/][0-9]{1,4}` + - String.raw`)`; - -const contentEntryHeadingRegexRaw = - String.raw`^(?:` + - String.raw`(?:` + - String.raw`<i>(?<artists>.+?):<\/i>` + - String.raw`(?: \((?<annotation1>.*)\))?` + - String.raw`)` + - String.raw`|` + - String.raw`(?:` + - String.raw`@@ (?<annotation2>.*)` + - String.raw`)` + - String.raw`)$`; + re([ + `(?<${groupName}>`, + /[a-zA-Z]+ [0-9]{1,2}, [0-9]{4,4}/, '|', + /[0-9]{1,2} [^,]*[0-9]{4,4}/, '|', + /[0-9]{1,4}[-/][0-9]{1,4}[-/][0-9]{1,4}/, + `)`, + ]); const contentEntryHeadingRegex = - new RegExp(contentEntryHeadingRegexRaw, 'gm'); - -const contentEntryAnnotationTailRegexRaw = - String.raw`(?:, |^)` + - - String.raw`(?:(?<dateKind>sometime|throughout|around) )?` + - String.raw`${dateRegex('date')}` + - String.raw`(?: ?- ?${dateRegex('secondDate')})?` + - - String.raw`(?: ?(?<= )` + - String.raw`(?<accessKind>captured|accessed) ${dateRegex('accessDate')}` + - String.raw`)?` + - - String.raw`$`; + re('gm', [ + '^(?:', + '(?:', + /<i>(?<artists>.+?):<\/i>/, + /(?: \((?<annotation1>.*)\))?/, + ')', + '|', + '(?:', + /@@ (?<annotation2>.*)/, + ')', + ')$', + ]); const contentEntryAnnotationTailRegex = - new RegExp(contentEntryAnnotationTailRegexRaw); + re([ + /(?:, |^)/, + + /(?:(?<dateKind>sometime|throughout|around) )?/, + dateRegex('date'), + + '(?:', + ' ?', + '-', + ' ?', + dateRegex('secondDate'), + ')?', + + '(?: ?(?<= )', + /(?<accessKind>captured|accessed)/, + ' ', + dateRegex('accessDate'), + ')?', + ]); export function* matchContentEntries(sourceText) { let workingEntry = null; @@ -593,7 +599,21 @@ export function* matchMarkdownLinks(markdownSource, {marked}) { } export function* matchInlineLinks(source) { - const plausibleLinkRegexp = /\b[a-z]*:\/\/[^ ]*?(?=(?:[,.!?]*)(?:\s|$))/gm; + const plausibleLinkRegexp = + re('gmi', [ + /\b[a-z]*:\/\//, + /.*?/, + + '(?=', + // Ordinary in-sentence punctuation doesn't terminate the + // un-greedy URL match above, but it shouldn't be counted + // as part of the link either, if it's at the end. + /(?:[,.!?]*)/, + + // Actual terminators. + /(?:\s|$|<br>)/, + ')', + ]); let plausibleMatch = null; while (plausibleMatch = plausibleLinkRegexp.exec(source)) { diff --git a/src/content/dependencies/generateTrackArtworkColumn.js b/src/content/dependencies/generateTrackArtworkColumn.js index feaed604..77ce0071 100644 --- a/src/content/dependencies/generateTrackArtworkColumn.js +++ b/src/content/dependencies/generateTrackArtworkColumn.js @@ -21,7 +21,7 @@ export default { relations.albumCover?.slots({ showOriginDetails: true, showArtTagDetails: true, - showReferenceDetails: true, + showReferenceDetails: false, }), relations.trackCovers.map(cover => diff --git a/src/static/css/miscellany.css b/src/static/css/miscellany.css index 70120a33..dcdd72ca 100644 --- a/src/static/css/miscellany.css +++ b/src/static/css/miscellany.css @@ -478,7 +478,9 @@ font-weight: normal; color: var(--primary-color); } +} +@layer interaction { summary > span:hover { cursor: pointer; text-decoration: underline; diff --git a/src/static/css/search.css b/src/static/css/search.css index f421803b..a79fb20a 100644 --- a/src/static/css/search.css +++ b/src/static/css/search.css @@ -191,6 +191,8 @@ @layer layout { .wiki-search-context-container { padding: 2px 12px 4px; + padding-left: calc(12px + 1.2ch); + text-indent: -1.2ch; } } diff --git a/src/static/css/tooltips.css b/src/static/css/tooltips.css index 644430b7..116c9181 100644 --- a/src/static/css/tooltips.css +++ b/src/static/css/tooltips.css @@ -416,10 +416,6 @@ display: inline-block; } - .content-tooltip-guy:not(.has-link) .hoverable { - cursor: default; - } - .content-tooltip-guy.has-link .text-with-tooltip-interaction-cue { text-decoration-color: var(--primary-color); } @@ -438,6 +434,10 @@ } @layer interaction { + .content-tooltip-guy:not(.has-link) .hoverable { + cursor: default; + } + .content-tooltip-guy .hoverable a { text-decoration-color: transparent; text-decoration-style: dotted; diff --git a/src/static/js/client/index.js b/src/static/js/client/index.js index 16ebe89f..cd617bea 100644 --- a/src/static/js/client/index.js +++ b/src/static/js/client/index.js @@ -133,7 +133,7 @@ for (const module of modules) { break; case 'boolean': - formatRead = Boolean; + formatRead = value => value === 'true' ? true : false; formatWrite = String; break; diff --git a/src/static/js/client/sidebar-search.js b/src/static/js/client/sidebar-search.js index 8b29cf63..c39c38bc 100644 --- a/src/static/js/client/sidebar-search.js +++ b/src/static/js/client/sidebar-search.js @@ -38,6 +38,9 @@ export const info = { searchLabel: null, searchInput: null, + contextContainer: null, + contextBackLink: null, + progressRule: null, progressContainer: null, progressLabel: null, @@ -46,9 +49,6 @@ export const info = { failedRule: null, failedContainer: null, - contextContainer: null, - contextBackLink: null, - filterContainer: null, albumFilterLink: null, artistFilterLink: null, @@ -127,6 +127,7 @@ export const info = { activeQueryContextPageName: {type: 'string'}, activeQueryContextPagePathname: {type: 'string'}, activeQueryContextPageColor: {type: 'string'}, + zapActiveQueryContext: {type: 'boolean'}, activeQueryResults: { type: 'json', @@ -163,6 +164,8 @@ export function* bindSessionStorage() { yield 'activeQueryContextPageName'; yield 'activeQueryContextPagePathname'; yield 'activeQueryContextPageColor'; + yield 'zapActiveQueryContext'; + yield 'activeQueryResults'; yield 'activeFilterType'; yield 'resultsScrollOffset'; @@ -302,6 +305,25 @@ export function addInternalListeners() { export function mutatePageContent() { if (!info.searchBox) return; + // Context section + + info.contextContainer = + document.createElement('div'); + + info.contextContainer.classList.add('wiki-search-context-container'); + + info.contextBackLink = + document.createElement('a'); + + info.contextContainer.appendChild( + templateContent(info.backString, { + page: info.contextBackLink, + })); + + cssProp(info.contextContainer, 'display', 'none'); + + info.searchBox.appendChild(info.contextContainer); + // Progress section info.progressRule = @@ -355,25 +377,6 @@ export function mutatePageContent() { info.searchBox.appendChild(info.failedRule); info.searchBox.appendChild(info.failedContainer); - // Context section - - info.contextContainer = - document.createElement('div'); - - info.contextContainer.classList.add('wiki-search-context-container'); - - info.contextBackLink = - document.createElement('a'); - - info.contextContainer.appendChild( - templateContent(info.backString, { - page: info.contextBackLink, - })); - - cssProp(info.contextContainer, 'display', 'none'); - - info.searchBox.appendChild(info.contextContainer); - // Filter section info.filterContainer = @@ -750,6 +753,20 @@ function recordActiveQueryContext() { const {session} = info; if (document.documentElement.dataset.urlKey === 'localized.home') { + session.activeQueryContextPageName = null; + session.activeQueryContextPagePathname = null; + session.activeQueryContextPageColor = null; + session.zapActiveQueryContext = true; + return; + } + + // Zapping means subsequent searches don't record context. + if (session.zapActiveQueryContext) { + return; + } + + // We also don't overwrite existing context. + if (session.activeQueryContextPagePathname) { return; } @@ -780,11 +797,22 @@ function clearSidebarSearch() { state.searchStage = null; + clearActiveQuery(); + + hideSidebarSearchResults(); +} + +function clearActiveQuery() { + const {session} = info; + session.activeQuery = null; session.activeQueryResults = null; session.resultsScrollOffset = null; - hideSidebarSearchResults(); + session.activeQueryContextPageName = null; + session.activeQueryContextPagePathname = null; + session.activeQueryContextPageColor = null; + session.zapActiveQueryContext = false; } function clearSidebarFilter() { @@ -1537,16 +1565,7 @@ function considerRecallingRecentSidebarSearch() { } function forgetRecentSidebarSearch() { - const {session} = info; - - session.activeQuery = null; - - session.activeQueryContextPageName = null; - session.activeQueryContextPagePathname = null; - session.activeQueryContextPageColor = null; - - session.activeQueryResults = null; - + clearActiveQuery(); clearSidebarFilter(); } |