From 28b1a728f429c4c04ee3a16584f8433a1d312c7c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 15 Sep 2022 15:20:17 -0300 Subject: update some misc-templates and refactor things --- src/util/link.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/sugar.js | 16 +++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) (limited to 'src/util') diff --git a/src/util/link.js b/src/util/link.js index ee3579d5..8fe3c2f4 100644 --- a/src/util/link.js +++ b/src/util/link.js @@ -14,6 +14,17 @@ import * as html from './html.js'; import {getColors} from './colors.js'; +import { + Album, + Artist, + ArtTag, + Flash, + Group, + NewsEntry, + StaticPage, + Track, +} from '../data/things.js'; + export function getLinkThemeString(color) { if (!color) return ''; @@ -80,6 +91,21 @@ const linkPathname = (key, conf) => const linkIndex = (key, conf) => linkHelper((_, {to}) => to('localized.' + key), conf); +// Mapping of Thing constructor classes to the key for a link.x() function. +// These represent a sensible "default" link, i.e. to the primary page for +// the given thing based on what it's an instance of. This is used for the +// link.anything() function. +const linkAnythingMapping = [ + [Album, 'album'], + [Artist, 'artist'], + [ArtTag, 'tag'], + [Flash, 'flash'], + [Group, 'groupInfo'], + [NewsEntry, 'newsEntry'], + [StaticPage, 'staticPage'], + [Track, 'track'], +]; + const link = { globalOptions: { // This should usually only 8e used during development! It'll take any @@ -134,6 +160,34 @@ const link = { root: linkPathname('shared.path', {color: false}), data: linkPathname('data.path', {color: false}), site: linkPathname('localized.path', {color: false}), + + // This is NOT an arrow functions because it should be callable for other + // "this" objects - i.e, if we bind arguments in other functions on the same + // link object, link.anything() should use those bound functions, not the + // original ones we're exporting here. + // + // This function has been through a lot of names: + // - getHrefOfAnythingMan (2020-05-25) + // - toAnythingMan (2021-03-02) + // - linkAnythingMan (2021-05-14) + // - link.anything (2022-09-15) + // ...And it'll probably end up being renamed yet again one day! + // + anything(...args) { + if (!this) { + throw new Error(`Missing value for \`this\` - investigate JS call stack`); + } + + const [thing] = args; + + for (const [constructor, fnKey] of linkAnythingMapping) { + if (thing instanceof constructor) { + return Reflect.apply(this[fnKey], this, args); + } + } + + throw new Error(`Unrecognized type of thing for linking: ${thing}`); + }, }; export default link; diff --git a/src/util/sugar.js b/src/util/sugar.js index 754f1991..8b59deef 100644 --- a/src/util/sugar.js +++ b/src/util/sugar.js @@ -107,12 +107,26 @@ export function escapeRegex(string) { return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); } +// Binds default values for arguments in a {key: value} type function argument +// (typically the second argument, but may be overridden by providing a +// [bindOpts.bindIndex] argument). Typically useful for preparing a function for +// reuse within one or multiple other contexts, which may not be aware of +// required or relevant values provided in the initial context. +// +// This function also passes the identity of `this` through (the returned value +// is not an arrow function), though note it's not a true bound function either +// (since Function.prototype.bind only supports positional arguments, not +// "options" specified via key/value). +// export function bindOpts(fn, bind) { const bindIndex = bind[bindOpts.bindIndex] ?? 1; const bound = function (...args) { const opts = args[bindIndex] ?? {}; - return fn(...args.slice(0, bindIndex), {...bind, ...opts}); + return Reflect.apply(fn, this, [ + ...args.slice(0, bindIndex), + {...bind, ...opts} + ]); }; Object.defineProperty(bound, 'name', { -- cgit 1.3.0-6-gf8a5