1
1
import Worker from '../worker.js' ;
2
+ import { objType , createElement } from './utils.js' ;
2
3
3
4
// Add page-break functionality.
4
5
@@ -7,17 +8,107 @@ var orig = {
7
8
toContainer : Worker . prototype . toContainer
8
9
} ;
9
10
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
+
10
19
Worker . prototype . toContainer = function toContainer ( ) {
11
20
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 ;
14
23
var pxPageHeight = this . prop . pageSize . inner . px . height ;
15
24
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?
19
81
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
+ } ) ;
22
113
} ) ;
23
114
} ;
0 commit comments