« get me outta code hell

content: listArtTagNetwork - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-10-13 21:35:05 -0300
committer(quasar) nebula <qznebula@protonmail.com>2023-10-13 21:35:05 -0300
commit7ff695f356d1e9a18d5f206e8d57bfc18c37f054 (patch)
tree2c60f9cc226be3351077c781718718770a8bd17f
parent43610c3dbef9a34fc66eed6b0bf7b22f989635c5 (diff)
content: listArtTagNetwork
-rw-r--r--src/content/dependencies/listArtTagNetwork.js247
-rw-r--r--src/listing-spec.js7
-rw-r--r--src/strings-default.json12
3 files changed, 265 insertions, 1 deletions
diff --git a/src/content/dependencies/listArtTagNetwork.js b/src/content/dependencies/listArtTagNetwork.js
index b3a5474..cc79d40 100644
--- a/src/content/dependencies/listArtTagNetwork.js
+++ b/src/content/dependencies/listArtTagNetwork.js
@@ -1 +1,246 @@
-export default {generate() {}};
+import {empty, stitchArrays, unique} from '#sugar';
+import {sortAlphabetically} from '#wiki-data';
+
+export default {
+  contentDependencies: ['generateListingPage', 'linkArtTagInfo'],
+  extraDependencies: ['html', 'language', 'wikiData'],
+
+  sprawl({artTagData}) {
+    return {artTagData};
+  },
+
+  query(sprawl, spec) {
+    const artTags =
+      sprawl.artTagData.filter(artTag => !artTag.isContentWarning);
+
+    const rootArtTags =
+      artTags
+        .filter(artTag => !empty(artTag.directDescendantArtTags))
+        .filter(artTag =>
+          empty(artTag.directAncestorArtTags) ||
+          artTag.directAncestorArtTags.length >= 2);
+
+    sortAlphabetically(rootArtTags);
+
+    rootArtTags.sort(
+      ({directAncestorArtTags: ancestorsA},
+       {directAncestorArtTags: ancestorsB}) =>
+        ancestorsA.length - ancestorsB.length);
+
+    const recursive = (artTag, asRoot) => {
+      const descendantNodes =
+        (empty(artTag.directDescendantArtTags)
+          ? null
+       : !asRoot && artTag.directAncestorArtTags.length >= 2
+          ? null
+          : artTag.directDescendantArtTags
+              .map(artTag => recursive(artTag, false)));
+
+      descendantNodes?.sort(
+        ({descendantNodes: descendantNodesA},
+         {descendantNodes: descendantNodesB}) =>
+            (descendantNodesA ? 1 : 0)
+          - (descendantNodesB ? 1 : 0));
+
+      const recursiveGetRootAncestor = ancestorArtTag =>
+        (rootArtTags.includes(ancestorArtTag)
+          ? ancestorArtTag
+          : recursiveGetRootAncestor(ancestorArtTag.directAncestorArtTags[0]));
+
+      const ancestorRootArtTags =
+        (asRoot && !empty(artTag.directAncestorArtTags)
+          ? unique(artTag.directAncestorArtTags.map(recursiveGetRootAncestor))
+          : null);
+
+      return {
+        artTag,
+        descendantNodes,
+        ancestorRootArtTags,
+      };
+    };
+
+    const uppermostRootTags =
+      artTags
+        .filter(artTag => !empty(artTag.directDescendantArtTags))
+        .filter(artTag => empty(artTag.directAncestorArtTags));
+
+    const orphanArtTags =
+      artTags
+        .filter(artTag => empty(artTag.directDescendantArtTags))
+        .filter(artTag => empty(artTag.directAncestorArtTags));
+
+    return {
+      spec,
+
+      rootNodes:
+        rootArtTags
+          .map(artTag => recursive(artTag, true)),
+
+      uppermostRootTags,
+      orphanArtTags,
+    };
+  },
+
+  relations(relation, query) {
+    const recursive = queryNode => ({
+      artTagLink:
+        relation('linkArtTagInfo', queryNode.artTag),
+
+      ancestorTagLinks:
+        queryNode.ancestorRootArtTags
+          ?.map(artTag => relation('linkArtTagInfo', artTag))
+          ?? null,
+
+      descendantNodes:
+        queryNode.descendantNodes
+          ?.map(recursive)
+          ?? null,
+    });
+
+    return {
+      page:
+        relation('generateListingPage', query.spec),
+
+      rootNodes:
+        query.rootNodes.map(recursive),
+
+      uppermostRootTagLinks:
+        query.uppermostRootTags
+          .map(artTag => relation('linkArtTagInfo', artTag)),
+
+      orphanArtTagLinks:
+        query.orphanArtTags
+          .map(artTag => relation('linkArtTagInfo', artTag)),
+    };
+  },
+
+  data(query) {
+    const rootArtTags = query.rootNodes.map(({artTag}) => artTag);
+
+    const recursive = queryNode => ({
+      directory:
+        queryNode.artTag.directory,
+
+      representsRoot:
+        rootArtTags.includes(queryNode.artTag),
+
+      ancestorTagDirectories:
+        queryNode.ancestorRootArtTags
+          ?.map(artTag => artTag.directory)
+          ?? null,
+
+      descendantNodes:
+        queryNode.descendantNodes
+          ?.map(recursive)
+          ?? null,
+    });
+
+    return {
+      rootNodes:
+        query.rootNodes.map(recursive),
+
+      uppermostRootTagDirectories:
+        query.uppermostRootTags
+          .map(artTag => artTag.directory),
+    };
+  },
+
+  generate(data, relations, {html, language}) {
+    const prefix = `listingPage.listArtTags.network`;
+
+    const recursive = (dataNode, relationsNode, asRoot) => [
+      html.tag('dt',
+        (asRoot
+          ? {id: dataNode.directory}
+          : {}),
+
+        (asRoot
+          ? (relationsNode.ancestorTagLinks
+              ? language.$(prefix, 'root.withAncestors', {
+                  tag: relationsNode.artTagLink,
+                  ancestors:
+                    language.formatUnitList(
+                      stitchArrays({
+                        link: relationsNode.ancestorTagLinks,
+                        directory: dataNode.ancestorTagDirectories,
+                      }).map(({link, directory}) =>
+                          link.slots({
+                            anchor: true,
+                            hash: directory,
+                          }))),
+                })
+              : language.$(prefix, 'root.jumpToTop', {
+                  tag: relationsNode.artTagLink,
+                  link:
+                    html.tag('a', {href: '#top'},
+                      language.$(prefix, 'root.jumpToTop.link')),
+                }))
+          : (dataNode.representsRoot
+              ? language.$(prefix, 'descendant.jumpToRoot', {
+                  tag:
+                    relationsNode.artTagLink.slots({
+                      anchor: true,
+                      hash: dataNode.directory,
+                    }),
+                })
+              : language.$(prefix, 'descendant', {
+                  tag: relationsNode.artTagLink,
+                })))),
+
+      dataNode.descendantNodes &&
+      relationsNode.descendantNodes &&
+        html.tag('dd',
+          html.tag('dl',
+            stitchArrays({
+              dataNode: dataNode.descendantNodes,
+              relationsNode: relationsNode.descendantNodes,
+            }).map(({dataNode, relationsNode}) =>
+                recursive(dataNode, relationsNode, false)))),
+    ];
+
+    return relations.page.slots({
+      type: 'custom',
+
+      content: [
+        html.tag('dl', [
+          html.tag('dt', {id: 'top'},
+            language.$(prefix, 'jumpToRoot.title')),
+
+          html.tag('dd',
+            html.tag('ul',
+              stitchArrays({
+                link: relations.uppermostRootTagLinks,
+                directory: data.uppermostRootTagDirectories,
+              }).map(({link, directory}) =>
+                  html.tag('li',
+                    language.$(prefix, 'jumpToRoot.item', {
+                      tag:
+                        link.slots({
+                          anchor: true,
+                          hash: directory,
+                        }),
+                    }))))),
+
+          stitchArrays({
+            dataNode: data.rootNodes,
+            relationsNode: relations.rootNodes,
+          }).map(({dataNode, relationsNode}) =>
+              recursive(dataNode, relationsNode, true)),
+
+          !empty(relations.orphanArtTagLinks) && [
+            html.tag('dt',
+              language.$(prefix, 'orphanArtTags.title')),
+
+            html.tag('dd',
+              html.tag('ul',
+                relations.orphanArtTagLinks.map(orphanArtTagLink =>
+                  html.tag('li',
+                    language.$(prefix, 'orphanArtTags.item', {
+                      tag: orphanArtTagLink,
+                    }))))),
+          ],
+        ]),
+      ],
+    });
+  },
+};
diff --git a/src/listing-spec.js b/src/listing-spec.js
index 5a2eaf5..93b1090 100644
--- a/src/listing-spec.js
+++ b/src/listing-spec.js
@@ -197,6 +197,13 @@ listingSpec.push({
 });
 
 listingSpec.push({
+  directory: 'tags/network',
+  stringsKey: 'listArtTags.network',
+  contentFunction: 'listArtTagNetwork',
+  featureFlag: 'enableArtTagUI',
+});
+
+listingSpec.push({
   directory: 'all-sheet-music-files',
   stringsKey: 'other.allSheetMusic',
   contentFunction: 'listAllSheetMusicFiles',
diff --git a/src/strings-default.json b/src/strings-default.json
index 0c34fdf..89f54a4 100644
--- a/src/strings-default.json
+++ b/src/strings-default.json
@@ -502,6 +502,18 @@
   "listingPage.listArtTags.byUses.title": "Tags - by Uses",
   "listingPage.listArtTags.byUses.title.short": "...by Uses",
   "listingPage.listArtTags.byUses.item": "{TAG} ({TIMES_USED})",
+  "listingPage.listArtTags.network.title": "Art Tag Network",
+  "listingPage.listArtTags.network.title.short": "Art Tag Network",
+  "listingPage.listArtTags.network.jumpToRoot.title": "Jump to one of the upper-most tags:",
+  "listingPage.listArtTags.network.jumpToRoot.item": "{TAG}",
+  "listingPage.listArtTags.network.root": "{TAG}",
+  "listingPage.listArtTags.network.root.jumpToTop": "{TAG} ({LINK})",
+  "listingPage.listArtTags.network.root.jumpToTop.link": "jump back to top",
+  "listingPage.listArtTags.network.root.withAncestors": "{TAG} (descends from {ANCESTORS})",
+  "listingPage.listArtTags.network.descendant": "{TAG}",
+  "listingPage.listArtTags.network.descendant.jumpToRoot": "Jump to: {TAG}",
+  "listingPage.listArtTags.network.orphanArtTags.title": "These tags don't have any descendants or ancestors:",
+  "listingPage.listArtTags.network.orphanArtTags.item": "{TAG}",
   "listingPage.other.allSheetMusic.title": "All Sheet Music",
   "listingPage.other.allSheetMusic.title.short": "All Sheet Music",
   "listingPage.other.allSheetMusic.albumFiles": "Album sheet music:",