9
9
*/
10
10
11
11
// minimal template polyfill
12
- if ( typeof HTMLTemplateElement === 'undefined' ) {
13
- ( function ( ) {
12
+ ( function ( ) {
13
+ var needsTemplate = ( typeof HTMLTemplateElement === 'undefined' ) ;
14
+
15
+ // returns true if nested templates can be cloned (they cannot be on
16
+ // some impl's like Safari 8)
17
+ var needsCloning = ( function ( ) {
18
+ if ( ! needsTemplate ) {
19
+ var t = document . createElement ( 'template' ) ;
20
+ t . innerHTML = '<div></div>' ;
21
+ var clone = t . cloneNode ( true ) ;
22
+ return ( clone . content . childNodes . length === 0 ) ;
23
+ }
24
+ } ) ( ) ;
25
+
26
+ var TEMPLATE_TAG = 'template' ;
27
+ var TemplateImpl = function ( ) { } ;
14
28
15
- var TEMPLATE_TAG = 'template' ;
29
+ if ( needsTemplate ) {
16
30
17
31
var contentDoc = document . implementation . createHTMLDocument ( 'template' ) ;
18
32
var canDecorate = true ;
19
33
20
34
/**
21
35
Provides a minimal shim for the <template> element.
22
36
*/
23
- HTMLTemplateElement = function ( ) { } ;
24
- HTMLTemplateElement . prototype = Object . create ( HTMLElement . prototype ) ;
37
+
38
+ TemplateImpl . prototype = Object . create ( HTMLElement . prototype ) ;
25
39
26
40
/**
27
41
The `decorate` method moves element children to the template's `content`.
28
42
NOTE: there is no support for dynamically adding elements to templates.
29
43
*/
30
- HTMLTemplateElement . decorate = function ( template ) {
44
+ TemplateImpl . decorate = function ( template ) {
31
45
// if the template is decorated, return fast
32
46
if ( template . content ) {
33
47
return ;
@@ -51,7 +65,7 @@ if (typeof HTMLTemplateElement === 'undefined') {
51
65
} ,
52
66
set : function ( text ) {
53
67
contentDoc . body . innerHTML = text ;
54
- HTMLTemplateElement . bootstrap ( contentDoc ) ;
68
+ TemplateImpl . bootstrap ( contentDoc ) ;
55
69
while ( this . content . firstChild ) {
56
70
this . content . removeChild ( this . content . firstChild ) ;
57
71
}
@@ -63,22 +77,73 @@ if (typeof HTMLTemplateElement === 'undefined') {
63
77
} ) ;
64
78
65
79
template . cloneNode = function ( deep ) {
66
- return HTMLTemplateElement . cloneNode ( this , deep ) ;
80
+ return TemplateImpl . cloneNode ( this , deep ) ;
67
81
} ;
68
82
69
83
} catch ( err ) {
70
84
canDecorate = false ;
71
85
}
72
86
}
73
87
// bootstrap recursively
74
- HTMLTemplateElement . bootstrap ( template . content ) ;
88
+ TemplateImpl . bootstrap ( template . content ) ;
89
+ } ;
90
+
91
+ /**
92
+ The `bootstrap` method is called automatically and "fixes" all
93
+ <template> elements in the document referenced by the `doc` argument.
94
+ */
95
+ TemplateImpl . bootstrap = function ( doc ) {
96
+ var templates = doc . querySelectorAll ( TEMPLATE_TAG ) ;
97
+ for ( var i = 0 , l = templates . length , t ; ( i < l ) && ( t = templates [ i ] ) ; i ++ ) {
98
+ TemplateImpl . decorate ( t ) ;
99
+ }
75
100
} ;
76
101
102
+ // auto-bootstrapping for main document
103
+ document . addEventListener ( 'DOMContentLoaded' , function ( ) {
104
+ TemplateImpl . bootstrap ( document ) ;
105
+ } ) ;
106
+
107
+ // Patch document.createElement to ensure newly created templates have content
108
+ var createElement = document . createElement ;
109
+ document . createElement = function ( ) {
110
+ 'use strict' ;
111
+ var el = createElement . apply ( document , arguments ) ;
112
+ if ( el . localName == 'template' ) {
113
+ TemplateImpl . decorate ( el ) ;
114
+ }
115
+ return el ;
116
+ } ;
117
+
118
+ var escapeDataRegExp = / [ & \u00A0 < > ] / g;
119
+
120
+ function escapeReplace ( c ) {
121
+ switch ( c ) {
122
+ case '&' :
123
+ return '&' ;
124
+ case '<' :
125
+ return '<' ;
126
+ case '>' :
127
+ return '>' ;
128
+ case '\u00A0' :
129
+ return ' ' ;
130
+ }
131
+ }
132
+
133
+ function escapeData ( s ) {
134
+ return s . replace ( escapeDataRegExp , escapeReplace ) ;
135
+ }
136
+ }
137
+
138
+ // make cloning/importing work!
139
+ if ( needsTemplate || needsCloning ) {
77
140
var nativeCloneNode = Node . prototype . cloneNode ;
78
141
79
- HTMLTemplateElement . cloneNode = function ( template , deep ) {
142
+ TemplateImpl . cloneNode = function ( template , deep ) {
80
143
var clone = nativeCloneNode . call ( template ) ;
81
- this . decorate ( clone ) ;
144
+ if ( this . decorate ) {
145
+ this . decorate ( clone ) ;
146
+ }
82
147
if ( deep ) {
83
148
// NOTE: use native clone node to make sure CE's wrapped
84
149
// cloneNode does not cause elements to upgrade.
@@ -90,13 +155,15 @@ if (typeof HTMLTemplateElement === 'undefined') {
90
155
return clone ;
91
156
} ;
92
157
93
- HTMLTemplateElement . fixClonedDom = function ( clone , source ) {
158
+ TemplateImpl . fixClonedDom = function ( clone , source ) {
94
159
var s$ = source . querySelectorAll ( TEMPLATE_TAG ) ;
95
160
var t$ = clone . querySelectorAll ( TEMPLATE_TAG ) ;
96
161
for ( var i = 0 , l = t$ . length , t , s ; i < l ; i ++ ) {
97
162
s = s$ [ i ] ;
98
163
t = t$ [ i ] ;
99
- this . decorate ( s ) ;
164
+ if ( this . decorate ) {
165
+ this . decorate ( s ) ;
166
+ }
100
167
t . parentNode . replaceChild ( s . cloneNode ( true ) , t ) ;
101
168
}
102
169
} ;
@@ -106,69 +173,27 @@ if (typeof HTMLTemplateElement === 'undefined') {
106
173
Node . prototype . cloneNode = function ( deep ) {
107
174
var dom = nativeCloneNode . call ( this , deep ) ;
108
175
if ( deep ) {
109
- HTMLTemplateElement . fixClonedDom ( dom , this ) ;
176
+ TemplateImpl . fixClonedDom ( dom , this ) ;
110
177
}
111
178
return dom ;
112
179
} ;
113
180
114
181
// clone instead of importing <template>
115
182
document . importNode = function ( element , deep ) {
116
183
if ( element . localName === TEMPLATE_TAG ) {
117
- return HTMLTemplateElement . cloneNode ( element , deep ) ;
184
+ return TemplateImpl . cloneNode ( element , deep ) ;
118
185
} else {
119
186
var dom = originalImportNode . call ( document , element , deep ) ;
120
187
if ( deep ) {
121
- HTMLTemplateElement . fixClonedDom ( dom , element ) ;
188
+ TemplateImpl . fixClonedDom ( dom , element ) ;
122
189
}
123
190
return dom ;
124
191
}
125
192
} ;
193
+ }
126
194
127
- /**
128
- The `bootstrap` method is called automatically and "fixes" all
129
- <template> elements in the document referenced by the `doc` argument.
130
- */
131
- HTMLTemplateElement . bootstrap = function ( doc ) {
132
- var templates = doc . querySelectorAll ( TEMPLATE_TAG ) ;
133
- for ( var i = 0 , l = templates . length , t ; ( i < l ) && ( t = templates [ i ] ) ; i ++ ) {
134
- HTMLTemplateElement . decorate ( t ) ;
135
- }
136
- } ;
137
-
138
- // auto-bootstrapping for main document
139
- document . addEventListener ( 'DOMContentLoaded' , function ( ) {
140
- HTMLTemplateElement . bootstrap ( document ) ;
141
- } ) ;
142
-
143
- // Patch document.createElement to ensure newly created templates have content
144
- var createElement = document . createElement ;
145
- document . createElement = function ( ) {
146
- 'use strict' ;
147
- var el = createElement . apply ( document , arguments ) ;
148
- if ( el . localName == 'template' ) {
149
- HTMLTemplateElement . decorate ( el ) ;
150
- }
151
- return el ;
152
- } ;
153
-
154
- var escapeDataRegExp = / [ & \u00A0 < > ] / g;
155
-
156
- function escapeReplace ( c ) {
157
- switch ( c ) {
158
- case '&' :
159
- return '&' ;
160
- case '<' :
161
- return '<' ;
162
- case '>' :
163
- return '>' ;
164
- case '\u00A0' :
165
- return ' ' ;
166
- }
167
- }
168
-
169
- function escapeData ( s ) {
170
- return s . replace ( escapeDataRegExp , escapeReplace ) ;
171
- }
195
+ if ( needsTemplate ) {
196
+ HTMLTemplateElement = TemplateImpl ;
197
+ }
172
198
173
- } ) ( ) ;
174
- }
199
+ } ) ( ) ;
0 commit comments