From 3fb98fcbeab5173acec5222bec7a4adf597e88bb Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sat, 7 Jan 2023 09:53:29 -0400 Subject: extract utility binds, content transform fns towards basic dynamics pt. 1 (#124) --- src/misc-templates.js | 105 ++++++ src/upd8.js | 776 +----------------------------------------- src/util/transform-content.js | 447 ++++++++++++++++++++++++ src/write/bind-utilities.js | 257 ++++++++++++++ 4 files changed, 825 insertions(+), 760 deletions(-) create mode 100644 src/util/transform-content.js create mode 100644 src/write/bind-utilities.js diff --git a/src/misc-templates.js b/src/misc-templates.js index a530a3cf..9a1bbf50 100644 --- a/src/misc-templates.js +++ b/src/misc-templates.js @@ -10,6 +10,8 @@ import { unique, } from './util/sugar.js'; +import {thumb} from './util/urls.js'; + import { getTotalDuration, sortAlbumsTracksChronologically, @@ -642,6 +644,107 @@ function unbound_getFlashGridHTML({ }); } +// Images + +function unbound_img({ + html, + + src, + alt, + noSrcText = '', + thumb: thumbKey, + reveal, + id, + class: className, + width, + height, + link = false, + lazy = false, + square = false, +}) { + const willSquare = square; + const willLink = typeof link === 'string' || link; + + const originalSrc = src; + const thumbSrc = src && (thumbKey ? thumb[thumbKey](src) : src); + + const imgAttributes = { + id: link ? '' : id, + class: className, + alt, + width, + height, + }; + + const noSrcHTML = + !src && + wrap( + html.tag('div', + {class: 'image-text-area'}, + noSrcText)); + + const nonlazyHTML = + src && + wrap( + html.tag('img', { + ...imgAttributes, + src: thumbSrc, + })); + + const lazyHTML = + src && + lazy && + wrap( + html.tag('img', + { + ...imgAttributes, + class: [className, 'lazy'], + 'data-original': thumbSrc, + }), + true); + + if (!src) { + return noSrcHTML; + } else if (lazy) { + return html.tag('noscript', nonlazyHTML) + '\n' + lazyHTML; + } else { + return nonlazyHTML; + } + + function wrap(input, hide = false) { + let wrapped = input; + + wrapped = html.tag('div', {class: 'image-inner-area'}, wrapped); + wrapped = html.tag('div', {class: 'image-container'}, wrapped); + + if (reveal) { + wrapped = html.tag('div', {class: 'reveal'}, [ + wrapped, + html.tag('span', {class: 'reveal-text'}, reveal), + ]); + } + + if (willSquare) { + wrapped = html.tag('div', {class: 'square-content'}, wrapped); + wrapped = html.tag('div', + {class: ['square', hide && !willLink && 'js-hide']}, + wrapped); + } + + if (willLink) { + wrapped = html.tag('a', + { + id, + class: ['box', hide && 'js-hide'], + href: typeof link === 'string' ? link : originalSrc, + }, + wrapped); + } + + return wrapped; + } +} + // Carousel reels // Layout constants: @@ -940,6 +1043,8 @@ export { unbound_getCarouselHTML as getCarouselHTML, + unbound_img as img, + unbound_generateInfoGalleryLinks as generateInfoGalleryLinks, unbound_generateNavigationLinks as generateNavigationLinks, diff --git a/src/upd8.js b/src/upd8.js index fad3c7d8..0573dcd2 100755 --- a/src/upd8.js +++ b/src/upd8.js @@ -31,11 +31,11 @@ // Oh yeah, like. Just run this through some relatively recent version of // node.js and you'll 8e fine. ...Within the project root. O8viously. +import chroma from 'chroma-js'; + import * as path from 'path'; import {fileURLToPath} from 'url'; -import chroma from 'chroma-js'; - import { copyFile, mkdir, @@ -52,17 +52,20 @@ import {listingSpec, listingTargetSpec} from './listing-spec.js'; import urlSpec from './url-spec.js'; import * as pageSpecs from './page/index.js'; -import find, {bindFind} from './util/find.js'; +import find from './util/find.js'; import * as html from './util/html.js'; import {getColors} from './util/colors.js'; import {findFiles} from './util/io.js'; import {isMain} from './util/node-utils.js'; +import {replacerSpec} from './util/transform-content.js'; import CacheableObject from './data/things/cacheable-object.js'; import {processLanguageFile} from './data/language.js'; import {serializeThings} from './data/serialize.js'; +import {bindUtilities} from './write/bind-utilities.js'; + import { filterDuplicateDirectories, filterReferenceErrors, @@ -73,32 +76,12 @@ import { } from './data/yaml.js'; import { - fancifyFlashURL, - fancifyURL, - generateAdditionalFilesShortcut, - generateAdditionalFilesList, - generateChronologyLinks, - generateCoverLink, - generateInfoGalleryLinks, - generateNavigationLinks, - generateStickyHeadingContainer, - generateTrackListDividedByGroups, - getAlbumGridHTML, - getAlbumStylesheet, - getArtistString, - getFlashGridHTML, getFooterLocalizationLinks, - getGridHTML, - getCarouselHTML, - getRevealStringFromTags, getRevealStringFromWarnings, - getThemeString as unbound_getThemeString, - iconifyURL, + img, } from './misc-templates.js'; -import unbound_link, { - getLinkThemeString as unbound_getLinkThemeString, -} from './util/link.js'; +import link from './util/link.js'; import { color, @@ -111,14 +94,7 @@ import { progressPromiseAll, } from './util/cli.js'; -import {validateReplacerSpec, transformInline} from './util/replacer.js'; - -import { - getAlbumCover, - getArtistAvatar, - getFlashCover, - getTrackCover, -} from './util/wiki-data.js'; +import {validateReplacerSpec} from './util/replacer.js'; /* import { @@ -131,14 +107,9 @@ import { } from './util/serialize.js'; */ -import { - bindOpts, - queue, - showAggregate, - withEntries, -} from './util/sugar.js'; +import {queue, showAggregate} from './util/sugar.js'; -import {generateURLs, thumb} from './util/urls.js'; +import {generateURLs} from './util/urls.js'; // Pensive emoji! import { OFFICIAL_GROUP_DIRECTORY } from './util/magic-constants.js'; @@ -199,541 +170,14 @@ let queueSize; const urls = generateURLs(urlSpec); -function splitLines(text) { - return text.split(/\r\n|\r|\n/); -} - -const replacerSpec = { - album: { - find: 'album', - link: 'album', - }, - 'album-commentary': { - find: 'album', - link: 'albumCommentary', - }, - 'album-gallery': { - find: 'album', - link: 'albumGallery', - }, - artist: { - find: 'artist', - link: 'artist', - }, - 'artist-gallery': { - find: 'artist', - link: 'artistGallery', - }, - 'commentary-index': { - find: null, - link: 'commentaryIndex', - }, - date: { - find: null, - value: (ref) => new Date(ref), - html: (date, {language}) => - html.tag('time', - {datetime: date.toString()}, - language.formatDate(date)), - }, - 'flash-index': { - find: null, - link: 'flashIndex', - }, - flash: { - find: 'flash', - link: 'flash', - transformName(name, node, input) { - const nextCharacter = input[node.iEnd]; - const lastCharacter = name[name.length - 1]; - if (![' ', '\n', '<'].includes(nextCharacter) && lastCharacter === '.') { - return name.slice(0, -1); - } else { - return name; - } - }, - }, - group: { - find: 'group', - link: 'groupInfo', - }, - 'group-gallery': { - find: 'group', - link: 'groupGallery', - }, - home: { - find: null, - link: 'home', - }, - 'listing-index': { - find: null, - link: 'listingIndex', - }, - listing: { - find: 'listing', - link: 'listing', - }, - media: { - find: null, - link: 'media', - }, - 'news-index': { - find: null, - link: 'newsIndex', - }, - 'news-entry': { - find: 'newsEntry', - link: 'newsEntry', - }, - root: { - find: null, - link: 'root', - }, - site: { - find: null, - link: 'site', - }, - static: { - find: 'staticPage', - link: 'staticPage', - }, - string: { - find: null, - value: (ref) => ref, - html: (ref, {language, args}) => language.$(ref, args), - }, - tag: { - find: 'artTag', - link: 'tag', - }, - track: { - find: 'track', - link: 'track', - }, -}; - -if (!validateReplacerSpec(replacerSpec, {find, link: unbound_link})) { +if (!validateReplacerSpec(replacerSpec, {find, link})) { process.exit(); } -function parseAttributes(string, {to}) { - const attributes = Object.create(null); - const skipWhitespace = (i) => { - const ws = /\s/; - if (ws.test(string[i])) { - const match = string.slice(i).match(/[^\s]/); - if (match) { - return i + match.index; - } else { - return string.length; - } - } else { - return i; - } - }; - - for (let i = 0; i < string.length; ) { - i = skipWhitespace(i); - const aStart = i; - const aEnd = i + string.slice(i).match(/[\s=]|$/).index; - const attribute = string.slice(aStart, aEnd); - i = skipWhitespace(aEnd); - if (string[i] === '=') { - i = skipWhitespace(i + 1); - let end, endOffset; - if (string[i] === '"' || string[i] === "'") { - end = string[i]; - endOffset = 1; - i++; - } else { - end = '\\s'; - endOffset = 0; - } - const vStart = i; - const vEnd = i + string.slice(i).match(new RegExp(`${end}|$`)).index; - const value = string.slice(vStart, vEnd); - i = vEnd + endOffset; - if (attribute === 'src' && value.startsWith('media/')) { - attributes[attribute] = to('media.path', value.slice('media/'.length)); - } else { - attributes[attribute] = value; - } - } else { - attributes[attribute] = attribute; - } - } - return Object.fromEntries( - Object.entries(attributes).map(([key, val]) => [ - key, - val === 'true' - ? true - : val === 'false' - ? false - : val === key - ? true - : val, - ]) - ); -} - -function joinLineBreaks(sourceLines) { - const outLines = []; - - let lineSoFar = ''; - for (let i = 0; i < sourceLines.length; i++) { - const line = sourceLines[i]; - lineSoFar += line; - if (!line.endsWith('
')) { - outLines.push(lineSoFar); - lineSoFar = ''; - } - } - - if (lineSoFar) { - outLines.push(lineSoFar); - } - - return outLines; -} - -function transformMultiline(text, { - parseAttributes, - transformInline, - thumb = null, -}) { - // Heck yes, HTML magics. - - text = transformInline(text.trim()); - - const outLines = []; - - const indentString = ' '.repeat(4); - - let levelIndents = []; - const openLevel = (indent) => { - // opening a sublist is a pain: to be semantically *and* visually - // correct, we have to append the