...
without any \n, the problem disappear
31 | // I think this handler can fix most of cases
32 | // Obviously, we cannot suppress all the \n in the HTML document
33 | // because carriage returns are important in
elements.
34 | // Tested with Chrome 76.0.3809.100/Windows
35 | Paged.registerHandlers(class extends Paged.Handler {
36 | constructor(chunker, polisher, caller) {
37 | super(chunker, polisher, caller);
38 | this.carriageReturn = String.fromCharCode(10);
39 | }
40 |
41 | checkNode(node) {
42 | if (!node) return;
43 | if (node.nodeType !== 3) return;
44 | if (node.textContent === this.carriageReturn) {
45 | node.remove();
46 | }
47 | }
48 |
49 | afterParsed(parsed) {
50 | let template = document.querySelector('template').content;
51 | const breakAfterAvoidElements = template.querySelectorAll('[data-break-after="avoid"], [data-break-before="avoid"]');
52 | for (let el of breakAfterAvoidElements) {
53 | this.checkNode(el.previousSibling);
54 | this.checkNode(el.nextSibling);
55 | }
56 | }
57 | });
58 |
59 | // This hook creates a list of abbreviations
60 | // Note: we also could implement this feature using a Pandoc filter
61 | Paged.registerHandlers(class extends Paged.Handler {
62 | constructor(chunker, polisher, caller) {
63 | super(chunker, polisher, caller);
64 | }
65 | beforeParsed(content) {
66 | // Find the abbreviation nodes
67 | const abbrNodeList = content.querySelectorAll('abbr');
68 |
69 | // Return early if there is no abbreviation
70 | if (abbrNodeList.length === 0) return;
71 |
72 | // Store unique values of abbreviations, see https://github.com/rstudio/pagedown/issues/218
73 | let abbreviations = [];
74 | for (const {title, innerHTML} of abbrNodeList.values()) {
75 | if (abbreviations.find(el => el.title === title && el.innerHTML === innerHTML)) {
76 | continue;
77 | }
78 | abbreviations.push({title: title, innerHTML: innerHTML});
79 | }
80 |
81 | const loaTitle = pandocMeta['loa-title'] ? pandocMetaToString(pandocMeta['loa-title']) : 'List of Abbreviations';
82 | const loaId = 'LOA';
83 | const tocList = content.querySelector('.toc ul');
84 | let listOfAbbreviations = document.createElement('div');
85 | let descriptionList = document.createElement('dl');
86 | content.appendChild(listOfAbbreviations);
87 | listOfAbbreviations.id = loaId;
88 | listOfAbbreviations.classList.add('section', 'front-matter', 'level1', 'loa');
89 | listOfAbbreviations.innerHTML = '' + loaTitle + '
';
90 | listOfAbbreviations.appendChild(descriptionList);
91 | for(let abbr of abbreviations) {
92 | if(!abbr.title) continue;
93 | let term = document.createElement('dt');
94 | let definition = document.createElement('dd');
95 | descriptionList.appendChild(term);
96 | descriptionList.appendChild(definition);
97 | term.innerHTML = abbr.innerHTML;
98 | definition.innerText = abbr.title;
99 | }
100 | if (tocList) {
101 | const loaTOCItem = document.createElement('li');
102 | loaTOCItem.innerHTML = '' + loaTitle + '';
103 | tocList.appendChild(loaTOCItem);
104 | }
105 | }
106 | });
107 |
108 | // This hook moves the sections of class front-matter in the div.front-matter-container
109 | Paged.registerHandlers(class extends Paged.Handler {
110 | constructor(chunker, polisher, caller) {
111 | super(chunker, polisher, caller);
112 | }
113 |
114 | beforeParsed(content) {
115 | const frontMatter = content.querySelector('.front-matter-container');
116 | if (!frontMatter) return;
117 |
118 | // move front matter sections in the front matter container
119 | const frontMatterSections = content.querySelectorAll('.level1.front-matter');
120 | for (const section of frontMatterSections) {
121 | frontMatter.appendChild(section);
122 | }
123 |
124 | // add the class front-matter-ref to any element
125 | // referring to an entry in the front matter
126 | const anchors = content.querySelectorAll('a[href^="#"]:not([href*=":"])');
127 | for (const a of anchors) {
128 | const ref = a.getAttribute('href').replace(/^#/, '');
129 | const element = content.getElementById(ref);
130 | if (frontMatter.contains(element)) a.classList.add('front-matter-ref');
131 | }
132 |
133 | // update the toc, lof and lot for front matter sections
134 | const frontMatterSectionsLinks = content.querySelectorAll('.toc .front-matter-ref, .lof .front-matter-ref, .lot .front-matter-ref');
135 | for (let i = frontMatterSectionsLinks.length - 1; i >= 0; i--) {
136 | const listItem = frontMatterSectionsLinks[i].parentNode;
137 | const list = listItem.parentNode;
138 | list.insertBefore(listItem, list.firstChild);
139 | }
140 | }
141 | });
142 |
143 | // This hook expands the links in the lists of figures and tables
144 | Paged.registerHandlers(class extends Paged.Handler {
145 | constructor(chunker, polisher, caller) {
146 | super(chunker, polisher, caller);
147 | }
148 |
149 | beforeParsed(content) {
150 | const items = content.querySelectorAll('.lof li, .lot li');
151 | for (const item of items) {
152 | const anchor = item.firstChild;
153 | anchor.innerText = item.innerText;
154 | item.innerText = '';
155 | item.append(anchor);
156 | }
157 | }
158 | });
159 |
160 | // This hook adds spans for leading symbols
161 | Paged.registerHandlers(class extends Paged.Handler {
162 | constructor(chunker, polisher, caller) {
163 | super(chunker, polisher, caller);
164 | }
165 |
166 | beforeParsed(content) {
167 | const anchors = content.querySelectorAll('.toc a, .lof a, .lot a');
168 | for (const a of anchors) {
169 | a.innerHTML = a.innerHTML + '';
170 | }
171 | }
172 | });
173 |
174 | // This hook appends short titles spans
175 | Paged.registerHandlers(class extends Paged.Handler {
176 | constructor(chunker, polisher, caller) {
177 | super(chunker, polisher, caller);
178 | }
179 |
180 | beforeParsed(content) {
181 | /* A factory returning a function that appends short titles spans.
182 | The text content of these spans are reused for running titles (see default.css).
183 | Argument: level - An integer between 1 and 6.
184 | */
185 | function appendShortTitleSpans(level) {
186 | return () => {
187 | const divs = Array.from(content.querySelectorAll('.level' + level));
188 |
189 | function addSpan(div) {
190 | const mainHeader = div.getElementsByTagName('h' + level)[0];
191 | if (!mainHeader) return;
192 | const mainTitle = mainHeader.textContent;
193 | const spanSectionNumber = mainHeader.getElementsByClassName('header-section-number')[0];
194 | const mainNumber = !!spanSectionNumber ? spanSectionNumber.textContent : '';
195 | const runningTitle = 'shortTitle' in div.dataset ? mainNumber + ' ' + div.dataset.shortTitle : mainTitle;
196 | const span = document.createElement('span');
197 | span.className = 'shorttitle' + level;
198 | span.innerText = runningTitle;
199 | span.style.display = "none";
200 | mainHeader.appendChild(span);
201 | if (level == 1 && div.querySelector('.level2') === null) {
202 | let span2 = document.createElement('span');
203 | span2.className = 'shorttitle2';
204 | span2.innerText = ' ';
205 | span2.style.display = "none";
206 | span.insertAdjacentElement('afterend', span2);
207 | }
208 | }
209 |
210 | for (const div of divs) {
211 | addSpan(div);
212 | }
213 | };
214 | }
215 |
216 | appendShortTitleSpans(1)();
217 | appendShortTitleSpans(2)();
218 | }
219 | });
220 |
221 | // Footnotes support
222 | Paged.registerHandlers(class extends Paged.Handler {
223 | constructor(chunker, polisher, caller) {
224 | super(chunker, polisher, caller);
225 |
226 | this.splittedParagraphRefs = [];
227 | }
228 |
229 | beforeParsed(content) {
230 | // remove footnotes in toc, lof, lot
231 | // see https://github.com/rstudio/pagedown/issues/54
232 | let removeThese = content.querySelectorAll('.toc .footnote, .lof .footnote, .lot .footnote');
233 | for (const el of removeThese) {
234 | el.remove();
235 | }
236 |
237 | let footnotes = content.querySelectorAll('.footnote');
238 |
239 | for (let footnote of footnotes) {
240 | let parentElement = footnote.parentElement;
241 | let footnoteCall = document.createElement('a');
242 | let footnoteNumber = footnote.dataset.pagedownFootnoteNumber;
243 |
244 | footnoteCall.className = 'footnote-ref'; // same class as Pandoc
245 | footnoteCall.setAttribute('id', 'fnref' + footnoteNumber); // same notation as Pandoc
246 | footnoteCall.setAttribute('href', '#' + footnote.id);
247 | footnoteCall.innerHTML = '' + footnoteNumber +'';
248 | parentElement.insertBefore(footnoteCall, footnote);
249 |
250 | // Here comes a hack. Fortunately, it works with Chrome and FF.
251 | let handler = document.createElement('p');
252 | handler.className = 'footnoteHandler';
253 | parentElement.insertBefore(handler, footnote);
254 | handler.appendChild(footnote);
255 | handler.style.display = 'inline-block';
256 | handler.style.width = '100%';
257 | handler.style.float = 'right';
258 | handler.style.pageBreakInside = 'avoid';
259 | }
260 | }
261 |
262 | afterPageLayout(pageFragment, page, breakToken) {
263 | function hasItemParent(node) {
264 | if (node.parentElement === null) {
265 | return false;
266 | } else {
267 | if (node.parentElement.tagName === 'LI') {
268 | return true;
269 | } else {
270 | return hasItemParent(node.parentElement);
271 | }
272 | }
273 | }
274 | // If a li item is broken, we store the reference of the p child element
275 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000
276 | if (breakToken !== undefined) {
277 | if (breakToken.node.nodeName === "#text" && hasItemParent(breakToken.node)) {
278 | this.splittedParagraphRefs.push(breakToken.node.parentElement.dataset.ref);
279 | }
280 | }
281 | }
282 |
283 | afterRendered(pages) {
284 | for (let page of pages) {
285 | const footnotes = page.element.querySelectorAll('.footnote');
286 | if (footnotes.length === 0) {
287 | continue;
288 | }
289 |
290 | const pageContent = page.element.querySelector('.pagedjs_page_content');
291 | let hr = document.createElement('hr');
292 | let footnoteArea = document.createElement('div');
293 |
294 | pageContent.style.display = 'flex';
295 | pageContent.style.flexDirection = 'column';
296 |
297 | hr.className = 'footnote-break';
298 | hr.style.marginTop = 'auto';
299 | hr.style.marginBottom = 0;
300 | hr.style.marginLeft = 0;
301 | hr.style.marginRight = 'auto';
302 | pageContent.appendChild(hr);
303 |
304 | footnoteArea.className = 'footnote-area';
305 | pageContent.appendChild(footnoteArea);
306 |
307 | for (let footnote of footnotes) {
308 | let handler = footnote.parentElement;
309 |
310 | footnoteArea.appendChild(footnote);
311 | handler.parentNode.removeChild(handler);
312 |
313 | footnote.innerHTML = '' + footnote.dataset.pagedownFootnoteNumber + '' + footnote.innerHTML;
314 | footnote.style.fontSize = 'x-small';
315 | footnote.style.marginTop = 0;
316 | footnote.style.marginBottom = 0;
317 | footnote.style.paddingTop = 0;
318 | footnote.style.paddingBottom = 0;
319 | footnote.style.display = 'block';
320 | }
321 | }
322 |
323 | for (let ref of this.splittedParagraphRefs) {
324 | let paragraphFirstPage = document.querySelector('[data-split-to="' + ref + '"]');
325 | // We test whether the paragraph is empty
326 | // see https://github.com/rstudio/pagedown/issues/23#issue-376548000
327 | if (paragraphFirstPage.innerText === "") {
328 | paragraphFirstPage.parentElement.style.display = "none";
329 | let paragraphSecondPage = document.querySelector('[data-split-from="' + ref + '"]');
330 | paragraphSecondPage.parentElement.style.setProperty('list-style', 'inherit', 'important');
331 | }
332 | }
333 | }
334 | });
335 |
336 | // Support for "Chapter " label on section with class `.chapter`
337 | Paged.registerHandlers(class extends Paged.Handler {
338 | constructor(chunker, polisher, caller) {
339 | super(chunker, polisher, caller);
340 |
341 | this.options = pandocMeta['chapter_name'];
342 |
343 | let styles;
344 | if (isString(this.options)) {
345 | this.options = pandocMetaToString(this.options);
346 | styles = `
347 | :root {
348 | --chapter-name-before: "${this.options}";
349 | }
350 | `;
351 | }
352 | if (isArray(this.options)) {
353 | this.options = this.options.map(pandocMetaToString);
354 | styles = `
355 | :root {
356 | --chapter-name-before: "${this.options[0]}";
357 | --chapter-name-after: "${this.options[1]}";
358 | }
359 | `;
360 | }
361 | if (styles) polisher.insert(styles);
362 | }
363 |
364 | beforeParsed(content) {
365 | const tocAnchors = content.querySelectorAll('.toc a[href^="#"]:not([href*=":"]');
366 | for (const anchor of tocAnchors) {
367 | const ref = anchor.getAttribute('href').replace(/^#/, '');
368 | const element = content.getElementById(ref);
369 | if (element.classList.contains('chapter')) {
370 | anchor.classList.add('chapter-ref');
371 | }
372 | }
373 | }
374 | });
375 |
376 | // Main text line numbering,
377 | // see https://github.com/rstudio/pagedown/issues/115
378 | // Original idea: Julien Taquet, thanks!
379 | Paged.registerHandlers(class extends Paged.Handler {
380 | constructor(chunker, polisher, caller) {
381 | super(chunker, polisher, caller);
382 |
383 | // get the number-lines option from Pandoc metavariables
384 | this.options = pandocMeta['number-lines'];
385 | // quit early if the "number-lines" option is false or missing
386 | if (!this.options) return;
387 | // retrieve the selector if provided, otherwise use the default selector
388 | this.selector = this.options.selector ? pandocMetaToString(this.options.selector) : '.level1:not(.front-matter) h1, .level1 h2, .level1 h3, .level1 p';
389 |
390 | const styles = `
391 | :root {
392 | --line-numbers-padding-right: 10px;
393 | --line-numbers-font-size: 8pt;
394 | }
395 | .pagedown-linenumbers-container {
396 | position: absolute;
397 | margin-top: var(--pagedjs-margin-top);
398 | right: calc(var(--pagedjs-width) - var(--pagedjs-margin-left));
399 | }
400 | .maintextlinenumbers {
401 | position: absolute;
402 | right: 0;
403 | text-align: right;
404 | padding-right: var(--line-numbers-padding-right);
405 | font-size: var(--line-numbers-font-size);
406 | }
407 | `;
408 | polisher.insert(styles);
409 |
410 | this.resetLinesCounter();
411 | }
412 |
413 | appendLineNumbersContainer(page) {
414 | const pagebox = page.element.querySelector('.pagedjs_pagebox');
415 | const lineNumbersContainer = document.createElement('div');
416 | lineNumbersContainer.classList.add('pagedown-linenumbers-container');
417 |
418 | return pagebox.appendChild(lineNumbersContainer);
419 | }
420 |
421 | lineHeight(element) {
422 | // If the document stylesheet does not define a value for line-height,
423 | // Blink returns "normal". Therefore, parseInt may return NaN.
424 | return parseInt(getComputedStyle(element).lineHeight);
425 | }
426 |
427 | innerHeight(element) {
428 | let outerHeight = element.getBoundingClientRect().height;
429 | let {borderTopWidth,
430 | borderBottomWidth,
431 | paddingTop,
432 | paddingBottom} = getComputedStyle(element);
433 |
434 | borderTopWidth = parseFloat(borderTopWidth);
435 | borderBottomWidth = parseFloat(borderBottomWidth);
436 | paddingTop = parseFloat(paddingTop);
437 | paddingBottom = parseFloat(paddingBottom);
438 |
439 | return Math.round(outerHeight - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom);
440 | }
441 |
442 | arrayOfInt(from, length) {
443 | // adapted from https://stackoverflow.com/a/50234108/6500804
444 | return Array.from(Array(length).keys(), n => n + from);
445 | }
446 |
447 | incrementLinesCounter(value) {
448 | this.linesCounter = this.linesCounter + value;
449 | }
450 |
451 | resetLinesCounter() {
452 | this.linesCounter = 0;
453 | }
454 |
455 | isDisplayMath(element) {
456 | const nodes = element.childNodes;
457 | if (nodes.length != 1) return false;
458 | return (nodes[0].nodeName === 'SPAN') && (nodes[0].classList.value === 'math display');
459 | }
460 |
461 | afterRendered(pages) {
462 | if (!this.options) return;
463 |
464 | for (let page of pages) {
465 | const lineNumbersContainer = this.appendLineNumbersContainer(page);
466 | const pageAreaY = page.area.getBoundingClientRect().y;
467 | let elementsToNumber = page.area.querySelectorAll(this.selector);
468 |
469 | for (let element of elementsToNumber) {
470 | // Do not add line numbers for display math environment
471 | if (this.isDisplayMath(element)) continue;
472 |
473 | // Try to retrieve line height
474 | const lineHeight = this.lineHeight(element);
475 | // Test against lineHeight method returns NaN
476 | if (!lineHeight) {
477 | console.warn('Failed to compute line height value on "' + page.id + '".');
478 | continue;
479 | }
480 |
481 | const innerHeight = this.innerHeight(element);
482 |
483 | // Number of lines estimation
484 | // There is no built-in method to detect the number of lines in a block.
485 | // The main caveat is that an actual line height can differ from
486 | // the line-height CSS property.
487 | // Mixed fonts, subscripts, superscripts, inline math... can increase
488 | // the actual line height.
489 | // Here, we divide the inner height of the block by the line-height
490 | // computed property and round to the floor to take into account that
491 | // sometimes the actual line height is greater than its property value.
492 | // This is far from perfect and can be easily broken especially by
493 | // inline math.
494 | const nLines = Math.floor(innerHeight / lineHeight);
495 |
496 | // do not add line numbers for void paragraphs
497 | if (nLines <= 0) continue;
498 |
499 | const linenumbers = document.createElement('div');
500 | lineNumbersContainer.appendChild(linenumbers);
501 | linenumbers.classList.add('maintextlinenumbers');
502 |
503 | const elementY = element.getBoundingClientRect().y;
504 | linenumbers.style.top = (elementY - pageAreaY) + 'px';
505 |
506 | const cs = getComputedStyle(element);
507 | const paddingTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth);
508 | linenumbers.style.paddingTop = paddingTop + 'px';
509 |
510 | linenumbers.style.lineHeight = cs.lineHeight;
511 |
512 | linenumbers.innerHTML = this.arrayOfInt(this.linesCounter + 1, nLines)
513 | .reduce((t, v) => t + '
' + v);
514 | this.incrementLinesCounter(nLines);
515 | }
516 |
517 | if (this.options['reset-page']) {
518 | this.resetLinesCounter();
519 | }
520 | }
521 | }
522 | });
523 |
524 | // Clean links to avoid impossible line breaking of long urls in a justified text
525 | // Author: Julien Taquet (Paged.js core team)
526 | // see https://github.com/spyrales/gouvdown/issues/37
527 | Paged.registerHandlers(class extends Paged.Handler {
528 | constructor(chunker, polisher, caller) {
529 | super(chunker, polisher, caller);
530 | }
531 | beforeParsed(content) {
532 | // add wbr to / in links
533 | const links = content.querySelectorAll('a[href^="http"], a[href^="www"]');
534 | links.forEach(link => {
535 | // Rerun to avoid large spaces.
536 | // Break after a colon or a double slash (//)
537 | // or before a single slash (/), a tilde (~), a period, a comma, a hyphen,
538 | // an underline (_), a question mark, a number sign, or a percent symbol.
539 | const content = link.textContent;
540 | if (!(link.childElementCount === 0 && content.match(/^http|^www/))) return;
541 | let printableUrl = content.replace(/\/\//g, "//\u003Cwbr\u003E");
542 | printableUrl = printableUrl.replace(/\,/g, ",\u003Cwbr\u003E");
543 | // put wbr around everything.
544 | printableUrl = printableUrl.replace(
545 | /(\/|\~|\-|\.|\,|\_|\?|\#|\%)/g,
546 | "\u003Cwbr\u003E$1"
547 | );
548 | // turn hyphen in non breaking hyphen
549 | printableUrl = printableUrl.replace(/\-/g, "\u003Cwbr\u003E‑");
550 | link.setAttribute("data-print-url", printableUrl);
551 | link.innerHTML = printableUrl;
552 | });
553 | }
554 | });
555 |
556 | // Repeat table headers on multiple pages
557 | // Authors: Julien Taquet, Lucas Maciuga and Tafael Caixeta, see https://gitlab.coko.foundation/pagedjs/pagedjs/-/issues/84
558 | // TODO: remove this hook when Paged.js integrates this feature
559 | Paged.registerHandlers(class RepeatingTableHeadersHandler extends Paged.Handler {
560 |
561 | constructor(chunker, polisher, caller) {
562 | super(chunker, polisher, caller);
563 | this.splitTablesRefs = [];
564 | }
565 |
566 | afterPageLayout(pageElement, page, breakToken, chunker) {
567 | this.chunker = chunker;
568 | this.splitTablesRefs = [];
569 |
570 | if (breakToken) {
571 | const node = breakToken.node;
572 | const tables = this.findAllAncestors(node, "table");
573 | if (node.tagName === "TABLE") {
574 | tables.push(node);
575 | }
576 |
577 | if (tables.length > 0) {
578 | this.splitTablesRefs = tables.map(t => t.dataset.ref);
579 |
580 | //checks if split inside thead and if so, set breakToken to next sibling element
581 | let thead = node.tagName === "THEAD" ? node : this.findFirstAncestor(node, "thead");
582 | if (thead) {
583 | let lastTheadNode = thead.hasChildNodes() ? thead.lastChild : thead;
584 | breakToken.node = this.nodeAfter(lastTheadNode, chunker.source);
585 | }
586 |
587 | this.hideEmptyTables(pageElement, node);
588 | }
589 | }
590 | }
591 |
592 | hideEmptyTables(pageElement, breakTokenNode) {
593 | this.splitTablesRefs.forEach(ref => {
594 | let table = pageElement.querySelector("[data-ref='" + ref + "']");
595 | if (table) {
596 | let sourceBody = table.querySelector("tbody > tr");
597 | if (!sourceBody || this.refEquals(sourceBody.firstElementChild, breakTokenNode)) {
598 | table.style.visibility = "hidden";
599 | table.style.position = "absolute";
600 | let lineSpacer = table.nextSibling;
601 | if (lineSpacer) {
602 | lineSpacer.style.visibility = "hidden";
603 | lineSpacer.style.position = "absolute";
604 | }
605 | }
606 | }
607 | });
608 | }
609 |
610 | refEquals(a, b) {
611 | return a && a.dataset && b && b.dataset && a.dataset.ref === b.dataset.ref;
612 | }
613 |
614 | findFirstAncestor(element, selector) {
615 | while (element.parentNode && element.parentNode.nodeType === 1) {
616 | if (element.parentNode.matches(selector)) {
617 | return element.parentNode;
618 | }
619 | element = element.parentNode;
620 | }
621 | return null;
622 | }
623 |
624 | findAllAncestors(element, selector) {
625 | const ancestors = [];
626 | while (element.parentNode && element.parentNode.nodeType === 1) {
627 | if (element.parentNode.matches(selector)) {
628 | ancestors.unshift(element.parentNode);
629 | }
630 | element = element.parentNode;
631 | }
632 | return ancestors;
633 | }
634 |
635 | // The addition of repeating Table Headers is done here because this hook is triggered before overflow handling
636 | layout(rendered, layout) {
637 | this.splitTablesRefs.forEach(ref => {
638 | const renderedTable = rendered.querySelector("[data-ref='" + ref + "']");
639 | if (renderedTable && renderedTable.hasAttribute("data-split-from")) {
640 | // this event can be triggered multiple times
641 | // added a flag repeated-headers to control when table headers already repeated in current page.
642 | if (!renderedTable.getAttribute("repeated-headers")) {
643 | const sourceTable = this.chunker.source.querySelector("[data-ref='" + ref + "']");
644 | this.repeatColgroup(sourceTable, renderedTable);
645 | this.repeatTHead(sourceTable, renderedTable);
646 | renderedTable.setAttribute("repeated-headers", true);
647 | }
648 | }
649 | });
650 | }
651 |
652 | repeatColgroup(sourceTable, renderedTable) {
653 | let colgroup = sourceTable.querySelectorAll("colgroup");
654 | let firstChild = renderedTable.firstChild;
655 | colgroup.forEach((colgroup) => {
656 | let clonedColgroup = colgroup.cloneNode(true);
657 | renderedTable.insertBefore(clonedColgroup, firstChild);
658 | });
659 | }
660 |
661 | repeatTHead(sourceTable, renderedTable) {
662 | let thead = sourceTable.querySelector("thead");
663 | if (thead) {
664 | let clonedThead = thead.cloneNode(true);
665 | renderedTable.insertBefore(clonedThead, renderedTable.firstChild);
666 | }
667 | }
668 |
669 | // the functions below are from pagedjs utils/dom.js
670 | nodeAfter(node, limiter) {
671 | if (limiter && node === limiter) {
672 | return;
673 | }
674 | let significantNode = this.nextSignificantNode(node);
675 | if (significantNode) {
676 | return significantNode;
677 | }
678 | if (node.parentNode) {
679 | while ((node = node.parentNode)) {
680 | if (limiter && node === limiter) {
681 | return;
682 | }
683 | significantNode = this.nextSignificantNode(node);
684 | if (significantNode) {
685 | return significantNode;
686 | }
687 | }
688 | }
689 | }
690 |
691 | nextSignificantNode(sib) {
692 | while ((sib = sib.nextSibling)) {
693 | if (!this.isIgnorable(sib)) return sib;
694 | }
695 | return null;
696 | }
697 |
698 | isIgnorable(node) {
699 | return (node.nodeType === 8) || // A comment node
700 | ((node.nodeType === 3) && this.isAllWhitespace(node)); // a text node, all whitespace
701 | }
702 |
703 | isAllWhitespace(node) {
704 | return !(/[^\t\n\r ]/.test(node.textContent));
705 | }
706 | });
707 |
708 | }
709 |
--------------------------------------------------------------------------------
/vignettes/figures/app_screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RConsortium/submissions-pilot2/c90937d8527ac9a36a46bad76f056f3880a4249f/vignettes/figures/app_screenshot1.png
--------------------------------------------------------------------------------
/vignettes/figures/app_screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RConsortium/submissions-pilot2/c90937d8527ac9a36a46bad76f056f3880a4249f/vignettes/figures/app_screenshot2.png
--------------------------------------------------------------------------------
/vignettes/figures/app_screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RConsortium/submissions-pilot2/c90937d8527ac9a36a46bad76f056f3880a4249f/vignettes/figures/app_screenshot3.png
--------------------------------------------------------------------------------
/vignettes/figures/app_screenshot4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RConsortium/submissions-pilot2/c90937d8527ac9a36a46bad76f056f3880a4249f/vignettes/figures/app_screenshot4.png
--------------------------------------------------------------------------------
/vignettes/figures/data_dependencies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RConsortium/submissions-pilot2/c90937d8527ac9a36a46bad76f056f3880a4249f/vignettes/figures/data_dependencies.png
--------------------------------------------------------------------------------
/vignettes/figures/study_design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RConsortium/submissions-pilot2/c90937d8527ac9a36a46bad76f056f3880a4249f/vignettes/figures/study_design.png
--------------------------------------------------------------------------------
/vignettes/letter_custom.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Palatino, "Palatino Linotype", "Palatino LT STD", Georgia, 'Source Han Serif', 'Songti SC', serif;
3 | line-height: 1.5em;
4 | }
5 |
6 | .title-page {
7 | display: none;
8 | }
9 |
10 | .from, .date {
11 | text-align: right;
12 | }
13 | .from p {
14 | text-align: left;
15 | display: inline-block;
16 | }
17 |
18 | .logo {
19 | position: running(header-logo);
20 | height: 1cm;
21 | }
22 |
23 | .date {
24 | margin-top: 4em;
25 | }
26 |
27 | @page {
28 | size: letter;
29 | margin: 4cm 3cm;
30 |
31 | @top-left {
32 | content: element(header-logo);
33 | }
34 | @bottom-right {
35 | content: counter(page);
36 | }
37 | }
38 |
39 | @media screen and (min-width: 12.32in) {
40 | .pagedjs_page, .pagedjs_first_page {
41 | margin: auto auto 5mm auto;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/vignettes/rconsortium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RConsortium/submissions-pilot2/c90937d8527ac9a36a46bad76f056f3880a4249f/vignettes/rconsortium.png
--------------------------------------------------------------------------------