Forked from theinvensi/pagedjs-repeat-table-header.js
Created
March 15, 2024 21:37
-
-
Save smerrill/398b64c47b70e7fffeaf40eb2cf2b925 to your computer and use it in GitHub Desktop.
pagedjs-repeat-table-header
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class RepeatTableHeadersHandler extends Paged.Handler { | |
constructor(chunker, polisher, caller) { | |
super(chunker, polisher, caller) | |
this.splitTablesRefs = [] | |
} | |
afterPageLayout(pageElement, page, breakToken, chunker) { | |
this.chunker = chunker | |
this.splitTablesRefs = [] | |
if (breakToken) { | |
const node = breakToken.node | |
const tables = this.findAllAncestors(node, "table") | |
if (node.tagName === "TABLE") tables.push(node) | |
if (tables.length > 0) { | |
this.splitTablesRefs = tables.map(t => t.dataset.ref) | |
let thead = node.tagName === "THEAD" ? node : this.findFirstAncestor(node, "thead") | |
if (thead) { | |
let lastTheadNode = thead.hasChildNodes() ? thead.lastChild : thead | |
breakToken.node = this.nodeAfter(lastTheadNode, chunker.source) | |
} | |
this.hideEmptyTables(pageElement, node) | |
} | |
} | |
} | |
hideEmptyTables(pageElement, breakTokenNode) { | |
this.splitTablesRefs.forEach(ref => { | |
let table = pageElement.querySelector("[data-ref='" + ref + "']") | |
if (table) { | |
let sourceBody = table.querySelector("tbody > tr") | |
if (!sourceBody || this.refEquals(sourceBody.firstElementChild, breakTokenNode)) { | |
table.style.visibility = "hidden" | |
table.style.position = "absolute" | |
let lineSpacer = table.nextSibling | |
if (lineSpacer) { | |
lineSpacer.style.visibility = "hidden" | |
lineSpacer.style.position = "absolute" | |
} | |
} | |
} | |
}) | |
} | |
refEquals(a, b) { | |
return a && a.dataset && b && b.dataset && a.dataset.ref === b.dataset.ref | |
} | |
findFirstAncestor(element, selector) { | |
while (element.parentNode && element.parentNode.nodeType === 1) { | |
if (element.parentNode.matches(selector)) return element.parentNode | |
element = element.parentNode | |
} | |
return null | |
} | |
findAllAncestors(element, selector) { | |
const ancestors = [] | |
while (element.parentNode && element.parentNode.nodeType === 1) { | |
if (element.parentNode.matches(selector)) ancestors.unshift(element.parentNode) | |
element = element.parentNode | |
} | |
return ancestors | |
} | |
layout(rendered, layout) { | |
this.splitTablesRefs.forEach(ref => { | |
const renderedTable = rendered.querySelector("[data-ref='" + ref + "']") | |
if (renderedTable) { | |
if (!renderedTable.getAttribute("repeated-headers")) { | |
const sourceTable = this.chunker.source.querySelector("[data-ref='" + ref + "']") | |
this.repeatColgroup(sourceTable, renderedTable) | |
this.repeatTHead(sourceTable, renderedTable) | |
renderedTable.setAttribute("repeated-headers", true) | |
} | |
} | |
}) | |
} | |
repeatColgroup(sourceTable, renderedTable) { | |
let colgroup = sourceTable.querySelectorAll("colgroup") | |
let firstChild = renderedTable.firstChild | |
colgroup.forEach((colgroup) => { | |
let clonedColgroup = colgroup.cloneNode(true) | |
renderedTable.insertBefore(clonedColgroup, firstChild) | |
}) | |
} | |
repeatTHead(sourceTable, renderedTable) { | |
let thead = sourceTable.querySelector("thead") | |
if (thead) { | |
let clonedThead = thead.cloneNode(true) | |
renderedTable.insertBefore(clonedThead, renderedTable.firstChild) | |
} | |
} | |
nodeAfter(node, limiter) { | |
if (limiter && node === limiter) return | |
let significantNode = this.nextSignificantNode(node) | |
if (significantNode) return significantNode | |
if (node.parentNode) { | |
while ((node = node.parentNode)) { | |
if (limiter && node === limiter) return | |
significantNode = this.nextSignificantNode(node) | |
if (significantNode) return significantNode | |
} | |
} | |
} | |
nextSignificantNode(sib) { | |
while ((sib = sib.nextSibling)) { if (!this.isIgnorable(sib)) return sib } | |
return null | |
} | |
isIgnorable(node) { | |
return ( | |
(node.nodeType === 8) | |
|| ((node.nodeType === 3) && this.isAllWhitespace(node)) | |
) | |
} | |
isAllWhitespace(node) { | |
return !(/[^\t\n\r ]/.test(node.textContent)) | |
} | |
} | |
Paged.registerHandlers(RepeatTableHeadersHandler) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment