diff --git a/css/smpte.css b/css/smpte.css index 280b1eb..80056b3 100644 --- a/css/smpte.css +++ b/css/smpte.css @@ -207,9 +207,9 @@ blockquote { font-style: italic; } -/* note and example */ +/* note, example, footnote */ -.note, .example { +.note, .example, .footnote { font-size: 0.9rem; margin-left: 1rem; } diff --git a/doc/main.html b/doc/main.html index 834d7d3..99a09bf 100644 --- a/doc/main.html +++ b/doc/main.html @@ -1133,10 +1133,78 @@

Tables

<a href="#tab-sample-tabledata"></a> is rendered as . -

+

For more examples of various table layouts and optional cell/column text alignment, see

+

Tables may include footnotes. Footnotes shall appear in a tfoot element at the foot of the table, + each as a p element with class="footnote" and a unique id attribute. Footnotes are automatically assigned superscript lowercase letters (a, b, c, …) in the order they appear in the tfoot element. + References to footnotes within the table body are marked with an a element whose href + attribute references the footnote's id.

+ +

Footnotes are only permitted within tables. They shall not be used outside of a table element.

+ +
+
+<table id="tab-sample-footnote">
+  <caption>Sample Table with Footnotes</caption>
+  <thead>
+    <tr>
+      <th>Sample Number</th>
+      <th>Sample Name</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>0001</td>
+      <td>Name 01 <a href="#fn-doc-example"></a></td>
+    </tr>
+    <tr>
+      <td>0002</td>
+      <td>Name 02</td>
+    </tr>
+  </tbody>
+  <tfoot>
+    <tr>
+      <td colspan="2">
+        <p class="footnote" id="fn-doc-example">Footnote content goes here.</p>
+      </td>
+    </tr>
+  </tfoot>
+</table>
+
+ +

is rendered as

+ + + + + + + + + + + + + + + + + + + + + + + + +
Sample Table with Footnotes
Sample NumberSample Name
0001Name 01
0002Name 02
+

Footnote content goes here.

+
+
+ +
@@ -1360,6 +1428,9 @@

Using class attributes

example
Applied to p or div elements to create a formatted and automatically numbered example. See .
+
footnote
+
Applied to a p element inside a tfoot element to create a table footnote. Footnotes are only permitted inside a tfoot element — use outside of tables is not allowed. See .
+
center-cell;
right-cell;
left-cell;
diff --git a/js/validate.mjs b/js/validate.mjs index 039193e..323e3bc 100644 --- a/js/validate.mjs +++ b/js/validate.mjs @@ -65,10 +65,18 @@ function validateDisallowedStyleAttributes(root, logger) { } } +function validateFootnoteLocation(root, logger) { + for (const fn of root.querySelectorAll('.footnote')) { + if (!fn.closest('tfoot')) + logger.error(`Footnotes are only permitted inside a table footer`, fn); + } +} + export function smpteValidate(doc, logger) { const docMetadata = smpte.validateHead(doc.head, logger); validateDisallowedHeadLinks(doc.head, logger); validateDisallowedStyleAttributes(doc.documentElement, logger); + validateFootnoteLocation(doc.documentElement, logger); validateBody(doc.body, logger); return docMetadata; } diff --git a/smpte.js b/smpte.js index 408fe2a..5b334b9 100644 --- a/smpte.js +++ b/smpte.js @@ -1104,6 +1104,7 @@ function numberNotesToEntry(internalTermsSection) { child.insertBefore(headingLabel, child.firstChild); } + } function numberSectionNotes(section) { @@ -1111,7 +1112,7 @@ function numberSectionNotes(section) { function _findNotes(e) { for (const child of e.children) { - if (child.localName === "section") + if (child.localName === "section" || child.localName === "table") numberSectionNotes(child); else if (child.classList.contains("note")) notes.push(child); @@ -1194,6 +1195,36 @@ function numberExamples() { } } +function numberTableFootnotes() { + for (const table of document.querySelectorAll("table")) { + const footnotes = Array.from(table.querySelectorAll("tfoot p.footnote")); + if (footnotes.length === 0) continue; + + let charCode = "a".charCodeAt(0); + + for (const fn of footnotes) { + if (!fn.id) continue; + const letter = String.fromCharCode(charCode++); + + const headingLabel = document.createElement("span"); + headingLabel.className = "heading-label"; + + const sup = document.createElement("sup"); + sup.textContent = letter; + + headingLabel.appendChild(sup); + headingLabel.appendChild(document.createTextNode("\u00a0")); + + fn.insertBefore(headingLabel, fn.firstChild); + + /* fill all reference anchors pointing to this footnote */ + for (const ref of table.querySelectorAll(`a[href="#${fn.id}"]`)) { + ref.textContent = letter; + } + } + } +} + function numberTerms() { const termsSection = document.getElementById("sec-terms-and-definitions"); const terms = document.getElementById("terms-int-defs"); @@ -1382,6 +1413,13 @@ function resolveLinks(docMetadata) { anchor.innerText = t; } + } else if (target.classList.contains("footnote")) { + + /* footnote ref — letter already filled by numberTableFootnotes; wrap in */ + const sup = document.createElement("sup"); + anchor.replaceWith(sup); + sup.appendChild(anchor); + } else if (target.localName === "section") { anchor.innerText = _getSectionReference(target); @@ -1487,6 +1525,7 @@ async function render() { numberFormulae(); numberNotes(); numberExamples(); + numberTableFootnotes(); numberTerms(); resolveLinks(docMetadata); insertTOC(docMetadata); diff --git a/test/resources/html/validation/footnote-invalid.html b/test/resources/html/validation/footnote-invalid.html new file mode 100644 index 0000000..a74f517 --- /dev/null +++ b/test/resources/html/validation/footnote-invalid.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + Title of the document + + +
+

This is the scope of the document.

+
+ +
+

Footnote

+ + + + + + + + + + + + + + + + + + + +
Sample Table
Sample NumberSample Name
0001Name 01
0002Name 02
+ +

Footnote content goes here.

+ +
+ + + \ No newline at end of file diff --git a/test/resources/html/validation/footnote-valid.html b/test/resources/html/validation/footnote-valid.html new file mode 100644 index 0000000..de7f324 --- /dev/null +++ b/test/resources/html/validation/footnote-valid.html @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + Title of the document + + +
+

This is the scope of the document.

+
+ +
+

Footnote

+ + + + + + + + + + + + + + + + + + + + + + + + +
Sample Table
Sample NumberSample Name
0001Name 01
0002Name 02
+

Footnote content goes here.

+
+ +
+ + + \ No newline at end of file diff --git a/test/resources/html/validation/st-valid.html b/test/resources/html/validation/st-valid.html index 9f9f2ff..258d097 100644 --- a/test/resources/html/validation/st-valid.html +++ b/test/resources/html/validation/st-valid.html @@ -19,5 +19,8 @@

This is the scope of the document.

+ + + \ No newline at end of file