|
139 | 139 |
|
140 | 140 | // make cloning/importing work! |
141 | 141 | if (needsTemplate || needsCloning) { |
| 142 | + // NOTE: we rely on this cloneNode not causing element upgrade. |
| 143 | + // This means this polyfill must load before the CE polyfill and |
| 144 | + // this would need to be re-worked if a browser supports native CE |
| 145 | + // but not <template>. |
142 | 146 | var nativeCloneNode = Node.prototype.cloneNode; |
143 | 147 |
|
144 | 148 | TemplateImpl.cloneNode = function(template, deep) { |
145 | 149 | var clone = nativeCloneNode.call(template); |
| 150 | + // NOTE: decorate doesn't auto-fix children because they are already |
| 151 | + // decorated so they need special clone fixup. |
146 | 152 | if (this.decorate) { |
147 | 153 | this.decorate(clone); |
148 | 154 | } |
|
151 | 157 | // cloneNode does not cause elements to upgrade. |
152 | 158 | clone.content.appendChild( |
153 | 159 | nativeCloneNode.call(template.content, true)); |
154 | | - // these two lists should be coincident |
| 160 | + // now ensure nested templates are cloned correctly. |
155 | 161 | this.fixClonedDom(clone.content, template.content); |
156 | 162 | } |
157 | 163 | return clone; |
158 | 164 | }; |
159 | 165 |
|
| 166 | + // Given a source and cloned subtree, find <template>'s in the cloned |
| 167 | + // subtree and replace them with cloned <template>'s from source. |
| 168 | + // We must do this because only the source templates have proper .content. |
160 | 169 | TemplateImpl.fixClonedDom = function(clone, source) { |
| 170 | + // these two lists should be coincident |
161 | 171 | var s$ = source.querySelectorAll(TEMPLATE_TAG); |
162 | 172 | var t$ = clone.querySelectorAll(TEMPLATE_TAG); |
163 | 173 | for (var i=0, l=t$.length, t, s; i<l; i++) { |
|
172 | 182 |
|
173 | 183 | var originalImportNode = document.importNode; |
174 | 184 |
|
| 185 | + // override all cloning to fix the cloned subtree to contain properly |
| 186 | + // cloned templates. |
175 | 187 | Node.prototype.cloneNode = function(deep) { |
176 | 188 | var dom = nativeCloneNode.call(this, deep); |
| 189 | + // template.content is cloned iff `deep`. |
177 | 190 | if (deep) { |
178 | 191 | TemplateImpl.fixClonedDom(dom, this); |
179 | 192 | } |
180 | 193 | return dom; |
181 | 194 | }; |
182 | 195 |
|
183 | | - // clone instead of importing <template> |
| 196 | + // NOTE: we are cloning instead of importing <template>'s. |
| 197 | + // However, the ownerDocument of the cloned template will be correct! |
| 198 | + // This is because the native import node creates the right document owned |
| 199 | + // subtree and `fixClonedDom` inserts cloned templates into this subtree, |
| 200 | + // thus updating the owner doc. |
184 | 201 | document.importNode = function(element, deep) { |
185 | 202 | if (element.localName === TEMPLATE_TAG) { |
186 | 203 | return TemplateImpl.cloneNode(element, deep); |
|
0 commit comments