;(function () { if ((!document.getNamedFlows) && document.webkitGetNamedFlows) { document.getNamedFlows = document.webkitGetNamedFlows; } if (!document.getNamedFlow) { document.getNamedFlow = function (name) { return document.getNamedFlows(name).namedItem(name); } } var textFlow = document.getNamedFlow('main'); /** * Returns first region the given node is shown within * * workaround for getRegionsForContent() as that function only seems to work * on block-elements */ function getRegionByNode(flow, node) { var ranges, regions = flow.getRegionsByContent(node); if (regions.length > 0) { return regions[0]; } else { regions = flow.getRegions(); for (var i=0; i < regions.length; i++) { ranges = regions[i].webkitGetRegionFlowRanges(); for (var r=0; r < ranges.length; r++) { if (ranges[r].isPointInRange(node, 0)) { return regions[i]; } } } console.log('Could not find region for node', node); } } /** * Find page for given node, travels up the DOM tree to find * first wrapping paper element. Does not work for Nodes in a flow. */ function getPageByNode (node) { if (node) { if (node.classList.contains('paper')) { return node; } else { if (node.parentElement) { return getPageByNode(node.parentElement); } else { return false; } } return false; } } /** * Get page by node in region */ function getPageByRegionNode (flow, node) { var region = getRegionByNode(flow, node); if (region) { return getPageByNode(getRegionByNode(flow, node)); } else { return null; } } /** * Return page number for given page */ function getPageNum (page) { return parseInt(page.id.replace(/\D/g, '')); } window.fixOrphans = function () { var threshold = 80, step = -.025, max = -0.125; spans = document.querySelectorAll('.last-line'); for (var i=0; i < spans.length; i++) { var rects = spans[i].getClientRects(), lineCount = rects.length; // Remember how many lines we had at the start if (rects.length > 0 && rects[rects.length-1].width <= threshold) { var spacing = 0; while(rects.length >= lineCount && spacing >= max) { spacing += step; spans[i].style.letterSpacing = spacing + 'mm'; rects = spans[i].getClientRects() } if (rects.length == lineCount) { spans[i].style.letterSpacing = 0; } } } } window.fixWidows = function () { var threshold = 40, p = document.querySelectorAll('p'); for (var i=0; i < p.length; i++) { var rects = p[i].getClientRects(); if (rects.length > 1 && rects[0].height < threshold) { p[i].classList.add('break-before'); } } } window.reattachHeaders = function () { var textFlow = document.getNamedFlow('main'), headers = document.querySelectorAll('h4'); for (var i=0; i< headers.length; i++) { var h = headers[i], p = h.nextElementSibling; if (getPageNum(getPageByRegionNode(textFlow, h)) != getPageNum(getPageByRegionNode(textFlow, p))) { h.classList.add('break-before'); } else { var threshold = 75, rects = p.getClientRects(); if (rects.length > 1 && rects[0].height <= threshold) { h.classList.add('break-before'); } } } } window.typographicFixes = function () { fixOrphans(); reattachHeaders(); fixWidows(); } })();