From c4b40f4b7fa7ef5439845538af22cc9076e4cb9c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 9 Aug 2023 09:42:15 -0300 Subject: content: listAll{Additional,SheetMusic,MidiProject}Files --- .../generateListAllAdditionalFilesChunk.js | 77 ++++++++ src/content/dependencies/listAllAdditionalFiles.js | 9 + .../dependencies/listAllAdditionalFilesTemplate.js | 206 +++++++++++++++++++++ .../dependencies/listAllMidiProjectFiles.js | 29 +-- src/content/dependencies/listAllSheetMusicFiles.js | 29 +-- src/listing-spec.js | 72 +------ src/strings-default.json | 7 + 7 files changed, 316 insertions(+), 113 deletions(-) create mode 100644 src/content/dependencies/generateListAllAdditionalFilesChunk.js create mode 100644 src/content/dependencies/listAllAdditionalFiles.js create mode 100644 src/content/dependencies/listAllAdditionalFilesTemplate.js diff --git a/src/content/dependencies/generateListAllAdditionalFilesChunk.js b/src/content/dependencies/generateListAllAdditionalFilesChunk.js new file mode 100644 index 0000000..29ef2c0 --- /dev/null +++ b/src/content/dependencies/generateListAllAdditionalFilesChunk.js @@ -0,0 +1,77 @@ +import {empty, stitchArrays} from '../../util/sugar.js'; + +export default { + extraDependencies: ['html', 'language'], + + slots: { + title: {type: 'html'}, + + additionalFileTitles: { + validate: v => v.strictArrayOf(v.isHTML), + }, + + additionalFileLinks: { + validate: v => v.strictArrayOf(v.strictArrayOf(v.isHTML)), + }, + + additionalFileFiles: { + validate: v => v.strictArrayOf(v.strictArrayOf(v.isString)), + }, + + stringsKey: {type: 'string'}, + }, + + generate(slots, {html, language}) { + if (empty(slots.additionalFileLinks)) { + return html.blank(); + } + + return html.tags([ + html.tag('dt', slots.title), + html.tag('dd', + html.tag('ul', + stitchArrays({ + additionalFileTitle: slots.additionalFileTitles, + additionalFileLinks: slots.additionalFileLinks, + additionalFileFiles: slots.additionalFileFiles, + }).map(({ + additionalFileTitle, + additionalFileLinks, + additionalFileFiles, + }) => + (additionalFileLinks.length === 1 + ? html.tag('li', + additionalFileLinks[0].slots({ + content: + language.$(`listingPage.${slots.stringsKey}.file`, { + title: additionalFileTitle, + }), + })) + + : html.tag('li', {class: 'has-details'}, + html.tag('details', [ + html.tag('summary', + html.tag('span', + language.$(`listingPage.${slots.stringsKey}.file.withMultipleFiles`, { + title: + html.tag('span', {class: 'group-name'}, additionalFileTitle), + files: + language.countAdditionalFiles(additionalFileLinks.length, {unit: true}), + }))), + + html.tag('ul', + stitchArrays({ + additionalFileLink: additionalFileLinks, + additionalFileFile: additionalFileFiles, + }).map(({additionalFileLink, additionalFileFile}) => + html.tag('li', + additionalFileLink.slots({ + content: + language.$(`listingPage.${slots.stringsKey}.file`, { + title: additionalFileFile, + }), + })))), + ])))))), + ]); + }, +}; diff --git a/src/content/dependencies/listAllAdditionalFiles.js b/src/content/dependencies/listAllAdditionalFiles.js new file mode 100644 index 0000000..a6e34b9 --- /dev/null +++ b/src/content/dependencies/listAllAdditionalFiles.js @@ -0,0 +1,9 @@ +export default { + contentDependencies: ['listAllAdditionalFilesTemplate'], + + relations: (relation, spec) => + ({page: relation('listAllAdditionalFilesTemplate', spec, 'additionalFiles')}), + + generate: (relations) => + relations.page.slot('stringsKey', 'other.allAdditionalFiles'), +}; diff --git a/src/content/dependencies/listAllAdditionalFilesTemplate.js b/src/content/dependencies/listAllAdditionalFilesTemplate.js new file mode 100644 index 0000000..258442f --- /dev/null +++ b/src/content/dependencies/listAllAdditionalFilesTemplate.js @@ -0,0 +1,206 @@ +import {empty, stitchArrays} from '../../util/sugar.js'; +import {filterMultipleArrays, sortChronologically} from '../../util/wiki-data.js'; + +export default { + contentDependencies: [ + 'generateListingPage', + 'generateListAllAdditionalFilesChunk', + 'linkAlbum', + 'linkTrack', + 'linkAlbumAdditionalFile', + ], + + extraDependencies: ['html', 'language', 'wikiData'], + + sprawl: ({albumData}) => ({albumData}), + + query(sprawl, spec, property) { + const albums = + sortChronologically(sprawl.albumData.slice()); + + const tracks = + albums + .map(album => album.tracks.slice()); + + // Get additional file objects from albums and their tracks. + // There's a possibility that albums and tracks don't both implement + // the same additional file fields - in this case, just treat them + // as though they do implement those fields, but don't have any + // additional files of that type. + + const albumAdditionalFileObjects = + albums + .map(album => album[property] ?? []); + + const trackAdditionalFileObjects = + tracks + .map(byAlbum => byAlbum + .map(track => track[property] ?? [])); + + // Filter out tracks that don't have any additional files. + + stitchArrays({tracks, trackAdditionalFileObjects}) + .forEach(({tracks, trackAdditionalFileObjects}) => { + filterMultipleArrays(tracks, trackAdditionalFileObjects, + (track, trackAdditionalFileObjects) => !empty(trackAdditionalFileObjects)); + }); + + // Filter out albums that don't have any tracks, + // nor any additional files of their own. + + filterMultipleArrays(albums, albumAdditionalFileObjects, tracks, trackAdditionalFileObjects, + (album, albumAdditionalFileObjects, tracks, trackAdditionalFileObjects) => + !empty(albumAdditionalFileObjects) || + !empty(trackAdditionalFileObjects)); + + // Map additional file objects into titles and lists of file names. + + const albumAdditionalFileTitles = + albumAdditionalFileObjects + .map(byAlbum => byAlbum + .map(({title}) => title)); + + const albumAdditionalFileFiles = + albumAdditionalFileObjects + .map(byAlbum => byAlbum + .map(({files}) => files)); + + const trackAdditionalFileTitles = + trackAdditionalFileObjects + .map(byAlbum => byAlbum + .map(byTrack => byTrack + .map(({title}) => title))); + + const trackAdditionalFileFiles = + trackAdditionalFileObjects + .map(byAlbum => byAlbum + .map(byTrack => byTrack + .map(({files}) => files))); + + return { + spec, + albums, + tracks, + albumAdditionalFileTitles, + albumAdditionalFileFiles, + trackAdditionalFileTitles, + trackAdditionalFileFiles, + }; + }, + + relations: (relation, query) => ({ + page: + relation('generateListingPage', query.spec), + + albumLinks: + query.albums + .map(album => relation('linkAlbum', album)), + + trackLinks: + query.tracks + .map(byAlbum => byAlbum + .map(track => relation('linkTrack', track))), + + albumChunks: + query.albums + .map(() => relation('generateListAllAdditionalFilesChunk')), + + trackChunks: + query.tracks + .map(byAlbum => byAlbum + .map(() => relation('generateListAllAdditionalFilesChunk'))), + + albumAdditionalFileLinks: + stitchArrays({ + album: query.albums, + files: query.albumAdditionalFileFiles, + }).map(({album, files: byAlbum}) => + byAlbum.map(files => files + .map(file => + relation('linkAlbumAdditionalFile', album, file)))), + + trackAdditionalFileLinks: + stitchArrays({ + album: query.albums, + files: query.trackAdditionalFileFiles, + }).map(({album, files: byAlbum}) => + byAlbum + .map(byTrack => byTrack + .map(files => files + .map(file => relation('linkAlbumAdditionalFile', album, file))))), + }), + + data: (query) => ({ + albumAdditionalFileTitles: query.albumAdditionalFileTitles, + trackAdditionalFileTitles: query.trackAdditionalFileTitles, + albumAdditionalFileFiles: query.albumAdditionalFileFiles, + trackAdditionalFileFiles: query.trackAdditionalFileFiles, + }), + + slots: { + stringsKey: {type: 'string'}, + }, + + generate: (data, relations, slots, {html, language}) => + relations.page.slots({ + type: 'custom', + + content: + stitchArrays({ + albumLink: relations.albumLinks, + trackLinks: relations.trackLinks, + albumChunk: relations.albumChunks, + trackChunks: relations.trackChunks, + albumAdditionalFileTitles: data.albumAdditionalFileTitles, + trackAdditionalFileTitles: data.trackAdditionalFileTitles, + albumAdditionalFileLinks: relations.albumAdditionalFileLinks, + trackAdditionalFileLinks: relations.trackAdditionalFileLinks, + albumAdditionalFileFiles: data.albumAdditionalFileFiles, + trackAdditionalFileFiles: data.trackAdditionalFileFiles, + }).map(({ + albumLink, + trackLinks, + albumChunk, + trackChunks, + albumAdditionalFileTitles, + trackAdditionalFileTitles, + albumAdditionalFileLinks, + trackAdditionalFileLinks, + albumAdditionalFileFiles, + trackAdditionalFileFiles, + }) => [ + html.tag('h3', {class: 'content-heading'}, albumLink), + + html.tag('dl', [ + albumChunk.slots({ + title: language.$(`listingPage.${slots.stringsKey}.albumFiles`), + additionalFileTitles: albumAdditionalFileTitles, + additionalFileLinks: albumAdditionalFileLinks, + additionalFileFiles: albumAdditionalFileFiles, + stringsKey: slots.stringsKey, + }), + + stitchArrays({ + trackLink: trackLinks, + trackChunk: trackChunks, + trackAdditionalFileTitles, + trackAdditionalFileLinks, + trackAdditionalFileFiles, + }).map(({ + trackLink, + trackChunk, + trackAdditionalFileTitles, + trackAdditionalFileLinks, + trackAdditionalFileFiles, + }) => + trackChunk.slots({ + title: trackLink, + additionalFileTitles: trackAdditionalFileTitles, + additionalFileLinks: trackAdditionalFileLinks, + additionalFileFiles: trackAdditionalFileFiles, + stringsKey: slots.stringsKey, + })), + ]), + ]), + }), +}; diff --git a/src/content/dependencies/listAllMidiProjectFiles.js b/src/content/dependencies/listAllMidiProjectFiles.js index 28a925a..31a70ef 100644 --- a/src/content/dependencies/listAllMidiProjectFiles.js +++ b/src/content/dependencies/listAllMidiProjectFiles.js @@ -1,28 +1,9 @@ export default { - contentDependencies: ['generateListingPage'], - extraDependencies: ['html', 'wikiData'], + contentDependencies: ['listAllAdditionalFilesTemplate'], - sprawl() { - return {}; - }, + relations: (relation, spec) => + ({page: relation('listAllAdditionalFilesTemplate', spec, 'midiProjectFiles')}), - query(sprawl, spec) { - return { - spec, - }; - }, - - relations(relation, query) { - return { - page: relation('generateListingPage', query.spec), - }; - }, - - generate(relations, {html}) { - return relations.page.slots({ - type: 'custom', - content: - html.tag('p', `Alright alright, this is a stub page! Coming soon!`), - }); - }, + generate: (relations) => + relations.page.slot('stringsKey', 'other.allMidiProjectFiles'), }; diff --git a/src/content/dependencies/listAllSheetMusicFiles.js b/src/content/dependencies/listAllSheetMusicFiles.js index 28a925a..166b206 100644 --- a/src/content/dependencies/listAllSheetMusicFiles.js +++ b/src/content/dependencies/listAllSheetMusicFiles.js @@ -1,28 +1,9 @@ export default { - contentDependencies: ['generateListingPage'], - extraDependencies: ['html', 'wikiData'], + contentDependencies: ['listAllAdditionalFilesTemplate'], - sprawl() { - return {}; - }, + relations: (relation, spec) => + ({page: relation('listAllAdditionalFilesTemplate', spec, 'sheetMusicFiles')}), - query(sprawl, spec) { - return { - spec, - }; - }, - - relations(relation, query) { - return { - page: relation('generateListingPage', query.spec), - }; - }, - - generate(relations, {html}) { - return relations.page.slots({ - type: 'custom', - content: - html.tag('p', `Alright alright, this is a stub page! Coming soon!`), - }); - }, + generate: (relations) => + relations.page.slot('stringsKey', 'other.allSheetMusic'), }; diff --git a/src/listing-spec.js b/src/listing-spec.js index 8250317..e19b90e 100644 --- a/src/listing-spec.js +++ b/src/listing-spec.js @@ -212,71 +212,7 @@ listingSpec.push({ featureFlag: 'enableArtTagUI', }); -/* -function listAdditionalFilesInProperty(property, { - directory, - stringsKey, - seeAlso, -}) { - return { - directory, - stringsKey, - seeAlso, - groupUnderOther: true, - - data: ({wikiData: {albumData}}) => - albumData - .map(album => ({ - album, - tracks: album.tracks.filter(t => !empty(t[property])), - })) - .filter(({tracks}) => !empty(tracks)), - - html: (data, { - html, - language, - link, - }) => - data.flatMap(({album, tracks}) => [ - html.tag('h3', {class: 'content-heading'}, - link.album(album)), - - html.tag('dl', tracks.flatMap(track => [ - // No hash here since the full list of additional files is already visible - // below. The track link serves more as a way to quickly recall the track or - // to access listen links, all of which is positioned at the top of the page. - html.tag('dt', link.track(track)), - html.tag('dd', - // This page doesn't really look better with color-coded file links. - // Track links are still colored. - html.tag('ul', track[property].map(({title, files}) => - html.tag('li', - {class: [files.length > 1 && 'has-details']}, - (files.length === 1 - ? link.albumAdditionalFile( - {album, file: files[0]}, - { - text: language.$(`listingPage.${stringsKey}.file`, {title}), - }) - : html.tag('details', [ - html.tag('summary', - html.tag('span', - language.$(`listingPage.${stringsKey}.file.withMultipleFiles`, { - title: html.tag('span', {class: 'group-name'}, title), - files: language.countAdditionalFiles(files.length, {unit: true}), - }))), - html.tag('ul', files.map(file => - html.tag('li', - link.albumAdditionalFile({album, file})))), - ])))))), - ])), - ]), - }; -} -*/ - listingSpec.push({ - /* listAdditionalFilesInProperty('sheetMusicFiles') */ directory: 'all-sheet-music-files', stringsKey: 'other.allSheetMusic', contentFunction: 'listAllSheetMusicFiles', @@ -285,7 +221,6 @@ listingSpec.push({ }); listingSpec.push({ - /* listAdditionalFilesInProperty('midiProjectFiles') */ directory: 'all-midi-project-files', stringsKey: 'other.allMidiProjectFiles', contentFunction: 'listAllMidiProjectFiles', @@ -293,6 +228,13 @@ listingSpec.push({ groupUnderOther: true, }); +listingSpec.push({ + directory: 'all-additional-files', + stringsKey: 'other.allAdditionalFiles', + contentFunction: 'listAllAdditionalFiles', + groupUnderOther: true, +}); + listingSpec.push({ directory: 'random', stringsKey: 'other.randomPages', diff --git a/src/strings-default.json b/src/strings-default.json index ec174a2..59e4a96 100644 --- a/src/strings-default.json +++ b/src/strings-default.json @@ -453,12 +453,19 @@ "listingPage.listTags.byUses.item": "{TAG} ({TIMES_USED})", "listingPage.other.allSheetMusic.title": "All Sheet Music", "listingPage.other.allSheetMusic.title.short": "All Sheet Music", + "listingPage.other.allSheetMusic.albumFiles": "Album sheet music:", "listingPage.other.allSheetMusic.file": "{TITLE}", "listingPage.other.allSheetMusic.file.withMultipleFiles": "{TITLE} ({FILES})", "listingPage.other.allMidiProjectFiles.title": "All MIDI/Project Files", "listingPage.other.allMidiProjectFiles.title.short": "All MIDI/Project Files", + "listingPage.other.allMidiProjectFiles.albumFiles": "Album MIDI/project files:", "listingPage.other.allMidiProjectFiles.file": "{TITLE}", "listingPage.other.allMidiProjectFiles.file.withMultipleFiles": "{TITLE} ({FILES})", + "listingPage.other.allAdditionalFiles.title": "All Additional Files", + "listingPage.other.allAdditionalFiles.title.short": "All Additional Files", + "listingPage.other.allAdditionalFiles.albumFiles": "Album additional files:", + "listingPage.other.allAdditionalFiles.file": "{TITLE}", + "listingPage.other.allAdditionalFiles.file.withMultipleFiles": "{TITLE} ({FILES})", "listingPage.other.randomPages.title": "Random Pages", "listingPage.other.randomPages.title.short": "Random Pages", "listingPage.misc.trackContributors": "Track Contributors", -- cgit 1.3.0-6-gf8a5