« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/content/dependencies/generateListingPage.js66
-rw-r--r--src/listing-spec.js54
2 files changed, 87 insertions, 33 deletions
diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js
index 74c90baa..1974f822 100644
--- a/src/content/dependencies/generateListingPage.js
+++ b/src/content/dependencies/generateListingPage.js
@@ -1,4 +1,4 @@
-import {empty} from '../../util/sugar.js';
+import {empty, stitchArrays} from '../../util/sugar.js';
 
 export default {
   contentDependencies: [
@@ -9,22 +9,7 @@ export default {
 
   extraDependencies: ['html', 'language', 'wikiData'],
 
-  sprawl({listingSpec}) {
-    return {listingSpec};
-  },
-
-  query(sprawl, listing) {
-    return {
-      seeAlso:
-        (listing.seeAlso
-          ? listing.seeAlso.map(directory =>
-              sprawl.listingSpec
-                .find(listing => listing.directory === directory))
-          : null),
-    };
-  },
-
-  relations(relation, query) {
+  relations(relation, listing) {
     const relations = {};
 
     relations.layout =
@@ -33,23 +18,34 @@ export default {
     relations.listingsIndexLink =
       relation('linkListingIndex');
 
-    if (!empty(query.seeAlso)) {
-      // TODO: Invalid listing directories filtered here aren't warned about anywhere.
-      // Honestly we shouldn't be searching listingSpec here at all - listings should
-      // be implemented as proper things which search listingSpec themselves, and
-      // expose seeAlso as a list of listing objects rather than by reference.
+    if (listing.target.listings.length > 1) {
+      relations.sameTargetListingLinks =
+        listing.target.listings
+          .map(listing => relation('linkListing', listing));
+    }
+
+    if (!empty(listing.seeAlso)) {
       relations.seeAlsoLinks =
-        query.seeAlso
-          .map(listing => relation('linkListing', listing))
-          .filter(Boolean);
+        listing.seeAlso
+          .map(listing => relation('linkListing', listing));
     }
 
     return relations;
   },
 
-  data(query, sprawl, listing) {
+  data(listing) {
     return {
       stringsKey: listing.stringsKey,
+
+      targetStringsKey: listing.target.stringsKey,
+
+      sameTargetListingStringsKeys:
+        listing.target.listings
+          .map(listing => listing.stringsKey),
+
+      sameTargetListingsCurrentIndex:
+        listing.target.listings
+          .indexOf(listing),
     };
   },
 
@@ -69,6 +65,24 @@ export default {
       headingMode: 'sticky',
 
       mainContent: [
+        relations.sameTargetListingLinks &&
+          html.tag('p',
+            language.$('listingPage.listingsFor', {
+              target: language.$(`listingPage.target.${data.targetStringsKey}`),
+              listings:
+                language.formatUnitList(
+                  stitchArrays({
+                    link: relations.sameTargetListingLinks,
+                    stringsKey: data.sameTargetListingStringsKeys,
+                  }).map(({link, stringsKey}, index) =>
+                      html.tag('span',
+                        {class: index === data.sameTargetListingsCurrentIndex && 'current'},
+                        link.slots({
+                          attributes: {class: 'nowrap'},
+                          content: language.$(`listingPage.${stringsKey}.title.short`),
+                        })))),
+            })),
+
         relations.seeAlsoLinks &&
           html.tag('p',
             language.$('listingPage.seeAlso', {
diff --git a/src/listing-spec.js b/src/listing-spec.js
index c81c0866..9c1134f4 100644
--- a/src/listing-spec.js
+++ b/src/listing-spec.js
@@ -1,8 +1,9 @@
 import {OFFICIAL_GROUP_DIRECTORY} from './util/magic-constants.js';
 
 import {
-  empty,
   accumulateSum,
+  empty,
+  showAggregate,
 } from './util/sugar.js';
 
 import {
@@ -1078,34 +1079,73 @@ listingSpec.push({
     ]),
 });
 
+{
+  const errors = [];
+
+  for (const listing of listingSpec) {
+    if (listing.seeAlso) {
+      const suberrors = [];
+
+      for (let i = 0; i < listing.seeAlso.length; i++) {
+        const directory = listing.seeAlso[i];
+        const match = listingSpec.find(listing => listing.directory === directory);
+
+        if (match) {
+          listing.seeAlso[i] = match;
+        } else {
+          listing.seeAlso[i] = null;
+          suberrors.push(new Error(`(index: ${i}) Didn't find a listing matching ${directory}`))
+        }
+      }
+
+      listing.seeAlso = listing.seeAlso.filter(Boolean);
+
+      if (!empty(suberrors)) {
+        errors.push(new AggregateError(suberrors, `Errors matching "see also" listings for ${listing.directory}`));
+      }
+    }
+  }
+
+  if (!empty(errors)) {
+    const aggregate = new AggregateError(errors, `Errors validating listings`);
+    showAggregate(aggregate, {showTraces: false});
+  }
+}
+
 const filterListings = (directoryPrefix) =>
   listingSpec.filter(l => l.directory.startsWith(directoryPrefix));
 
 const listingTargetSpec = [
   {
-    title: ({language}) => language.$('listingPage.target.album'),
+    stringsKey: 'album',
     listings: filterListings('album'),
   },
   {
-    title: ({language}) => language.$('listingPage.target.artist'),
+    stringsKey: 'artist',
     listings: filterListings('artist'),
   },
   {
-    title: ({language}) => language.$('listingPage.target.group'),
+    stringsKey: 'group',
     listings: filterListings('group'),
   },
   {
-    title: ({language}) => language.$('listingPage.target.track'),
+    stringsKey: 'track',
     listings: filterListings('track'),
   },
   {
-    title: ({language}) => language.$('listingPage.target.tag'),
+    stringsKey: 'tag',
     listings: filterListings('tag'),
   },
   {
-    title: ({language}) => language.$('listingPage.target.other'),
+    stringsKey: 'other',
     listings: listingSpec.filter(l => l.groupUnderOther),
   },
 ];
 
+for (const target of listingTargetSpec) {
+  for (const listing of target.listings) {
+    listing.target = target;
+  }
+}
+
 export {listingSpec, listingTargetSpec};