Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1041)

Side by Side Diff: src/com/google/caja/plugin/html-emitter.js

Issue 89076: fix some html-emitter problems on IE (Closed) Base URL: http://google-caja.googlecode.com/svn/trunk/
Patch Set: fix some html-emitter problems on IE Created 14 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/com/google/caja/plugin/DomitaTest.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (C) 2008 Google Inc. 1 // Copyright (C) 2008 Google Inc.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 /** 15 /**
16 * @fileoverview 16 * @fileoverview
17 * JavaScript support for TemplateCompiler.java. 17 * JavaScript support for TemplateCompiler.java.
18 * <p> 18 * <p>
19 * This handles the problem of making sure that only the bits of a Gadget's 19 * This handles the problem of making sure that only the bits of a Gadget's
20 * static HTML which should be visible to a script are visible, and provides 20 * static HTML which should be visible to a script are visible, and provides
21 * mechanisms to reliably find elements using dynamically generated unique IDs 21 * mechanisms to reliably find elements using dynamically generated unique IDs
22 * in the face of DOM modifications by untrusted scripts. 22 * in the face of DOM modifications by untrusted scripts.
23 * 23 *
24 * TODO: automated browser tests. detach/reattach hits some browser quirks.
25 * http://code.google.com/p/google-caja/issues/detail?id=1060
26 *
24 * @author mikesamuel@gmail.com 27 * @author mikesamuel@gmail.com
25 */ 28 */
26 function HtmlEmitter(base, opt_tameDocument) { 29 function HtmlEmitter(base, opt_tameDocument) {
27 if (!base) { throw new Error(); } 30 if (!base) { throw new Error(); }
28 31
29 /** 32 /**
30 * Contiguous pairs of ex-descendants of base, and their ex-parent. 33 * Contiguous pairs of ex-descendants of base, and their ex-parent.
31 * The detached elements (even indices) are ordered depth-first. 34 * The detached elements (even indices) are ordered depth-first.
32 */ 35 */
33 var detached = null; 36 var detached = null;
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 // nodes with the nodes detached from limit. 176 // nodes with the nodes detached from limit.
174 var newDetached = [0, 0]; 177 var newDetached = [0, 0];
175 // Since limit has no parent, detachOnto will bottom out at its sibling. 178 // Since limit has no parent, detachOnto will bottom out at its sibling.
176 detachOnto(limit, newDetached); 179 detachOnto(limit, newDetached);
177 // Find the node containing limit that appears on detached. 180 // Find the node containing limit that appears on detached.
178 for (var limitAnc = limit, parent; (parent = limitAnc.parentNode);) { 181 for (var limitAnc = limit, parent; (parent = limitAnc.parentNode);) {
179 limitAnc = parent; 182 limitAnc = parent;
180 } 183 }
181 // Reattach up to and including limit ancestor. 184 // Reattach up to and including limit ancestor.
182 var nConsumed = 0; 185 var nConsumed = 0;
183 while (true) { 186 while (nConsumed < detached.length) {
184 var toReattach = detached[nConsumed]; 187 // in IE, some types of nodes can't be standalone, and detaching
185 (detached[nConsumed + 1] /* the parent */).appendChild(toReattach); 188 // one will create new parentNodes for them. so at this point,
189 // limitAnc might be an ancestor of the node on detached.
190 var reattach = detached[nConsumed];
191 var reattAnc = reattach;
192 for (; reattAnc.parentNode; reattAnc = reattAnc.parentNode) {}
193 (detached[nConsumed + 1] /* the parent */).appendChild(reattach);
186 nConsumed += 2; 194 nConsumed += 2;
187 if (toReattach === limitAnc) { break; } 195 if (reattAnc === limitAnc) { break; }
188 } 196 }
189 // Replace the reattached bits with the ones detached from limit. 197 // Replace the reattached bits with the ones detached from limit.
190 newDetached[1] = nConsumed; // splice's second arg is the number removed 198 newDetached[1] = nConsumed; // splice's second arg is the number removed
191 arraySplice.apply(detached, newDetached); 199 arraySplice.apply(detached, newDetached);
192 } else { 200 } else {
193 // The first time attach is called, the limit is actually part of the DOM. 201 // The first time attach is called, the limit is actually part of the DOM.
194 // There's no point removing anything when all scripts are deferred. 202 // There's no point removing anything when all scripts are deferred.
195 detached = []; 203 detached = [];
196 detachOnto(limit, detached); 204 detachOnto(limit, detached);
197 } 205 }
198 return limit; 206 return limit;
199 } 207 }
200 /** 208 /**
201 * Removes a wrapper from a textNode 209 * Removes a TextNode wrapper.
202 * When a text node immediately precedes a script block, the limit will be 210 * When the last node before a script block is a TextNode, the
203 * a text node. Text nodes can't be addressed by ID, so the TemplateCompiler 211 * TemplateCompiler labels that TextNode by wrapping it in a span, and
204 * wraps them in a <span> which must be removed to be semantics preserving. 212 * adds a call to unwrap() to tell us when to remove the span.
205 */ 213 */
206 function unwrap(wrapper) { 214 function unwrap(wrapper) {
207 // Text nodes must have exactly one child, so it must be first on the 215 // At this point, the wrapper's TextNode child has been removed and
208 // detached list, since children are earlier than siblings by DFS order. 216 // placed at the front of the detached nodes list. There should never
209 var text = detached[0]; 217 // be more than one, but sometimes there's zero, because some browsers
210 // If this is not true, the TemplateCompiler must be generating unwrap calls 218 // (such as IE) do not create a TextNode when it's only whitespace.
211 // out of order. 219 if (detached[1] === wrapper) {
212 // An untrusted script block should not be able to nuke the wrapper before 220 wrapper.parentNode.replaceChild(detached[0], wrapper);
213 // it's removed so there should be a parentNode. 221 detached.splice(0, 2);
214 wrapper.parentNode.replaceChild(text, wrapper); 222 }
215 detached.splice(0, 2);
216 } 223 }
217 /** 224 /**
218 * Reattach any remaining detached bits, free resources, and fire a document 225 * Reattach any remaining detached bits, free resources, and fire a document
219 * loaded event. 226 * loaded event.
220 */ 227 */
221 function finish() { 228 function finish() {
222 if (detached) { 229 if (detached) {
223 for (var i = 0, n = detached.length; i < n; i += 2) { 230 for (var i = 0, n = detached.length; i < n; i += 2) {
224 detached[i + 1].appendChild(detached[i]); 231 detached[i + 1].appendChild(detached[i]);
225 } 232 }
226 } 233 }
227 // Release references so nodes can be garbage collected. 234 // Release references so nodes can be garbage collected.
228 idMap = detached = base = null; 235 idMap = detached = base = null;
229 return this; 236 return this;
230 } 237 }
231 238
232 function signalLoaded() { 239 function signalLoaded() {
233 // Signals the close of the document and fires any window.onload event 240 // Signals the close of the document and fires any window.onload event
234 // handlers. 241 // handlers.
235 var doc = opt_tameDocument; 242 var doc = opt_tameDocument;
236 if (doc) { doc.signalLoaded___(); } 243 if (doc) { doc.signalLoaded___(); }
237 return this; 244 return this;
238 } 245 }
239 246
247 /** Set an attribute on an element */
248 function setAttr(el, attrName, value) {
249 bridal.setAttribute(el, attrName, value);
250
251 // onevent attributes are extra special
252 var tagAttr = el.tagName.toLowerCase() + ':' + attrName;
MikeSamuel 2009/07/20 19:04:51 Can we use the lower casing function from domita h
253 if (html4.ATTRIBS[tagAttr] === html4.atype.SCRIPT
254 || html4.ATTRIBS['*:' + attrName] === html4.atype.SCRIPT) {
MikeSamuel 2009/07/20 19:04:51 The second clause only applies if html4.ATTRIBS[ta
255 // IE<8 requires us to set onevent attributes this way.
256 el[attrName] = new Function('event', value);
257 }
258 }
259
240 this.byId = byId; 260 this.byId = byId;
241 this.attach = attach; 261 this.attach = attach;
242 this.unwrap = unwrap; 262 this.unwrap = unwrap;
243 this.finish = finish; 263 this.finish = finish;
244 this.signalLoaded = signalLoaded; 264 this.signalLoaded = signalLoaded;
245 this.setAttr = bridal.setAttribute; 265 this.setAttr = setAttr;
246 } 266 }
OLDNEW
« no previous file with comments | « no previous file | tests/com/google/caja/plugin/DomitaTest.java » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b