« get me outta code hell

html: html.metatag('breakout') - 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>2026-06-11 08:43:28 -0300
committer(quasar) nebula <qznebula@protonmail.com>2026-06-11 08:43:36 -0300
commit64251967d7536118e1d8c2a0d2957b9d2e91cf17 (patch)
treec8b6d516a2d03f2603c04196331571bd7825349e
parent5c0430309427a4d1acc2ded199cb2eb138a82ad7 (diff)
html: html.metatag('breakout')
not actually tested with blockwrap hell yeah hell yeah
-rw-r--r--src/html.js43
1 files changed, 37 insertions, 6 deletions
diff --git a/src/html.js b/src/html.js
index b4f62ae0..7b8f327a 100644
--- a/src/html.js
+++ b/src/html.js
@@ -152,6 +152,14 @@ export const blockwrap = Symbol();
 // considered wrappable units, not the entire element!
 export const chunkwrap = Symbol();
 
+// Don't pass this directly, use html.metatag('breakout') instead.
+// Causes *contained* content to be excluded from any *containing* metatag
+// to do with special line breaking, i.e. blockwrap or chunkwrap, regardless
+// the hierarchical distance. Practically, that means momentarily concluding
+// the containing metatag's behavior wherever it operates, then starting more
+// or less anew, so the metatag still applies to any following content.
+export const breakout = 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
@@ -391,6 +399,9 @@ export function metatag(identifier, ...args) {
     case 'chunkwrap':
       return new Tag(null, {[chunkwrap]: true, ...opts}, content);
 
+    case 'breakout':
+      return new Tag(null, {[breakout]: true}, content);
+
     case 'imaginary-sibling':
       return new Tag(null, {[imaginarySibling]: true}, content);
 
@@ -691,6 +702,14 @@ export class Tag {
     return this.#getAttributeFlag(chunkwrap);
   }
 
+  get breakout() {
+    return this.#getAttributeFlag(breakout);
+  }
+
+  set breakout(value) {
+    this.#setAttributeFlag(breakout, value);
+  }
+
   set imaginarySibling(value) {
     this.#setAttributeFlag(imaginarySibling, value);
 
@@ -819,10 +838,15 @@ export class Tag {
           chunkwrapSplitter &&
           itemContent.includes('<span class="chunkwrap"');
 
+        const itemIncludesBreakout =
+          typeof item !== 'string' &&
+          itemContent.includes(`<span class="breakout"`);
+
         if (content) {
           if (
             itemIncludesChunkwrapSplit && !insideOpenChunkwrapChunk ||
             itemIncludesItsOwnChunkwrap && !insideOpenChunkwrapChunk ||
+            itemIncludesBreakout && chunkwrapSplitter && !insideOpenChunkwrapChunk
           ) {
             // The first time we see a chunkwrap splitter, backtrack and wrap
             // the content *so far* in a chunk. This will be treated just like
@@ -856,7 +880,7 @@ export class Tag {
           blockwrapClosers += `</span>`;
         }
 
-        if (itemIncludesItsOwnChunkwrap) {
+        if (itemIncludesItsOwnChunkwrap || itemIncludesBreakout) {
           const trailingWhitespace = content.match(/\s*$/);
           if (trailingWhitespace) {
             content = content.slice(0, -trailingWhitespace.length);
@@ -864,16 +888,21 @@ export class Tag {
 
           if (insideOpenChunkwrapChunk) {
             content += '</span>';
+          } else if (blockwrapClosers) {
+            content += blockwrapClosers;
+            blockwrapClosers = '';
           }
 
           content += trailingWhitespace;
           content += itemContent;
 
-          // Instate a new EVIL chunkwrap: it's not a chunkwrap chunk at all,
-          // because it's treated as display: inline, but will be closed the
-          // same as <span class="chunkwrap">, and can be detected in CSS.
-          content += `<span class="chunkwrap chunkwrapnt">`;
-          insideOpenChunkwrapChunk = true;
+          if (chunkwrapSplitter) {
+            // Instate a new EVIL chunkwrap: it's not a chunkwrap chunk at all,
+            // because it's treated as display: inline, but will be closed the
+            // same as <span class="chunkwrap">, and can be detected in CSS.
+            content += `<span class="chunkwrap chunkwrapnt">`;
+            insideOpenChunkwrapChunk = true;
+          }
 
           /* Bonus commentary re: above -
            * An item that item includes its own chunkwrap purposely causes
@@ -939,6 +968,8 @@ export class Tag {
         // been seen at all, just wrap everything in one now.
         content = `<span class="chunkwrap">${content}</span>`;
       }
+    } else if (this.breakout) {
+      content = `<span class="breakout">${content}</span>`;
     }
 
     content += blockwrapClosers;