All files / report PDFFormatter.js

100% Statements 42/42
100% Branches 10/10
100% Functions 13/13
100% Lines 42/42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 894x 4x       4x 4x       4x 11x 11x 3x           1x 1x 1x 1x       17x       21x 21x       2x 2x       3x       3x 2x 2x 2x 2x 2x   1x         5x 5x       2x 2x 6x 6x       6x 2x 2x 4x 2x 2x           2x 2x 2x 2x 2x          
const PDF_HEIGHT = 1404; // 11.7 in to px at 120 dpi
const PAGE_MARGIN = 84; // 0.7 in to px at 120 dpi
 
class PDFFormatter {
  constructor(page) {
    this.currentPageHeight = 0;
    this.modules = page.children;
  }
 
  formatPage() {
    Array.prototype.forEach.call(this.modules, (module) => {
      this.addToCurrentPage(module);
      if (this.needsPageBreak()) {
        this.addPageBreak(module);
      }
    });
  }
 
  static formatWrapper(wrapper) {
    wrapper.style.setProperty('border', '1px solid white');
    wrapper.style.setProperty('height', '99%');
    wrapper.style.setProperty('page-break-after', 'avoid');
    wrapper.style.setProperty('page-break-before', 'avoid');
  }
 
  needsPageBreak() {
    return this.currentPageHeight >= (PDF_HEIGHT - PAGE_MARGIN);
  }
 
  addToCurrentPage(element) {
    this.currentPageHeight += element.clientHeight;
    this.currentPageHeight += parseInt(window.getComputedStyle(element).marginTop, 10);
  }
 
  removeFromCurrentPage(element) {
    this.currentPageHeight -= element.clientHeight;
    this.currentPageHeight -= parseInt(window.getComputedStyle(element).marginTop, 10);
  }
 
  static canBeBrokenDownIntoMultiplePages (element) {
    return element.getElementsByTagName('ol').length > 0;
  }
 
  addPageBreak(element) {
    if (PDFFormatter.canBeBrokenDownIntoMultiplePages(element)) {
      this.removeFromCurrentPage(element);
      const [title, content] = element.children;
      const [list] = content.children;
      const listItems = list.getElementsByTagName('li');
      this.breakTableIntoPages(listItems, title);
    } else {
      this.addNewPage(element);
    }
  }
 
  addNewPage(element) {
    element.style.setProperty('page-break-before', 'always');
    this.currentPageHeight = element.clientHeight;
  }
 
  breakTableIntoPages(listItems, title) {
    this.addToCurrentPage(title);
    Array.prototype.forEach.call(listItems, (li, index) => {
      this.addToCurrentPage(li);
      const needsPageBreak = this.needsPageBreak();
 
      // We don't want to send the first element to a new page
      // if that is needed we should break before the title.
      if (needsPageBreak && index === 0) {
        this.addNewPage(title);
        this.addToCurrentPage(li);
      } else if (needsPageBreak) {
        this.addNewPage(li);
        PDFFormatter.addBorder(li);
      }
    });
  }
 
  static addBorder(element) {
    const color = getComputedStyle(element).getPropertyValue('border-bottom-color');
    element.style.setProperty('border-top-color', color);
    element.style.setProperty('border-top-width', '1px');
    element.style.setProperty('border-top-style', 'dotted');
    element.style.setProperty('margin-top', '2.8rem');
  }
}
 
export default PDFFormatter;