« get me outta code hell

html: metatag('imaginary-sibling') - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2024-11-15 18:35:52 -0400
committer(quasar) nebula <qznebula@protonmail.com>2024-11-15 18:46:56 -0400
commitdda59b812f86bd2e92ad8c471300e055b38db166 (patch)
tree5a7b019b073a770953e594cfdc087e432469eee8 /src
parent60f007a20db3547c57b1b1f84510707b38a4076a (diff)
html: metatag('imaginary-sibling')
Diffstat (limited to 'src')
-rw-r--r--src/util/html.js26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/util/html.js b/src/util/html.js
index 73e08854..0d667f6c 100644
--- a/src/util/html.js
+++ b/src/util/html.js
@@ -105,6 +105,12 @@ export const blockwrap = Symbol();
 // considered wrappable units, not the entire element!
 export const chunkwrap = Symbol();
 
+// Don't pass this directly, use html.metatag('imaginary-sibling') instead.
+// A tag without any content, which is completely ignored when serializing,
+// but makes siblings with [onlyIfSiblings] feel less shy and show up on
+// their own, even without a non-blank (and non-onlyIfSiblings) sibling.
+export const imaginarySibling = Symbol();
+
 // Recursive helper function for isBlank, which basically flattens an array
 // and returns as soon as it finds any content - a non-blank case - and doesn't
 // traverse templates of its own accord. If it doesn't find directly non-blank
@@ -322,6 +328,9 @@ export function metatag(identifier, ...args) {
     case 'chunkwrap':
       return new Tag(null, {[chunkwrap]: true, ...opts}, content);
 
+    case 'imaginary-sibling':
+      return new Tag(null, {[imaginarySibling]: true});
+
     default:
       throw new Error(`Unknown metatag "${identifier}"`);
   }
@@ -440,6 +449,10 @@ export class Tag {
     // something about this tag's own content or attributes. It does *not*
     // account for [html.onlyIfSiblings]!
 
+    if (this.imaginarySibling) {
+      return true;
+    }
+
     if (this.onlyIfContent && isBlank(this.content)) {
       return true;
     }
@@ -555,6 +568,14 @@ export class Tag {
     return this.#getAttributeFlag(chunkwrap);
   }
 
+  set imaginarySibling(value) {
+    this.#setAttributeFlag(imaginarySibling, value);
+  }
+
+  get imaginarySibling() {
+    return this.#getAttributeFlag(imaginarySibling);
+  }
+
   toString() {
     if (this.onlyIfContent && isBlank(this.content)) {
       return '';
@@ -652,6 +673,11 @@ export class Tag {
       const nonTemplateItem =
         Template.resolve(item);
 
+      if (nonTemplateItem instanceof Tag && nonTemplateItem.imaginarySibling) {
+        seenSiblingIndependentContent = true;
+        continue;
+      }
+
       let itemContent;
       try {
         itemContent = nonTemplateItem.toString();