99 */
1010
1111// 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 ( ) { } ;
1428
15- var TEMPLATE_TAG = 'template' ;
29+ if ( needsTemplate ) {
1630
1731 var contentDoc = document . implementation . createHTMLDocument ( 'template' ) ;
1832 var canDecorate = true ;
1933
2034 /**
2135 Provides a minimal shim for the <template> element.
2236 */
23- HTMLTemplateElement = function ( ) { } ;
24- HTMLTemplateElement . prototype = Object . create ( HTMLElement . prototype ) ;
37+
38+ TemplateImpl . prototype = Object . create ( HTMLElement . prototype ) ;
2539
2640 /**
2741 The `decorate` method moves element children to the template's `content`.
2842 NOTE: there is no support for dynamically adding elements to templates.
2943 */
30- HTMLTemplateElement . decorate = function ( template ) {
44+ TemplateImpl . decorate = function ( template ) {
3145 // if the template is decorated, return fast
3246 if ( template . content ) {
3347 return ;
@@ -51,7 +65,7 @@ if (typeof HTMLTemplateElement === 'undefined') {
5165 } ,
5266 set : function ( text ) {
5367 contentDoc . body . innerHTML = text ;
54- HTMLTemplateElement . bootstrap ( contentDoc ) ;
68+ TemplateImpl . bootstrap ( contentDoc ) ;
5569 while ( this . content . firstChild ) {
5670 this . content . removeChild ( this . content . firstChild ) ;
5771 }
@@ -63,22 +77,73 @@ if (typeof HTMLTemplateElement === 'undefined') {
6377 } ) ;
6478
6579 template . cloneNode = function ( deep ) {
66- return HTMLTemplateElement . cloneNode ( this , deep ) ;
80+ return TemplateImpl . cloneNode ( this , deep ) ;
6781 } ;
6882
6983 } catch ( err ) {
7084 canDecorate = false ;
7185 }
7286 }
7387 // 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+ }
75100 } ;
76101
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 ) {
77140 var nativeCloneNode = Node . prototype . cloneNode ;
78141
79- HTMLTemplateElement . cloneNode = function ( template , deep ) {
142+ TemplateImpl . cloneNode = function ( template , deep ) {
80143 var clone = nativeCloneNode . call ( template ) ;
81- this . decorate ( clone ) ;
144+ if ( this . decorate ) {
145+ this . decorate ( clone ) ;
146+ }
82147 if ( deep ) {
83148 // NOTE: use native clone node to make sure CE's wrapped
84149 // cloneNode does not cause elements to upgrade.
@@ -90,13 +155,15 @@ if (typeof HTMLTemplateElement === 'undefined') {
90155 return clone ;
91156 } ;
92157
93- HTMLTemplateElement . fixClonedDom = function ( clone , source ) {
158+ TemplateImpl . fixClonedDom = function ( clone , source ) {
94159 var s$ = source . querySelectorAll ( TEMPLATE_TAG ) ;
95160 var t$ = clone . querySelectorAll ( TEMPLATE_TAG ) ;
96161 for ( var i = 0 , l = t$ . length , t , s ; i < l ; i ++ ) {
97162 s = s$ [ i ] ;
98163 t = t$ [ i ] ;
99- this . decorate ( s ) ;
164+ if ( this . decorate ) {
165+ this . decorate ( s ) ;
166+ }
100167 t . parentNode . replaceChild ( s . cloneNode ( true ) , t ) ;
101168 }
102169 } ;
@@ -106,69 +173,27 @@ if (typeof HTMLTemplateElement === 'undefined') {
106173 Node . prototype . cloneNode = function ( deep ) {
107174 var dom = nativeCloneNode . call ( this , deep ) ;
108175 if ( deep ) {
109- HTMLTemplateElement . fixClonedDom ( dom , this ) ;
176+ TemplateImpl . fixClonedDom ( dom , this ) ;
110177 }
111178 return dom ;
112179 } ;
113180
114181 // clone instead of importing <template>
115182 document . importNode = function ( element , deep ) {
116183 if ( element . localName === TEMPLATE_TAG ) {
117- return HTMLTemplateElement . cloneNode ( element , deep ) ;
184+ return TemplateImpl . cloneNode ( element , deep ) ;
118185 } else {
119186 var dom = originalImportNode . call ( document , element , deep ) ;
120187 if ( deep ) {
121- HTMLTemplateElement . fixClonedDom ( dom , element ) ;
188+ TemplateImpl . fixClonedDom ( dom , element ) ;
122189 }
123190 return dom ;
124191 }
125192 } ;
193+ }
126194
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+ }
172198
173- } ) ( ) ;
174- }
199+ } ) ( ) ;
0 commit comments