UNPKG

pagedjs

Version:

Chunks up a document into paged media flows and applies print styles

858 lines (845 loc) 35.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _utils = require("../utils/utils.cjs"); var _dom = require("../utils/dom.cjs"); var _breaktoken = _interopRequireDefault(require("./breaktoken.cjs")); var _renderresult = _interopRequireWildcard(require("./renderresult.cjs")); var _eventEmitter = _interopRequireDefault(require("event-emitter")); var _hook = _interopRequireDefault(require("../utils/hook.cjs")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } var MAX_CHARS_PER_BREAK = 1500; /** * Layout * @class */ var Layout = /*#__PURE__*/function () { function Layout(element, hooks, options) { (0, _classCallCheck2["default"])(this, Layout); this.element = element; this.bounds = this.element.getBoundingClientRect(); this.parentBounds = this.element.offsetParent.getBoundingClientRect(); var gap = parseFloat(window.getComputedStyle(this.element).columnGap); if (gap) { var leftMargin = this.bounds.left - this.parentBounds.left; this.gap = gap - leftMargin; } else { this.gap = 0; } if (hooks) { this.hooks = hooks; } else { this.hooks = {}; this.hooks.onPageLayout = new _hook["default"](); this.hooks.layout = new _hook["default"](); this.hooks.renderNode = new _hook["default"](); this.hooks.layoutNode = new _hook["default"](); this.hooks.beforeOverflow = new _hook["default"](); this.hooks.onOverflow = new _hook["default"](); this.hooks.afterOverflowRemoved = new _hook["default"](); this.hooks.onBreakToken = new _hook["default"](); this.hooks.beforeRenderResult = new _hook["default"](); } this.settings = options || {}; this.maxChars = this.settings.maxChars || MAX_CHARS_PER_BREAK; this.forceRenderBreak = false; } (0, _createClass2["default"])(Layout, [{ key: "renderTo", value: function () { var _renderTo = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(wrapper, source, breakToken) { var bounds, start, walker, node, prevNode, done, next, hasRenderedContent, newBreakToken, length, prevBreakToken, imgs, _imgs, after, named, page, shallow, rendered, _imgs2, _after, _args = arguments; return _regenerator["default"].wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: bounds = _args.length > 3 && _args[3] !== undefined ? _args[3] : this.bounds; start = this.getStart(source, breakToken); walker = (0, _dom.walk)(start, source); hasRenderedContent = false; length = 0; prevBreakToken = breakToken || new _breaktoken["default"](start); this.hooks && this.hooks.onPageLayout.trigger(wrapper, prevBreakToken, this); case 7: if (!(!done && !newBreakToken)) { _context.next = 77; break; } next = walker.next(); prevNode = node; node = next.value; done = next.done; if (node) { _context.next = 26; break; } this.hooks && this.hooks.layout.trigger(wrapper, this); imgs = wrapper.querySelectorAll("img"); if (!imgs.length) { _context.next = 18; break; } _context.next = 18; return this.waitForImages(imgs); case 18: newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (!(newBreakToken && newBreakToken.equals(prevBreakToken))) { _context.next = 23; break; } console.warn("Unable to layout item: ", prevNode); this.hooks && this.hooks.beforeRenderResult.trigger(undefined, wrapper, this); return _context.abrupt("return", new _renderresult["default"](undefined, new _renderresult.OverflowContentError("Unable to layout item", [prevNode]))); case 23: this.rebuildTableFromBreakToken(newBreakToken, wrapper); this.hooks && this.hooks.beforeRenderResult.trigger(newBreakToken, wrapper, this); return _context.abrupt("return", new _renderresult["default"](newBreakToken)); case 26: this.hooks && this.hooks.layoutNode.trigger(node); // Check if the rendered element has a break set if (!(hasRenderedContent && this.shouldBreak(node, start))) { _context.next = 45; break; } this.hooks && this.hooks.layout.trigger(wrapper, this); _imgs = wrapper.querySelectorAll("img"); if (!_imgs.length) { _context.next = 33; break; } _context.next = 33; return this.waitForImages(_imgs); case 33: newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (!newBreakToken) { newBreakToken = this.breakAt(node); } else { this.rebuildTableFromBreakToken(newBreakToken, wrapper); } if (!(newBreakToken && newBreakToken.equals(prevBreakToken))) { _context.next = 43; break; } console.warn("Unable to layout item: ", node); after = newBreakToken.node && (0, _dom.nodeAfter)(newBreakToken.node); if (!after) { _context.next = 42; break; } newBreakToken = new _breaktoken["default"](after); _context.next = 43; break; case 42: return _context.abrupt("return", new _renderresult["default"](undefined, new _renderresult.OverflowContentError("Unable to layout item", [node]))); case 43: length = 0; return _context.abrupt("break", 77); case 45: if (node.dataset && node.dataset.page) { named = node.dataset.page; page = this.element.closest(".pagedjs_page"); page.classList.add("pagedjs_named_page"); page.classList.add("pagedjs_" + named + "_page"); if (!node.dataset.splitFrom) { page.classList.add("pagedjs_" + named + "_first_page"); } } // Should the Node be a shallow or deep clone shallow = (0, _dom.isContainer)(node); rendered = this.append(node, wrapper, breakToken, shallow); length += rendered.textContent.length; // Check if layout has content yet if (!hasRenderedContent) { hasRenderedContent = (0, _dom.hasContent)(node); } // Skip to the next node if a deep clone was rendered if (!shallow) { walker = (0, _dom.walk)((0, _dom.nodeAfter)(node, source), source); } if (!this.forceRenderBreak) { _context.next = 58; break; } this.hooks && this.hooks.layout.trigger(wrapper, this); newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (!newBreakToken) { newBreakToken = this.breakAt(node); } else { this.rebuildTableFromBreakToken(newBreakToken, wrapper); } length = 0; this.forceRenderBreak = false; return _context.abrupt("break", 77); case 58: if (!(length >= this.maxChars)) { _context.next = 75; break; } this.hooks && this.hooks.layout.trigger(wrapper, this); _imgs2 = wrapper.querySelectorAll("img"); if (!_imgs2.length) { _context.next = 64; break; } _context.next = 64; return this.waitForImages(_imgs2); case 64: newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (newBreakToken) { length = 0; this.rebuildTableFromBreakToken(newBreakToken, wrapper); } if (!(newBreakToken && newBreakToken.equals(prevBreakToken))) { _context.next = 75; break; } console.warn("Unable to layout item: ", node); _after = newBreakToken.node && (0, _dom.nodeAfter)(newBreakToken.node); if (!_after) { _context.next = 73; break; } newBreakToken = new _breaktoken["default"](_after); _context.next = 75; break; case 73: this.hooks && this.hooks.beforeRenderResult.trigger(undefined, wrapper, this); return _context.abrupt("return", new _renderresult["default"](undefined, new _renderresult.OverflowContentError("Unable to layout item", [node]))); case 75: _context.next = 7; break; case 77: this.hooks && this.hooks.beforeRenderResult.trigger(newBreakToken, wrapper, this); return _context.abrupt("return", new _renderresult["default"](newBreakToken)); case 79: case "end": return _context.stop(); } }, _callee, this); })); function renderTo(_x, _x2, _x3) { return _renderTo.apply(this, arguments); } return renderTo; }() }, { key: "breakAt", value: function breakAt(node) { var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var newBreakToken = new _breaktoken["default"](node, offset); var breakHooks = this.hooks.onBreakToken.triggerSync(newBreakToken, undefined, node, this); breakHooks.forEach(function (newToken) { if (typeof newToken != "undefined") { newBreakToken = newToken; } }); return newBreakToken; } }, { key: "shouldBreak", value: function shouldBreak(node, limiter) { var previousNode = (0, _dom.nodeBefore)(node, limiter); var parentNode = node.parentNode; var parentBreakBefore = (0, _dom.needsBreakBefore)(node) && parentNode && !previousNode && (0, _dom.needsBreakBefore)(parentNode); var doubleBreakBefore; if (parentBreakBefore) { doubleBreakBefore = node.dataset.breakBefore === parentNode.dataset.breakBefore; } return !doubleBreakBefore && (0, _dom.needsBreakBefore)(node) || (0, _dom.needsPreviousBreakAfter)(node) || (0, _dom.needsPageBreak)(node, previousNode); } }, { key: "forceBreak", value: function forceBreak() { this.forceRenderBreak = true; } }, { key: "getStart", value: function getStart(source, breakToken) { var start; var node = breakToken && breakToken.node; if (node) { start = node; } else { start = source.firstChild; } return start; } }, { key: "append", value: function append(node, dest, breakToken) { var shallow = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; var rebuild = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; var clone = (0, _dom.cloneNode)(node, !shallow); if (node.parentNode && (0, _dom.isElement)(node.parentNode)) { var parent = (0, _dom.findElement)(node.parentNode, dest); // Rebuild chain if (parent) { parent.appendChild(clone); } else if (rebuild) { var fragment = (0, _dom.rebuildAncestors)(node); parent = (0, _dom.findElement)(node.parentNode, fragment); if (!parent) { dest.appendChild(clone); } else if (breakToken && (0, _dom.isText)(breakToken.node) && breakToken.offset > 0) { clone.textContent = clone.textContent.substring(breakToken.offset); parent.appendChild(clone); } else { parent.appendChild(clone); } dest.appendChild(fragment); } else { dest.appendChild(clone); } } else { dest.appendChild(clone); } if (clone.dataset && clone.dataset.ref) { if (!dest.indexOfRefs) { dest.indexOfRefs = {}; } dest.indexOfRefs[clone.dataset.ref] = clone; } var nodeHooks = this.hooks.renderNode.triggerSync(clone, node, this); nodeHooks.forEach(function (newNode) { if (typeof newNode != "undefined") { clone = newNode; } }); return clone; } }, { key: "rebuildTableFromBreakToken", value: function rebuildTableFromBreakToken(breakToken, dest) { if (!breakToken || !breakToken.node) { return; } var node = breakToken.node; var td = (0, _dom.isElement)(node) ? node.closest("td") : node.parentElement.closest("td"); if (td) { var rendered = (0, _dom.findElement)(td, dest, true); if (!rendered) { return; } while (td = td.nextElementSibling) { this.append(td, dest, null, true); } } } }, { key: "waitForImages", value: function () { var _waitForImages = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(imgs) { var _this = this; var results; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: results = Array.from(imgs).map( /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(img) { return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: return _context2.abrupt("return", _this.awaitImageLoaded(img)); case 1: case "end": return _context2.stop(); } }, _callee2); })); return function (_x5) { return _ref.apply(this, arguments); }; }()); _context3.next = 3; return Promise.all(results); case 3: case "end": return _context3.stop(); } }, _callee3); })); function waitForImages(_x4) { return _waitForImages.apply(this, arguments); } return waitForImages; }() }, { key: "awaitImageLoaded", value: function () { var _awaitImageLoaded = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(image) { return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) switch (_context4.prev = _context4.next) { case 0: return _context4.abrupt("return", new Promise(function (resolve) { if (image.complete !== true) { image.onload = function () { var _window$getComputedSt = window.getComputedStyle(image), width = _window$getComputedSt.width, height = _window$getComputedSt.height; resolve(width, height); }; image.onerror = function (e) { var _window$getComputedSt2 = window.getComputedStyle(image), width = _window$getComputedSt2.width, height = _window$getComputedSt2.height; resolve(width, height, e); }; } else { var _window$getComputedSt3 = window.getComputedStyle(image), width = _window$getComputedSt3.width, height = _window$getComputedSt3.height; resolve(width, height); } })); case 1: case "end": return _context4.stop(); } }, _callee4); })); function awaitImageLoaded(_x6) { return _awaitImageLoaded.apply(this, arguments); } return awaitImageLoaded; }() }, { key: "avoidBreakInside", value: function avoidBreakInside(node, limiter) { var breakNode; if (node === limiter) { return; } while (node.parentNode) { node = node.parentNode; if (node === limiter) { break; } if (window.getComputedStyle(node)["break-inside"] === "avoid") { breakNode = node; break; } } return breakNode; } }, { key: "createBreakToken", value: function createBreakToken(overflow, rendered, source) { var container = overflow.startContainer; var offset = overflow.startOffset; var node, renderedNode, parent, index, temp; if ((0, _dom.isElement)(container)) { temp = (0, _dom.child)(container, offset); if ((0, _dom.isElement)(temp)) { renderedNode = (0, _dom.findElement)(temp, rendered); if (!renderedNode) { // Find closest element with data-ref var prevNode = (0, _dom.prevValidNode)(temp); if (!(0, _dom.isElement)(prevNode)) { prevNode = prevNode.parentElement; } renderedNode = (0, _dom.findElement)(prevNode, rendered); // Check if temp is the last rendered node at its level. if (!temp.nextSibling) { // We need to ensure that the previous sibling of temp is fully rendered. var renderedNodeFromSource = (0, _dom.findElement)(renderedNode, source); var walker = document.createTreeWalker(renderedNodeFromSource, NodeFilter.SHOW_ELEMENT); var lastChildOfRenderedNodeFromSource = walker.lastChild(); var lastChildOfRenderedNodeMatchingFromRendered = (0, _dom.findElement)(lastChildOfRenderedNodeFromSource, rendered); // Check if we found that the last child in source if (!lastChildOfRenderedNodeMatchingFromRendered) { // Pending content to be rendered before virtual break token return; } // Otherwise we will return a break token as per below } // renderedNode is actually the last unbroken box that does not overflow. // Break Token is therefore the next sibling of renderedNode within source node. node = (0, _dom.findElement)(renderedNode, source).nextSibling; offset = 0; } else { node = (0, _dom.findElement)(renderedNode, source); offset = 0; } } else { renderedNode = (0, _dom.findElement)(container, rendered); if (!renderedNode) { renderedNode = (0, _dom.findElement)((0, _dom.prevValidNode)(container), rendered); } parent = (0, _dom.findElement)(renderedNode, source); index = (0, _dom.indexOfTextNode)(temp, parent); // No seperatation for the first textNode of an element if (index === 0) { node = parent; offset = 0; } else { node = (0, _dom.child)(parent, index); offset = 0; } } } else { renderedNode = (0, _dom.findElement)(container.parentNode, rendered); if (!renderedNode) { renderedNode = (0, _dom.findElement)((0, _dom.prevValidNode)(container.parentNode), rendered); } parent = (0, _dom.findElement)(renderedNode, source); index = (0, _dom.indexOfTextNode)(container, parent); if (index === -1) { return; } node = (0, _dom.child)(parent, index); offset += node.textContent.indexOf(container.textContent); } if (!node) { return; } return new _breaktoken["default"](node, offset); } }, { key: "findBreakToken", value: function findBreakToken(rendered, source) { var bounds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.bounds; var prevBreakToken = arguments.length > 3 ? arguments[3] : undefined; var extract = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; var overflow = this.findOverflow(rendered, bounds); var breakToken, breakLetter; var overflowHooks = this.hooks.onOverflow.triggerSync(overflow, rendered, bounds, this); overflowHooks.forEach(function (newOverflow) { if (typeof newOverflow != "undefined") { overflow = newOverflow; } }); if (overflow) { breakToken = this.createBreakToken(overflow, rendered, source); // breakToken is nullable var breakHooks = this.hooks.onBreakToken.triggerSync(breakToken, overflow, rendered, this); breakHooks.forEach(function (newToken) { if (typeof newToken != "undefined") { breakToken = newToken; } }); // Stop removal if we are in a loop if (breakToken && breakToken.equals(prevBreakToken)) { return breakToken; } if (breakToken && breakToken["node"] && breakToken["offset"] && breakToken["node"].textContent) { breakLetter = breakToken["node"].textContent.charAt(breakToken["offset"]); } else { breakLetter = undefined; } if (breakToken && breakToken.node && extract) { var removed = this.removeOverflow(overflow, breakLetter); this.hooks && this.hooks.afterOverflowRemoved.trigger(removed, rendered, this); } } return breakToken; } }, { key: "hasOverflow", value: function hasOverflow(element) { var bounds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bounds; var constrainingElement = element && element.parentNode; // this gets the element, instead of the wrapper for the width workaround var _element$getBoundingC = element.getBoundingClientRect(), width = _element$getBoundingC.width, height = _element$getBoundingC.height; var scrollWidth = constrainingElement ? constrainingElement.scrollWidth : 0; var scrollHeight = constrainingElement ? constrainingElement.scrollHeight : 0; return Math.max(Math.floor(width), scrollWidth) > Math.round(bounds.width) || Math.max(Math.floor(height), scrollHeight) > Math.round(bounds.height); } }, { key: "findOverflow", value: function findOverflow(rendered) { var bounds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bounds; var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.gap; if (!this.hasOverflow(rendered, bounds)) return; var start = Math.floor(bounds.left); var end = Math.round(bounds.right + gap); var vStart = Math.round(bounds.top); var vEnd = Math.round(bounds.bottom); var range; var walker = (0, _dom.walk)(rendered.firstChild, rendered); // Find Start var next, done, node, offset, skip, breakAvoid, prev, br; while (!done) { next = walker.next(); done = next.done; node = next.value; skip = false; breakAvoid = false; prev = undefined; br = undefined; if (node) { var pos = (0, _utils.getBoundingClientRect)(node); var left = Math.round(pos.left); var right = Math.floor(pos.right); var top = Math.round(pos.top); var bottom = Math.floor(pos.bottom); if (!range && (left >= end || top >= vEnd)) { // Check if it is a float var isFloat = false; // Check if the node is inside a break-inside: avoid table cell var insideTableCell = (0, _dom.parentOf)(node, "TD", rendered); if (insideTableCell && window.getComputedStyle(insideTableCell)["break-inside"] === "avoid") { // breaking inside a table cell produces unexpected result, as a workaround, we forcibly avoid break inside in a cell. // But we take the whole row, not just the cell that is causing the break. prev = insideTableCell.parentElement; } else if ((0, _dom.isElement)(node)) { var styles = window.getComputedStyle(node); isFloat = styles.getPropertyValue("float") !== "none"; skip = styles.getPropertyValue("break-inside") === "avoid"; breakAvoid = node.dataset.breakBefore === "avoid" || node.dataset.previousBreakAfter === "avoid"; prev = breakAvoid && (0, _dom.nodeBefore)(node, rendered); br = node.tagName === "BR" || node.tagName === "WBR"; } var tableRow = void 0; if (node.nodeName === "TR") { tableRow = node; } else { tableRow = (0, _dom.parentOf)(node, "TR", rendered); } if (tableRow) { // honor break-inside="avoid" in parent tbody/thead var container = tableRow.parentElement; if (["TBODY", "THEAD"].includes(container.nodeName)) { var _styles = window.getComputedStyle(container); if (_styles.getPropertyValue("break-inside") === "avoid") prev = container; } // Check if the node is inside a row with a rowspan var table = (0, _dom.parentOf)(tableRow, "TABLE", rendered); var rowspan = table.querySelector("[colspan]"); if (table && rowspan) { var columnCount = 0; for (var _i = 0, _Array$from = Array.from(table.rows[0].cells); _i < _Array$from.length; _i++) { var cell = _Array$from[_i]; columnCount += parseInt(cell.getAttribute("colspan") || "1"); } if (tableRow.cells.length !== columnCount) { var previousRow = tableRow.previousElementSibling; var previousRowColumnCount = void 0; while (previousRow !== null) { previousRowColumnCount = 0; for (var _i2 = 0, _Array$from2 = Array.from(previousRow.cells); _i2 < _Array$from2.length; _i2++) { var _cell = _Array$from2[_i2]; previousRowColumnCount += parseInt(_cell.getAttribute("colspan") || "1"); } if (previousRowColumnCount === columnCount) { break; } previousRow = previousRow.previousElementSibling; } if (previousRowColumnCount === columnCount) { prev = previousRow; } } } } if (prev) { range = document.createRange(); range.selectNode(prev); break; } if (!br && !isFloat && (0, _dom.isElement)(node)) { range = document.createRange(); range.selectNode(node); break; } if ((0, _dom.isText)(node) && node.textContent.trim().length) { range = document.createRange(); range.selectNode(node); break; } } if (!range && (0, _dom.isText)(node) && node.textContent.trim().length && !(0, _dom.breakInsideAvoidParentNode)(node.parentNode)) { var rects = (0, _utils.getClientRects)(node); var rect = void 0; left = 0; top = 0; for (var i = 0; i != rects.length; i++) { rect = rects[i]; if (rect.width > 0 && (!left || rect.left > left)) { left = rect.left; } if (rect.height > 0 && (!top || rect.top > top)) { top = rect.top; } } if (left >= end || top >= vEnd) { range = document.createRange(); offset = this.textBreak(node, start, end, vStart, vEnd); if (!offset) { range = undefined; } else { range.setStart(node, offset); } break; } } // Skip children if (skip || right <= end && bottom <= vEnd) { next = (0, _dom.nodeAfter)(node, rendered); if (next) { walker = (0, _dom.walk)(next, rendered); } } } } // Find End if (range) { range.setEndAfter(rendered.lastChild); return range; } } }, { key: "findEndToken", value: function findEndToken(rendered, source) { if (rendered.childNodes.length === 0) { return; } var lastChild = rendered.lastChild; var lastNodeIndex; while (lastChild && lastChild.lastChild) { if (!(0, _dom.validNode)(lastChild)) { // Only get elements with refs lastChild = lastChild.previousSibling; } else if (!(0, _dom.validNode)(lastChild.lastChild)) { // Deal with invalid dom items lastChild = (0, _dom.prevValidNode)(lastChild.lastChild); break; } else { lastChild = lastChild.lastChild; } } if ((0, _dom.isText)(lastChild)) { if (lastChild.parentNode.dataset.ref) { lastNodeIndex = (0, _dom.indexOf)(lastChild); lastChild = lastChild.parentNode; } else { lastChild = lastChild.previousSibling; } } var original = (0, _dom.findElement)(lastChild, source); if (lastNodeIndex) { original = original.childNodes[lastNodeIndex]; } var after = (0, _dom.nodeAfter)(original); return this.breakAt(after); } }, { key: "textBreak", value: function textBreak(node, start, end, vStart, vEnd) { var wordwalker = (0, _dom.words)(node); var left = 0; var right = 0; var top = 0; var bottom = 0; var word, next, done, pos; var offset; while (!done) { next = wordwalker.next(); word = next.value; done = next.done; if (!word) { break; } pos = (0, _utils.getBoundingClientRect)(word); left = Math.floor(pos.left); right = Math.floor(pos.right); top = Math.floor(pos.top); bottom = Math.floor(pos.bottom); if (left >= end || top >= vEnd) { offset = word.startOffset; break; } if (right > end || bottom > vEnd) { var letterwalker = (0, _dom.letters)(word); var letter = void 0, nextLetter = void 0, doneLetter = void 0; while (!doneLetter) { nextLetter = letterwalker.next(); letter = nextLetter.value; doneLetter = nextLetter.done; if (!letter) { break; } pos = (0, _utils.getBoundingClientRect)(letter); left = Math.floor(pos.left); top = Math.floor(pos.top); if (left >= end || top >= vEnd) { offset = letter.startOffset; done = true; break; } } } } return offset; } }, { key: "removeOverflow", value: function removeOverflow(overflow, breakLetter) { var startContainer = overflow.startContainer; var extracted = overflow.extractContents(); this.hyphenateAtBreak(startContainer, breakLetter); return extracted; } }, { key: "hyphenateAtBreak", value: function hyphenateAtBreak(startContainer, breakLetter) { if ((0, _dom.isText)(startContainer)) { var startText = startContainer.textContent; var prevLetter = startText[startText.length - 1]; // Add a hyphen if previous character is a letter or soft hyphen if (breakLetter && /^\w|\u00AD$/.test(prevLetter) && /^\w|\u00AD$/.test(breakLetter) || !breakLetter && /^\w|\u00AD$/.test(prevLetter)) { startContainer.parentNode.classList.add("pagedjs_hyphen"); startContainer.textContent += this.settings.hyphenGlyph || "\u2011"; } } } }, { key: "equalTokens", value: function equalTokens(a, b) { if (!a || !b) { return false; } if (a["node"] && b["node"] && a["node"] !== b["node"]) { return false; } if (a["offset"] && b["offset"] && a["offset"] !== b["offset"]) { return false; } return true; } }]); return Layout; }(); (0, _eventEmitter["default"])(Layout.prototype); var _default = Layout; exports["default"] = _default;