11import Worker from '../worker.js' ;
2+ import { objType , createElement } from './utils.js' ;
23
34// Add page-break functionality.
45
@@ -7,17 +8,107 @@ var orig = {
78 toContainer : Worker . prototype . toContainer
89} ;
910
11+ // Add pageBreak default options to the Worker template.
12+ Worker . template . opt . pageBreak = {
13+ mode : [ 'css' , 'legacy' ] , // 'avoid-all', 'css', 'legacy', 'whiteline'
14+ before : [ ] ,
15+ after : [ ] ,
16+ avoid : [ ]
17+ } ;
18+
1019Worker . prototype . toContainer = function toContainer ( ) {
1120 return orig . toContainer . call ( this ) . then ( function toContainer_pagebreak ( ) {
12- // Find all page-break elements and setup page height.
13- var pageBreaks = this . prop . container . querySelectorAll ( '.html2pdf__page-break' ) ;
21+ // Setup root element and inner page height.
22+ var root = this . prop . container ;
1423 var pxPageHeight = this . prop . pageSize . inner . px . height ;
1524
16- // Set each page-break element to a block with the appropriate height.
17- Array . prototype . forEach . call ( pageBreaks , function pageBreak_loop ( el ) {
18- el . style . display = 'block' ;
25+ // Check all requested modes.
26+ var modeSrc = [ ] . concat ( this . opt . pageBreak . mode ) ;
27+ var mode = {
28+ avoidAll : modeSrc . indexOf ( 'avoid-all' ) !== - 1 ,
29+ css : modeSrc . indexOf ( 'css' ) !== - 1 ,
30+ legacy : modeSrc . indexOf ( 'legacy' ) !== - 1 ,
31+ whiteline : modeSrc . indexOf ( 'whiteline' ) !== - 1
32+ } ;
33+
34+ // Get arrays of all explicitly requested elements.
35+ var select = { } ;
36+ [ 'before' , 'after' , 'avoid' ] . forEach ( function ( key ) {
37+ var all = mode . avoidAll && key === 'avoid' ;
38+ select [ key ] = all ? [ ] : [ ] . concat ( this . opt . pageBreak [ key ] ) ;
39+ if ( select [ key ] . length > 0 ) {
40+ select [ key ] = Array . prototype . slice . call (
41+ root . querySelectorAll ( select [ key ] . join ( ', ' ) ) ) ;
42+ }
43+ } ) ;
44+
45+ // Get all legacy page-break elements.
46+ var legacyEls = root . querySelectorAll ( '.html2pdf__page-break' ) ;
47+ legacyEls = Array . prototype . slice . call ( legacyEls ) ;
48+
49+ // Loop through all elements.
50+ // TODO: Only loop through all if css option is chosen?
51+ var els = root . querySelectorAll ( '*' ) ;
52+ Array . prototype . forEach . call ( els , function pageBreak_loop ( el ) {
53+ // Setup pagebreak rules based on legacy and avoidAll modes.
54+ var rules = {
55+ before : false ,
56+ after : mode . legacy && legacyEls . indexOf ( el ) !== - 1 ,
57+ avoid : mode . avoidAll
58+ } ;
59+
60+ // Add rules for css mode.
61+ if ( mode . css ) {
62+ // TODO: Check if this is valid with iFrames.
63+ var style = window . getComputedStyle ( el ) ;
64+ // TODO: Handle 'left' and 'right' correctly.
65+ // TODO: Add support for 'avoid' on breakBefore/After.
66+ var cssOpt = [ 'always' , 'left' , 'right' ] ;
67+ rules = {
68+ before : rules . before || cssOpt . indexOf ( style . breakBefore || style . pageBreakBefore ) !== - 1 ,
69+ after : rules . after || cssOpt . indexOf ( style . breakAfter || style . pageBreakAfter ) !== - 1 ,
70+ avoid : rules . avoid || ( style . breakInside || style . pageBreakInside ) === 'avoid'
71+ } ;
72+ }
73+
74+ // Add rules for explicit requests.
75+ Object . keys ( rules ) . forEach ( function ( key ) {
76+ rules [ key ] = rules [ key ] || select [ key ] . indexOf ( el ) !== - 1 ;
77+ } ) ;
78+
79+ // Get element position on the screen.
80+ // TODO: Subtract the top of the container from clientRect.top/bottom?
1981 var clientRect = el . getBoundingClientRect ( ) ;
20- el . style . height = pxPageHeight - ( clientRect . top % pxPageHeight ) + 'px' ;
21- } , this ) ;
82+
83+ // Avoid: Check if a break happens mid-element.
84+ if ( rules . avoid && ! rules . before ) {
85+ var startPage = Math . floor ( clientRect . top / pxPageHeight ) ;
86+ var endPage = Math . floor ( clientRect . bottom / pxPageHeight ) ;
87+ var nPages = Math . abs ( clientRect . bottom - clientRect . top ) / pxPageHeight ;
88+
89+ // Turn on rules.before if the el is broken and is less than a page long.
90+ if ( endPage !== startPage && nPages < 1 ) {
91+ rules . before = true ;
92+ }
93+ }
94+
95+ // Before: Create a padding div to push the element to the next page.
96+ if ( rules . before ) {
97+ var pad = createElement ( 'div' , { style : {
98+ display : 'block' ,
99+ height : pxPageHeight - ( clientRect . top % pxPageHeight ) + 'px'
100+ } } ) ;
101+ el . parentNode . insertBefore ( pad , el ) ;
102+ }
103+
104+ // After: Create a padding div to fill the remaining page.
105+ if ( rules . after ) {
106+ var pad = createElement ( 'div' , { style : {
107+ display : 'block' ,
108+ height : pxPageHeight - ( clientRect . bottom % pxPageHeight ) + 'px'
109+ } } ) ;
110+ el . parentNode . insertAfter ( pad , el ) ;
111+ }
112+ } ) ;
22113 } ) ;
23114} ;
0 commit comments