Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: pkg/shadow_dom/lib/shadow_dom.debug.js

Issue 23548014: update shadowdom polyfill to latest (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 if ((!HTMLElement.prototype.createShadowRoot && 1 if ((!HTMLElement.prototype.createShadowRoot &&
2 !HTMLElement.prototype.webkitCreateShadowRoot) || 2 !HTMLElement.prototype.webkitCreateShadowRoot) ||
3 window.__forceShadowDomPolyfill) { 3 window.__forceShadowDomPolyfill) {
4 4
5 /* 5 /*
6 * Copyright 2013 The Polymer Authors. All rights reserved. 6 * Copyright 2013 The Polymer Authors. All rights reserved.
7 * Use of this source code is governed by a BSD-style 7 * Use of this source code is governed by a BSD-style
8 * license that can be found in the LICENSE file. 8 * license that can be found in the LICENSE file.
9 */ 9 */
10 (function() { 10 (function() {
(...skipping 13 matching lines...) Expand all
24 24
25 // SideTable is a weak map where possible. If WeakMap is not available the 25 // SideTable is a weak map where possible. If WeakMap is not available the
26 // association is stored as an expando property. 26 // association is stored as an expando property.
27 var SideTable; 27 var SideTable;
28 // TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox 28 // TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox
29 if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) { 29 if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) {
30 SideTable = WeakMap; 30 SideTable = WeakMap;
31 } else { 31 } else {
32 (function() { 32 (function() {
33 var defineProperty = Object.defineProperty; 33 var defineProperty = Object.defineProperty;
34 var hasOwnProperty = Object.hasOwnProperty; 34 var counter = Date.now() % 1e9;
35 var counter = new Date().getTime() % 1e9;
36 35
37 SideTable = function() { 36 SideTable = function() {
38 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__'); 37 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
39 }; 38 };
40 39
41 SideTable.prototype = { 40 SideTable.prototype = {
42 set: function(key, value) { 41 set: function(key, value) {
43 defineProperty(key, this.name, {value: value, writable: true}); 42 var entry = key[this.name];
43 if (entry && entry[0] === key)
44 entry[1] = value;
45 else
46 defineProperty(key, this.name, {value: [key, value], writable: true});
44 }, 47 },
45 get: function(key) { 48 get: function(key) {
46 return hasOwnProperty.call(key, this.name) ? key[this.name] : undefined; 49 var entry;
50 return (entry = key[this.name]) && entry[0] === key ?
51 entry[1] : undefined;
47 }, 52 },
48 delete: function(key) { 53 delete: function(key) {
49 this.set(key, undefined); 54 this.set(key, undefined);
50 } 55 }
51 } 56 }
52 })(); 57 })();
53 } 58 }
54 59
55 // Copyright 2012 The Polymer Authors. All rights reserved. 60 // Copyright 2012 The Polymer Authors. All rights reserved.
56 // Use of this source code is goverened by a BSD-style 61 // Use of this source code is goverened by a BSD-style
57 // license that can be found in the LICENSE file. 62 // license that can be found in the LICENSE file.
58 63
59 var ShadowDOMPolyfill = {}; 64 var ShadowDOMPolyfill = {};
60 65
61 (function(scope) { 66 (function(scope) {
62 'use strict'; 67 'use strict';
63 68
64 var wrapperTable = new SideTable(); 69 var wrapperTable = new SideTable();
65 var constructorTable = new SideTable(); 70 var constructorTable = new SideTable();
71 var nativePrototypeTable = new SideTable();
66 var wrappers = Object.create(null); 72 var wrappers = Object.create(null);
67 73
68 function assert(b) { 74 function assert(b) {
69 if (!b) 75 if (!b)
70 throw new Error('Assertion failed'); 76 throw new Error('Assertion failed');
71 }; 77 };
72 78
73 function mixin(to, from) { 79 function mixin(to, from) {
74 Object.getOwnPropertyNames(from).forEach(function(name) { 80 Object.getOwnPropertyNames(from).forEach(function(name) {
75 Object.defineProperty(to, name, 81 Object.defineProperty(to, name,
(...skipping 12 matching lines...) Expand all
88 case 'prototype': 94 case 'prototype':
89 case 'toString': 95 case 'toString':
90 return; 96 return;
91 } 97 }
92 Object.defineProperty(to, name, 98 Object.defineProperty(to, name,
93 Object.getOwnPropertyDescriptor(from, name)); 99 Object.getOwnPropertyDescriptor(from, name));
94 }); 100 });
95 return to; 101 return to;
96 }; 102 };
97 103
104 function oneOf(object, propertyNames) {
105 for (var i = 0; i < propertyNames.length; i++) {
106 if (propertyNames[i] in object)
107 return propertyNames[i];
108 }
109 }
110
98 // Mozilla's old DOM bindings are bretty busted: 111 // Mozilla's old DOM bindings are bretty busted:
99 // https://bugzilla.mozilla.org/show_bug.cgi?id=855844 112 // https://bugzilla.mozilla.org/show_bug.cgi?id=855844
100 // Make sure they are create before we start modifying things. 113 // Make sure they are create before we start modifying things.
101 Object.getOwnPropertyNames(window); 114 Object.getOwnPropertyNames(window);
102 115
103 function getWrapperConstructor(node) { 116 function getWrapperConstructor(node) {
104 var nativePrototype = node.__proto__ || Object.getPrototypeOf(node); 117 var nativePrototype = node.__proto__ || Object.getPrototypeOf(node);
105 var wrapperConstructor = constructorTable.get(nativePrototype); 118 var wrapperConstructor = constructorTable.get(nativePrototype);
106 if (wrapperConstructor) 119 if (wrapperConstructor)
107 return wrapperConstructor; 120 return wrapperConstructor;
(...skipping 18 matching lines...) Expand all
126 139
127 // This is used as a fallback when getting the descriptor fails in 140 // This is used as a fallback when getting the descriptor fails in
128 // installProperty. 141 // installProperty.
129 var dummyDescriptor = { 142 var dummyDescriptor = {
130 get: function() {}, 143 get: function() {},
131 set: function(v) {}, 144 set: function(v) {},
132 configurable: true, 145 configurable: true,
133 enumerable: true 146 enumerable: true
134 }; 147 };
135 148
149 function isEventHandlerName(name) {
150 return /^on[a-z]+$/.test(name);
151 }
152
136 function installProperty(source, target, allowMethod) { 153 function installProperty(source, target, allowMethod) {
137 Object.getOwnPropertyNames(source).forEach(function(name) { 154 Object.getOwnPropertyNames(source).forEach(function(name) {
138 if (name in target) 155 if (name in target)
139 return; 156 return;
140 157
141 if (isFirefox) { 158 if (isFirefox) {
142 // Tickle Firefox's old bindings. 159 // Tickle Firefox's old bindings.
143 source.__lookupGetter__(name); 160 source.__lookupGetter__(name);
144 } 161 }
145 var descriptor; 162 var descriptor;
146 try { 163 try {
147 descriptor = Object.getOwnPropertyDescriptor(source, name); 164 descriptor = Object.getOwnPropertyDescriptor(source, name);
148 } catch (ex) { 165 } catch (ex) {
149 // JSC and V8 both use data properties instead accessors which can cause 166 // JSC and V8 both use data properties instead of accessors which can
150 // getting the property desciptor throw an exception. 167 // cause getting the property desciptor to throw an exception.
151 // https://bugs.webkit.org/show_bug.cgi?id=49739 168 // https://bugs.webkit.org/show_bug.cgi?id=49739
152 descriptor = dummyDescriptor; 169 descriptor = dummyDescriptor;
153 } 170 }
154 var getter, setter; 171 var getter, setter;
155 if (allowMethod && typeof descriptor.value === 'function') { 172 if (allowMethod && typeof descriptor.value === 'function') {
156 target[name] = function() { 173 target[name] = function() {
157 return this.impl[name].apply(this.impl, arguments); 174 return this.impl[name].apply(this.impl, arguments);
158 }; 175 };
159 return; 176 return;
160 } 177 }
161 178
162 getter = function() { 179 var isEvent = isEventHandlerName(name);
163 return this.impl[name]; 180 if (isEvent) {
164 }; 181 getter = scope.getEventHandlerGetter(name);
165 182 } else {
166 if (descriptor.writable || descriptor.set) { 183 getter = function() {
167 setter = function(value) { 184 return this.impl[name];
168 this.impl[name] = value;
169 }; 185 };
170 } 186 }
171 187
188 if (descriptor.writable || descriptor.set) {
189 if (isEvent) {
190 setter = scope.getEventHandlerSetter(name);
191 } else {
192 setter = function(value) {
193 this.impl[name] = value;
194 };
195 }
196 }
197
172 Object.defineProperty(target, name, { 198 Object.defineProperty(target, name, {
173 get: getter, 199 get: getter,
174 set: setter, 200 set: setter,
175 configurable: descriptor.configurable, 201 configurable: descriptor.configurable,
176 enumerable: descriptor.enumerable 202 enumerable: descriptor.enumerable
177 }); 203 });
178 }); 204 });
179 } 205 }
180 206
181 /** 207 /**
182 * @param {Function} nativeConstructor 208 * @param {Function} nativeConstructor
183 * @param {Function} wrapperConstructor 209 * @param {Function} wrapperConstructor
184 * @param {string|Object=} opt_instance If present, this is used to extract 210 * @param {Object=} opt_instance If present, this is used to extract
185 * properties from an instance object. If this is a string 211 * properties from an instance object.
186 * |document.createElement| is used to create an instance.
187 */ 212 */
188 function register(nativeConstructor, wrapperConstructor, opt_instance) { 213 function register(nativeConstructor, wrapperConstructor, opt_instance) {
189 var nativePrototype = nativeConstructor.prototype; 214 var nativePrototype = nativeConstructor.prototype;
190 registerInternal(nativePrototype, wrapperConstructor, opt_instance); 215 registerInternal(nativePrototype, wrapperConstructor, opt_instance);
191 mixinStatics(wrapperConstructor, nativeConstructor); 216 mixinStatics(wrapperConstructor, nativeConstructor);
192 } 217 }
193 218
194 function registerInternal(nativePrototype, wrapperConstructor, opt_instance) { 219 function registerInternal(nativePrototype, wrapperConstructor, opt_instance) {
195 var wrapperPrototype = wrapperConstructor.prototype; 220 var wrapperPrototype = wrapperConstructor.prototype;
196 assert(constructorTable.get(nativePrototype) === undefined); 221 assert(constructorTable.get(nativePrototype) === undefined);
222
197 constructorTable.set(nativePrototype, wrapperConstructor); 223 constructorTable.set(nativePrototype, wrapperConstructor);
224 nativePrototypeTable.set(wrapperPrototype, nativePrototype);
225
198 addForwardingProperties(nativePrototype, wrapperPrototype); 226 addForwardingProperties(nativePrototype, wrapperPrototype);
199 if (opt_instance) 227 if (opt_instance)
200 registerInstanceProperties(wrapperPrototype, opt_instance); 228 registerInstanceProperties(wrapperPrototype, opt_instance);
201 } 229 }
202 230
203 function isWrapperFor(wrapperConstructor, nativeConstructor) { 231 function isWrapperFor(wrapperConstructor, nativeConstructor) {
204 return constructorTable.get(nativeConstructor.prototype) === 232 return constructorTable.get(nativeConstructor.prototype) ===
205 wrapperConstructor; 233 wrapperConstructor;
206 } 234 }
207 235
(...skipping 17 matching lines...) Expand all
225 return GeneratedWrapper; 253 return GeneratedWrapper;
226 } 254 }
227 255
228 function createWrapperConstructor(superWrapperConstructor) { 256 function createWrapperConstructor(superWrapperConstructor) {
229 function GeneratedWrapper(node) { 257 function GeneratedWrapper(node) {
230 superWrapperConstructor.call(this, node); 258 superWrapperConstructor.call(this, node);
231 } 259 }
232 GeneratedWrapper.prototype = 260 GeneratedWrapper.prototype =
233 Object.create(superWrapperConstructor.prototype); 261 Object.create(superWrapperConstructor.prototype);
234 GeneratedWrapper.prototype.constructor = GeneratedWrapper; 262 GeneratedWrapper.prototype.constructor = GeneratedWrapper;
235 // We add this property to work around a Firefox bug where HTMLFormElement
236 // and HTMLInputElements sometimes have their constructor incorrectly
237 // attached to GeneratedWrapper. See lib/patches-shadowdom-polyfill.js
238 GeneratedWrapper._ShadowDOMPolyfill$isGeneratedWrapper = true;
239 263
240 return GeneratedWrapper; 264 return GeneratedWrapper;
241 } 265 }
242 266
243 var OriginalDOMImplementation = DOMImplementation; 267 var OriginalDOMImplementation = DOMImplementation;
244 var OriginalEvent = Event; 268 var OriginalEvent = Event;
245 var OriginalNode = Node; 269 var OriginalNode = Node;
246 var OriginalWindow = Window; 270 var OriginalWindow = Window;
271 var OriginalRange = Range;
247 272
248 function isWrapper(object) { 273 function isWrapper(object) {
249 return object instanceof wrappers.EventTarget || 274 return object instanceof wrappers.EventTarget ||
250 object instanceof wrappers.Event || 275 object instanceof wrappers.Event ||
276 object instanceof wrappers.Range ||
251 object instanceof wrappers.DOMImplementation; 277 object instanceof wrappers.DOMImplementation;
252 } 278 }
253 279
254 function isNative(object) { 280 function isNative(object) {
255 return object instanceof OriginalNode || 281 return object instanceof OriginalNode ||
256 object instanceof OriginalEvent || 282 object instanceof OriginalEvent ||
257 object instanceof OriginalWindow || 283 object instanceof OriginalWindow ||
284 object instanceof OriginalRange ||
258 object instanceof OriginalDOMImplementation; 285 object instanceof OriginalDOMImplementation;
259 } 286 }
260 287
261 /** 288 /**
262 * Wraps a node in a WrapperNode. If there already exists a wrapper for the 289 * Wraps a node in a WrapperNode. If there already exists a wrapper for the
263 * |node| that wrapper is returned instead. 290 * |node| that wrapper is returned instead.
264 * @param {Node} node 291 * @param {Node} node
265 * @return {WrapperNode} 292 * @return {WrapperNode}
266 */ 293 */
267 function wrap(impl) { 294 function wrap(impl) {
268 if (impl === null) 295 if (impl === null)
269 return null; 296 return null;
270 297
271 assert(isNative(impl)); 298 assert(isNative(impl));
272 var wrapper = wrapperTable.get(impl); 299 var wrapper = wrapperTable.get(impl);
273 if (!wrapper) { 300 if (!wrapper)
274 var wrapperConstructor = getWrapperConstructor(impl); 301 wrapperTable.set(impl, wrapper = new (getWrapperConstructor(impl))(impl));
275 wrapper = new wrapperConstructor(impl);
276 wrapperTable.set(impl, wrapper);
277 }
278 return wrapper; 302 return wrapper;
279 } 303 }
280 304
281 /** 305 /**
282 * Unwraps a wrapper and returns the node it is wrapping. 306 * Unwraps a wrapper and returns the node it is wrapping.
283 * @param {WrapperNode} wrapper 307 * @param {WrapperNode} wrapper
284 * @return {Node} 308 * @return {Node}
285 */ 309 */
286 function unwrap(wrapper) { 310 function unwrap(wrapper) {
287 if (wrapper === null) 311 if (wrapper === null)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 * Forwards existing methods on the native object to the wrapper methods. 364 * Forwards existing methods on the native object to the wrapper methods.
341 * This does not wrap any of the arguments or the return value since the 365 * This does not wrap any of the arguments or the return value since the
342 * wrapper implementation already takes care of that. 366 * wrapper implementation already takes care of that.
343 * @param {Array.<Function>} constructors 367 * @param {Array.<Function>} constructors
344 * @parem {Array.<string>} names 368 * @parem {Array.<string>} names
345 */ 369 */
346 function forwardMethodsToWrapper(constructors, names) { 370 function forwardMethodsToWrapper(constructors, names) {
347 constructors.forEach(function(constructor) { 371 constructors.forEach(function(constructor) {
348 names.forEach(function(name) { 372 names.forEach(function(name) {
349 constructor.prototype[name] = function() { 373 constructor.prototype[name] = function() {
350 var w = wrap(this); 374 var w = wrapIfNeeded(this);
351 return w[name].apply(w, arguments); 375 return w[name].apply(w, arguments);
352 }; 376 };
353 }); 377 });
354 }); 378 });
355 } 379 }
356 380
357 scope.assert = assert; 381 scope.assert = assert;
382 scope.constructorTable = constructorTable;
358 scope.defineGetter = defineGetter; 383 scope.defineGetter = defineGetter;
359 scope.defineWrapGetter = defineWrapGetter; 384 scope.defineWrapGetter = defineWrapGetter;
360 scope.forwardMethodsToWrapper = forwardMethodsToWrapper; 385 scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
361 scope.isWrapper = isWrapper;
362 scope.isWrapperFor = isWrapperFor; 386 scope.isWrapperFor = isWrapperFor;
363 scope.mixin = mixin; 387 scope.mixin = mixin;
388 scope.nativePrototypeTable = nativePrototypeTable;
389 scope.oneOf = oneOf;
364 scope.registerObject = registerObject; 390 scope.registerObject = registerObject;
365 scope.registerWrapper = register; 391 scope.registerWrapper = register;
366 scope.rewrap = rewrap; 392 scope.rewrap = rewrap;
367 scope.unwrap = unwrap; 393 scope.unwrap = unwrap;
368 scope.unwrapIfNeeded = unwrapIfNeeded; 394 scope.unwrapIfNeeded = unwrapIfNeeded;
369 scope.wrap = wrap; 395 scope.wrap = wrap;
370 scope.wrapIfNeeded = wrapIfNeeded; 396 scope.wrapIfNeeded = wrapIfNeeded;
371 scope.wrappers = wrappers; 397 scope.wrappers = wrappers;
372 398
373 })(this.ShadowDOMPolyfill); 399 })(this.ShadowDOMPolyfill);
374
375 // Copyright 2013 The Polymer Authors. All rights reserved. 400 // Copyright 2013 The Polymer Authors. All rights reserved.
376 // Use of this source code is goverened by a BSD-style 401 // Use of this source code is goverened by a BSD-style
377 // license that can be found in the LICENSE file. 402 // license that can be found in the LICENSE file.
378 403
379 (function(scope) { 404 (function(scope) {
380 'use strict'; 405 'use strict';
381 406
382 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; 407 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
383 var mixin = scope.mixin; 408 var mixin = scope.mixin;
384 var registerWrapper = scope.registerWrapper; 409 var registerWrapper = scope.registerWrapper;
385 var unwrap = scope.unwrap; 410 var unwrap = scope.unwrap;
386 var wrap = scope.wrap; 411 var wrap = scope.wrap;
387 var wrappers = scope.wrappers; 412 var wrappers = scope.wrappers;
388 413
389 var wrappedFuns = new SideTable(); 414 var wrappedFuns = new SideTable();
390 var listenersTable = new SideTable(); 415 var listenersTable = new SideTable();
391 var handledEventsTable = new SideTable(); 416 var handledEventsTable = new SideTable();
392 var targetTable = new SideTable(); 417 var targetTable = new SideTable();
393 var currentTargetTable = new SideTable(); 418 var currentTargetTable = new SideTable();
394 var relatedTargetTable = new SideTable(); 419 var relatedTargetTable = new SideTable();
395 var eventPhaseTable = new SideTable(); 420 var eventPhaseTable = new SideTable();
396 var stopPropagationTable = new SideTable(); 421 var stopPropagationTable = new SideTable();
397 var stopImmediatePropagationTable = new SideTable(); 422 var stopImmediatePropagationTable = new SideTable();
423 var eventHandlersTable = new SideTable();
424 var eventPathTable = new SideTable();
398 425
399 function isShadowRoot(node) { 426 function isShadowRoot(node) {
400 return node instanceof wrappers.ShadowRoot; 427 return node instanceof wrappers.ShadowRoot;
401 } 428 }
402 429
403 function isInsertionPoint(node) { 430 function isInsertionPoint(node) {
404 var localName = node.localName; 431 var localName = node.localName;
405 return localName === 'content' || localName === 'shadow'; 432 return localName === 'content' || localName === 'shadow';
406 } 433 }
407 434
408 function isShadowHost(node) { 435 function isShadowHost(node) {
409 return !!node.shadowRoot; 436 return !!node.shadowRoot;
410 } 437 }
411 438
412 function getEventParent(node) { 439 function getEventParent(node) {
413 var dv; 440 var dv;
414 return node.parentNode || (dv = node.defaultView) && wrap(dv) || null; 441 return node.parentNode || (dv = node.defaultView) && wrap(dv) || null;
415 } 442 }
416 443
417 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-parent 444 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-parent
418 function calculateParents(node, context, ancestors) { 445 function calculateParents(node, context, ancestors) {
419 if (ancestors.length) 446 if (ancestors.length)
420 return ancestors.shift(); 447 return ancestors.shift();
421 448
422 // 1. 449 // 1.
423 if (isShadowRoot(node)) 450 if (isShadowRoot(node))
424 return node.insertionParent || scope.getHostForShadowRoot(node); 451 return getInsertionParent(node) || scope.getHostForShadowRoot(node);
425 452
426 // 2. 453 // 2.
427 var eventParents = scope.eventParentsTable.get(node); 454 var eventParents = scope.eventParentsTable.get(node);
428 if (eventParents) { 455 if (eventParents) {
429 // Copy over the remaining event parents for next iteration. 456 // Copy over the remaining event parents for next iteration.
430 for (var i = 1; i < eventParents.length; i++) { 457 for (var i = 1; i < eventParents.length; i++) {
431 ancestors[i - 1] = eventParents[i]; 458 ancestors[i - 1] = eventParents[i];
432 } 459 }
433 return eventParents[0]; 460 return eventParents[0];
434 } 461 }
435 462
436 // 3. 463 // 3.
437 if (context && isInsertionPoint(node)) { 464 if (context && isInsertionPoint(node)) {
438 var parentNode = node.parentNode; 465 var parentNode = node.parentNode;
439 if (parentNode && isShadowHost(parentNode)) { 466 if (parentNode && isShadowHost(parentNode)) {
440 var trees = scope.getShadowTrees(parentNode); 467 var trees = scope.getShadowTrees(parentNode);
441 var p = context.insertionParent; 468 var p = getInsertionParent(context);
442 for (var i = 0; i < trees.length; i++) { 469 for (var i = 0; i < trees.length; i++) {
443 if (trees[i].contains(p)) 470 if (trees[i].contains(p))
444 return p; 471 return p;
445 } 472 }
446 } 473 }
447 } 474 }
448 475
449 return getEventParent(node); 476 return getEventParent(node);
450 } 477 }
451 478
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 last = ancestor; // 3.4.6. 543 last = ancestor; // 3.4.6.
517 ancestor = calculateParents(ancestor, context, ancestors); // 3.4.7. 544 ancestor = calculateParents(ancestor, context, ancestors); // 3.4.7.
518 } 545 }
519 if (isShadowRoot(target)) // 3.5. 546 if (isShadowRoot(target)) // 3.5.
520 target = scope.getHostForShadowRoot(target); 547 target = scope.getHostForShadowRoot(target);
521 else 548 else
522 target = target.parentNode; // 3.6. 549 target = target.parentNode; // 3.6.
523 } 550 }
524 } 551 }
525 552
553 function getInsertionParent(node) {
554 return scope.insertionParentTable.get(node);
555 }
556
526 function isDistributed(node) { 557 function isDistributed(node) {
527 return node.insertionParent; 558 return getInsertionParent(node);
528 } 559 }
529 560
530 function rootOfNode(node) { 561 function rootOfNode(node) {
531 var p; 562 var p;
532 while (p = node.parentNode) { 563 while (p = node.parentNode) {
533 node = p; 564 node = p;
534 } 565 }
535 return node; 566 return node;
536 } 567 }
537 568
538 function inSameTree(a, b) { 569 function inSameTree(a, b) {
539 return rootOfNode(a) === rootOfNode(b); 570 return rootOfNode(a) === rootOfNode(b);
540 } 571 }
541 572
573 function enclosedBy(a, b) {
574 if (a === b)
575 return true;
576 if (a instanceof wrappers.ShadowRoot) {
577 var host = scope.getHostForShadowRoot(a);
578 return enclosedBy(rootOfNode(host), b);
579 }
580 return false;
581
Emily Fortuna 2013/09/05 18:19:10 remove extra line here?
Jennifer Messerly 2013/09/05 19:47:02 I submitted a pull request for upstream: https://g
582 }
583
542 function isMutationEvent(type) { 584 function isMutationEvent(type) {
543 switch (type) { 585 switch (type) {
544 case 'DOMAttrModified': 586 case 'DOMAttrModified':
545 case 'DOMAttributeNameChanged': 587 case 'DOMAttributeNameChanged':
546 case 'DOMCharacterDataModified': 588 case 'DOMCharacterDataModified':
547 case 'DOMElementNameChanged': 589 case 'DOMElementNameChanged':
548 case 'DOMNodeInserted': 590 case 'DOMNodeInserted':
549 case 'DOMNodeInsertedIntoDocument': 591 case 'DOMNodeInsertedIntoDocument':
550 case 'DOMNodeRemoved': 592 case 'DOMNodeRemoved':
551 case 'DOMNodeRemovedFromDocument': 593 case 'DOMNodeRemovedFromDocument':
(...skipping 21 matching lines...) Expand all
573 } 615 }
574 616
575 function dispatchEvent(event, originalWrapperTarget) { 617 function dispatchEvent(event, originalWrapperTarget) {
576 var eventPath = retarget(originalWrapperTarget); 618 var eventPath = retarget(originalWrapperTarget);
577 619
578 // For window load events the load event is dispatched at the window but 620 // For window load events the load event is dispatched at the window but
579 // the target is set to the document. 621 // the target is set to the document.
580 // 622 //
581 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end 623 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end
582 // 624 //
583 // TODO(arv): Find a loess hacky way to do this. 625 // TODO(arv): Find a less hacky way to do this.
584 if (event.type === 'load' && 626 if (event.type === 'load' &&
585 eventPath.length === 2 && 627 eventPath.length === 2 &&
586 eventPath[0].target instanceof wrappers.Document) { 628 eventPath[0].target instanceof wrappers.Document) {
587 eventPath.shift(); 629 eventPath.shift();
588 } 630 }
589 631
632 eventPathTable.set(event, eventPath);
633
590 if (dispatchCapturing(event, eventPath)) { 634 if (dispatchCapturing(event, eventPath)) {
591 if (dispatchAtTarget(event, eventPath)) { 635 if (dispatchAtTarget(event, eventPath)) {
592 dispatchBubbling(event, eventPath); 636 dispatchBubbling(event, eventPath);
593 } 637 }
594 } 638 }
595 639
596 eventPhaseTable.set(event, Event.NONE); 640 eventPhaseTable.set(event, Event.NONE);
597 currentTargetTable.set(event, null); 641 currentTargetTable.set(event, null);
598 642
599 return event.defaultPrevented; 643 return event.defaultPrevented;
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 Event.prototype = { 787 Event.prototype = {
744 get target() { 788 get target() {
745 return targetTable.get(this); 789 return targetTable.get(this);
746 }, 790 },
747 get currentTarget() { 791 get currentTarget() {
748 return currentTargetTable.get(this); 792 return currentTargetTable.get(this);
749 }, 793 },
750 get eventPhase() { 794 get eventPhase() {
751 return eventPhaseTable.get(this); 795 return eventPhaseTable.get(this);
752 }, 796 },
797 get path() {
798 var nodeList = new wrappers.NodeList();
799 var eventPath = eventPathTable.get(this);
800 if (eventPath) {
801 var index = 0;
802 var lastIndex = eventPath.length - 1;
803 var baseRoot = rootOfNode(currentTargetTable.get(this));
804
805 for (var i = 0; i <= lastIndex; i++) {
806 var currentTarget = eventPath[i].currentTarget;
807 var currentRoot = rootOfNode(currentTarget);
808 if (enclosedBy(baseRoot, currentRoot) &&
809 // Make sure we do not add Window to the path.
810 (i !== lastIndex || currentTarget instanceof wrappers.Node)) {
811 nodeList[index++] = currentTarget;
812 }
813 }
814 nodeList.length = index;
815 }
816 return nodeList;
817 },
753 stopPropagation: function() { 818 stopPropagation: function() {
754 stopPropagationTable.set(this, true); 819 stopPropagationTable.set(this, true);
755 }, 820 },
756 stopImmediatePropagation: function() { 821 stopImmediatePropagation: function() {
757 stopPropagationTable.set(this, true); 822 stopPropagationTable.set(this, true);
758 stopImmediatePropagationTable.set(this, true); 823 stopImmediatePropagationTable.set(this, true);
759 } 824 }
760 }; 825 };
761 registerWrapper(OriginalEvent, Event, document.createEvent('Event')); 826 registerWrapper(OriginalEvent, Event, document.createEvent('Event'));
762 827
763 function unwrapOptions(options) { 828 function unwrapOptions(options) {
764 if (!options || !options.relatedTarget) 829 if (!options || !options.relatedTarget)
765 return options; 830 return options;
766 return Object.create(options, { 831 return Object.create(options, {
767 relatedTarget: {value: unwrap(options.relatedTarget)} 832 relatedTarget: {value: unwrap(options.relatedTarget)}
768 }); 833 });
769 } 834 }
770 835
771 function registerGenericEvent(name, SuperEvent, prototype) { 836 function registerGenericEvent(name, SuperEvent, prototype) {
772 var OriginalEvent = window[name]; 837 var OriginalEvent = window[name];
773 var GenericEvent = function(type, options) { 838 var GenericEvent = function(type, options) {
774 if (type instanceof OriginalEvent) 839 if (type instanceof OriginalEvent)
775 this.impl = type; 840 this.impl = type;
776 else 841 else
777 return wrap(constructEvent(OriginalEvent, name, type, options)); 842 return wrap(constructEvent(OriginalEvent, name, type, options));
778 }; 843 };
779 GenericEvent.prototype = Object.create(SuperEvent.prototype); 844 GenericEvent.prototype = Object.create(SuperEvent.prototype);
780 if (prototype) 845 if (prototype)
781 mixin(GenericEvent.prototype, prototype); 846 mixin(GenericEvent.prototype, prototype);
782 // Firefox does not support FocusEvent 847 if (OriginalEvent) {
783 // https://bugzilla.mozilla.org/show_bug.cgi?id=855741 848 // IE does not support event constructors but FocusEvent can only be
784 if (OriginalEvent) 849 // created using new FocusEvent in Firefox.
785 registerWrapper(OriginalEvent, GenericEvent, document.createEvent(name)); 850 // https://bugzilla.mozilla.org/show_bug.cgi?id=882165
851 if (OriginalEvent.prototype['init' + name]) {
852 registerWrapper(OriginalEvent, GenericEvent,
853 document.createEvent(name));
854 } else {
855 registerWrapper(OriginalEvent, GenericEvent, new OriginalEvent('temp'));
856 }
857 }
786 return GenericEvent; 858 return GenericEvent;
787 } 859 }
788 860
789 var UIEvent = registerGenericEvent('UIEvent', Event); 861 var UIEvent = registerGenericEvent('UIEvent', Event);
790 var CustomEvent = registerGenericEvent('CustomEvent', Event); 862 var CustomEvent = registerGenericEvent('CustomEvent', Event);
791 863
792 var relatedTargetProto = { 864 var relatedTargetProto = {
793 get relatedTarget() { 865 get relatedTarget() {
794 return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget); 866 return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget);
795 } 867 }
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 } 977 }
906 978
907 // Node and Window have different internal type checks in WebKit so we cannot 979 // Node and Window have different internal type checks in WebKit so we cannot
908 // use the same method as the original function. 980 // use the same method as the original function.
909 var methodNames = [ 981 var methodNames = [
910 'addEventListener', 982 'addEventListener',
911 'removeEventListener', 983 'removeEventListener',
912 'dispatchEvent' 984 'dispatchEvent'
913 ]; 985 ];
914 986
915 [Element, Window, Document].forEach(function(constructor) { 987 [Node, Window].forEach(function(constructor) {
916 var p = constructor.prototype; 988 var p = constructor.prototype;
917 methodNames.forEach(function(name) { 989 methodNames.forEach(function(name) {
918 Object.defineProperty(p, name + '_', {value: p[name]}); 990 Object.defineProperty(p, name + '_', {value: p[name]});
919 }); 991 });
920 }); 992 });
921 993
922 function getTargetToListenAt(wrapper) { 994 function getTargetToListenAt(wrapper) {
923 if (wrapper instanceof wrappers.ShadowRoot) 995 if (wrapper instanceof wrappers.ShadowRoot)
924 wrapper = scope.getHostForShadowRoot(wrapper); 996 wrapper = scope.getHostForShadowRoot(wrapper);
925 return unwrap(wrapper); 997 return unwrap(wrapper);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 var element = wrap(originalElementFromPoint.call(document.impl, x, y)); 1064 var element = wrap(originalElementFromPoint.call(document.impl, x, y));
993 var targets = retarget(element, this) 1065 var targets = retarget(element, this)
994 for (var i = 0; i < targets.length; i++) { 1066 for (var i = 0; i < targets.length; i++) {
995 var target = targets[i]; 1067 var target = targets[i];
996 if (target.currentTarget === self) 1068 if (target.currentTarget === self)
997 return target.target; 1069 return target.target;
998 } 1070 }
999 return null; 1071 return null;
1000 } 1072 }
1001 1073
1074 /**
1075 * Returns a function that is to be used as a getter for `onfoo` properties.
1076 * @param {string} name
1077 * @return {Function}
1078 */
1079 function getEventHandlerGetter(name) {
1080 return function() {
1081 var inlineEventHandlers = eventHandlersTable.get(this);
1082 return inlineEventHandlers && inlineEventHandlers[name] &&
1083 inlineEventHandlers[name].value || null;
1084 };
1085 }
1086
1087 /**
1088 * Returns a function that is to be used as a setter for `onfoo` properties.
1089 * @param {string} name
1090 * @return {Function}
1091 */
1092 function getEventHandlerSetter(name) {
1093 var eventType = name.slice(2);
1094 return function(value) {
1095 var inlineEventHandlers = eventHandlersTable.get(this);
1096 if (!inlineEventHandlers) {
1097 inlineEventHandlers = Object.create(null);
1098 eventHandlersTable.set(this, inlineEventHandlers);
1099 }
1100
1101 var old = inlineEventHandlers[name];
1102 if (old)
1103 this.removeEventListener(eventType, old.wrapped, false);
1104
1105 if (typeof value === 'function') {
1106 var wrapped = function(e) {
1107 var rv = value.call(this, e);
1108 if (rv === false)
1109 e.preventDefault();
1110 else if (name === 'onbeforeunload' && typeof rv === 'string')
1111 e.returnValue = rv;
1112 // mouseover uses true for preventDefault but preventDefault for
1113 // mouseover is ignored by browsers these day.
1114 };
1115
1116 this.addEventListener(eventType, wrapped, false);
1117 inlineEventHandlers[name] = {
1118 value: value,
1119 wrapped: wrapped
1120 };
1121 }
1122 };
1123 }
1124
1002 scope.adjustRelatedTarget = adjustRelatedTarget; 1125 scope.adjustRelatedTarget = adjustRelatedTarget;
1003 scope.elementFromPoint = elementFromPoint; 1126 scope.elementFromPoint = elementFromPoint;
1127 scope.getEventHandlerGetter = getEventHandlerGetter;
1128 scope.getEventHandlerSetter = getEventHandlerSetter;
1004 scope.wrapEventTargetMethods = wrapEventTargetMethods; 1129 scope.wrapEventTargetMethods = wrapEventTargetMethods;
1005 scope.wrappers.CustomEvent = CustomEvent; 1130 scope.wrappers.CustomEvent = CustomEvent;
1006 scope.wrappers.Event = Event; 1131 scope.wrappers.Event = Event;
1007 scope.wrappers.EventTarget = EventTarget; 1132 scope.wrappers.EventTarget = EventTarget;
1008 scope.wrappers.FocusEvent = FocusEvent; 1133 scope.wrappers.FocusEvent = FocusEvent;
1009 scope.wrappers.MouseEvent = MouseEvent; 1134 scope.wrappers.MouseEvent = MouseEvent;
1010 scope.wrappers.MutationEvent = MutationEvent; 1135 scope.wrappers.MutationEvent = MutationEvent;
1011 scope.wrappers.UIEvent = UIEvent; 1136 scope.wrappers.UIEvent = UIEvent;
1012 1137
1013 })(this.ShadowDOMPolyfill); 1138 })(this.ShadowDOMPolyfill);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1066 'use strict'; 1191 'use strict';
1067 1192
1068 var EventTarget = scope.wrappers.EventTarget; 1193 var EventTarget = scope.wrappers.EventTarget;
1069 var NodeList = scope.wrappers.NodeList; 1194 var NodeList = scope.wrappers.NodeList;
1070 var defineWrapGetter = scope.defineWrapGetter; 1195 var defineWrapGetter = scope.defineWrapGetter;
1071 var assert = scope.assert; 1196 var assert = scope.assert;
1072 var mixin = scope.mixin; 1197 var mixin = scope.mixin;
1073 var registerWrapper = scope.registerWrapper; 1198 var registerWrapper = scope.registerWrapper;
1074 var unwrap = scope.unwrap; 1199 var unwrap = scope.unwrap;
1075 var wrap = scope.wrap; 1200 var wrap = scope.wrap;
1201 var wrapIfNeeded = scope.wrapIfNeeded;
1076 1202
1077 function assertIsNodeWrapper(node) { 1203 function assertIsNodeWrapper(node) {
1078 assert(node instanceof Node); 1204 assert(node instanceof Node);
1079 } 1205 }
1080 1206
1081 /** 1207 /**
1082 * Collects nodes from a DocumentFragment or a Node for removal followed 1208 * Collects nodes from a DocumentFragment or a Node for removal followed
1083 * by an insertion. 1209 * by an insertion.
1084 * 1210 *
1085 * This updates the internal pointers for node, previousNode and nextNode. 1211 * This updates the internal pointers for node, previousNode and nextNode.
(...skipping 26 matching lines...) Expand all
1112 } 1238 }
1113 1239
1114 if (previousNode) 1240 if (previousNode)
1115 previousNode.nextSibling_ = nodes[0]; 1241 previousNode.nextSibling_ = nodes[0];
1116 if (nextNode) 1242 if (nextNode)
1117 nextNode.previousSibling_ = nodes[nodes.length - 1]; 1243 nextNode.previousSibling_ = nodes[nodes.length - 1];
1118 1244
1119 return nodes; 1245 return nodes;
1120 } 1246 }
1121 1247
1122 function unwrapNodesForInsertion(nodes) { 1248 function ensureSameOwnerDocument(parent, child) {
1123 if (nodes.length === 1) 1249 var ownerDoc = parent.nodeType === Node.DOCUMENT_NODE ?
1250 parent : parent.ownerDocument;
1251 if (ownerDoc !== child.ownerDocument)
1252 ownerDoc.adoptNode(child);
1253 }
1254
1255 function adoptNodesIfNeeded(owner, nodes) {
1256 if (!nodes.length)
1257 return;
1258
1259 var ownerDoc = owner.ownerDocument;
1260
1261 // All nodes have the same ownerDocument when we get here.
1262 if (ownerDoc === nodes[0].ownerDocument)
1263 return;
1264
1265 for (var i = 0; i < nodes.length; i++) {
1266 scope.adoptNodeNoRemove(nodes[i], ownerDoc);
1267 }
1268 }
1269
1270 function unwrapNodesForInsertion(owner, nodes) {
1271 adoptNodesIfNeeded(owner, nodes);
1272 var length = nodes.length;
1273
1274 if (length === 1)
1124 return unwrap(nodes[0]); 1275 return unwrap(nodes[0]);
1125 1276
1126 var df = unwrap(document.createDocumentFragment()); 1277 var df = unwrap(owner.ownerDocument.createDocumentFragment());
1127 for (var i = 0; i < nodes.length; i++) { 1278 for (var i = 0; i < length; i++) {
1128 df.appendChild(unwrap(nodes[i])); 1279 df.appendChild(unwrap(nodes[i]));
1129 } 1280 }
1130 return df; 1281 return df;
1131 } 1282 }
1132 1283
1133 function removeAllChildNodes(wrapper) { 1284 function removeAllChildNodes(wrapper) {
1134 var childWrapper = wrapper.firstChild; 1285 if (wrapper.invalidateShadowRenderer()) {
1135 while (childWrapper) { 1286 var childWrapper = wrapper.firstChild;
1136 assert(childWrapper.parentNode === wrapper); 1287 while (childWrapper) {
1137 var nextSibling = childWrapper.nextSibling; 1288 assert(childWrapper.parentNode === wrapper);
1138 var childNode = unwrap(childWrapper); 1289 var nextSibling = childWrapper.nextSibling;
1139 var parentNode = childNode.parentNode; 1290 var childNode = unwrap(childWrapper);
1140 if (parentNode) 1291 var parentNode = childNode.parentNode;
1141 originalRemoveChild.call(parentNode, childNode); 1292 if (parentNode)
1142 childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.p arentNode_ = null; 1293 originalRemoveChild.call(parentNode, childNode);
1143 childWrapper = nextSibling; 1294 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
1295 childWrapper.parentNode_ = null;
1296 childWrapper = nextSibling;
1297 }
1298 wrapper.firstChild_ = wrapper.lastChild_ = null;
1299 } else {
1300 var node = unwrap(wrapper);
1301 var child = node.firstChild;
1302 var nextSibling;
1303 while (child) {
1304 nextSibling = child.nextSibling;
1305 originalRemoveChild.call(node, child);
1306 child = nextSibling;
1307 }
1144 } 1308 }
1145 wrapper.firstChild_ = wrapper.lastChild_ = null; 1309 }
1310
1311 function invalidateParent(node) {
1312 var p = node.parentNode;
1313 return p && p.invalidateShadowRenderer();
1146 } 1314 }
1147 1315
1148 var OriginalNode = window.Node; 1316 var OriginalNode = window.Node;
1149 1317
1150 /** 1318 /**
1151 * This represents a wrapper of a native DOM node. 1319 * This represents a wrapper of a native DOM node.
1152 * @param {!Node} original The original DOM node, aka, the visual DOM node. 1320 * @param {!Node} original The original DOM node, aka, the visual DOM node.
1153 * @constructor 1321 * @constructor
1154 * @extends {EventTarget} 1322 * @extends {EventTarget}
1155 */ 1323 */
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1198 var originalReplaceChild = OriginalNode.prototype.replaceChild; 1366 var originalReplaceChild = OriginalNode.prototype.replaceChild;
1199 var originalRemoveChild = OriginalNode.prototype.removeChild; 1367 var originalRemoveChild = OriginalNode.prototype.removeChild;
1200 var originalCompareDocumentPosition = 1368 var originalCompareDocumentPosition =
1201 OriginalNode.prototype.compareDocumentPosition; 1369 OriginalNode.prototype.compareDocumentPosition;
1202 1370
1203 Node.prototype = Object.create(EventTarget.prototype); 1371 Node.prototype = Object.create(EventTarget.prototype);
1204 mixin(Node.prototype, { 1372 mixin(Node.prototype, {
1205 appendChild: function(childWrapper) { 1373 appendChild: function(childWrapper) {
1206 assertIsNodeWrapper(childWrapper); 1374 assertIsNodeWrapper(childWrapper);
1207 1375
1208 this.invalidateShadowRenderer(); 1376 if (this.invalidateShadowRenderer() || invalidateParent(childWrapper)) {
1377 var previousNode = this.lastChild;
1378 var nextNode = null;
1379 var nodes = collectNodes(childWrapper, this, previousNode, nextNode);
1209 1380
1210 var previousNode = this.lastChild; 1381 this.lastChild_ = nodes[nodes.length - 1];
1211 var nextNode = null; 1382 if (!previousNode)
1212 var nodes = collectNodes(childWrapper, this, 1383 this.firstChild_ = nodes[0];
1213 previousNode, nextNode);
1214 1384
1215 this.lastChild_ = nodes[nodes.length - 1]; 1385 originalAppendChild.call(this.impl, unwrapNodesForInsertion(this, nodes) );
1216 if (!previousNode) 1386 } else {
1217 this.firstChild_ = nodes[0]; 1387 ensureSameOwnerDocument(this, childWrapper);
1388 originalAppendChild.call(this.impl, unwrap(childWrapper));
1389 }
1218 1390
1219 // TODO(arv): It is unclear if we need to update the visual DOM here. 1391 childWrapper.nodeWasAdded_();
1220 // A better aproach might be to make sure we only get here for nodes that
1221 // are related to a shadow host and then invalidate that and re-render
1222 // the host (on reflow?).
1223 originalAppendChild.call(this.impl, unwrapNodesForInsertion(nodes));
1224 1392
1225 return childWrapper; 1393 return childWrapper;
1226 }, 1394 },
1227 1395
1228 insertBefore: function(childWrapper, refWrapper) { 1396 insertBefore: function(childWrapper, refWrapper) {
1229 // TODO(arv): Unify with appendChild 1397 // TODO(arv): Unify with appendChild
1230 if (!refWrapper) 1398 if (!refWrapper)
1231 return this.appendChild(childWrapper); 1399 return this.appendChild(childWrapper);
1232 1400
1233 assertIsNodeWrapper(childWrapper); 1401 assertIsNodeWrapper(childWrapper);
1234 assertIsNodeWrapper(refWrapper); 1402 assertIsNodeWrapper(refWrapper);
1235 assert(refWrapper.parentNode === this); 1403 assert(refWrapper.parentNode === this);
1236 1404
1237 this.invalidateShadowRenderer(); 1405 if (this.invalidateShadowRenderer() || invalidateParent(childWrapper)) {
1406 var previousNode = refWrapper.previousSibling;
1407 var nextNode = refWrapper;
1408 var nodes = collectNodes(childWrapper, this, previousNode, nextNode);
1238 1409
1239 var previousNode = refWrapper.previousSibling; 1410 if (this.firstChild === refWrapper)
1240 var nextNode = refWrapper; 1411 this.firstChild_ = nodes[0];
1241 var nodes = collectNodes(childWrapper, this,
1242 previousNode, nextNode);
1243 1412
1413 // insertBefore refWrapper no matter what the parent is?
1414 var refNode = unwrap(refWrapper);
1415 var parentNode = refNode.parentNode;
1244 1416
1245 if (this.firstChild === refWrapper) 1417 if (parentNode) {
1246 this.firstChild_ = nodes[0]; 1418 originalInsertBefore.call(
1419 parentNode,
1420 unwrapNodesForInsertion(this, nodes),
1421 refNode);
1422 } else {
1423 adoptNodesIfNeeded(this, nodes);
1424 }
1425 } else {
1426 ensureSameOwnerDocument(this, childWrapper);
1427 originalInsertBefore.call(this.impl, unwrap(childWrapper),
1428 unwrap(refWrapper));
1429 }
1247 1430
1248 // insertBefore refWrapper no matter what the parent is? 1431 childWrapper.nodeWasAdded_();
1249 var refNode = unwrap(refWrapper);
1250 var parentNode = refNode.parentNode;
1251 if (parentNode) {
1252 originalInsertBefore.call(
1253 parentNode,
1254 unwrapNodesForInsertion(nodes),
1255 refNode);
1256 }
1257 1432
1258 return childWrapper; 1433 return childWrapper;
1259 }, 1434 },
1260 1435
1261 removeChild: function(childWrapper) { 1436 removeChild: function(childWrapper) {
1262 assertIsNodeWrapper(childWrapper); 1437 assertIsNodeWrapper(childWrapper);
1263 if (childWrapper.parentNode !== this) { 1438 if (childWrapper.parentNode !== this) {
1264 // TODO(arv): DOMException 1439 // TODO(arv): DOMException
1265 throw new Error('NotFoundError'); 1440 throw new Error('NotFoundError');
1266 } 1441 }
1267 1442
1268 this.invalidateShadowRenderer(); 1443 var childNode = unwrap(childWrapper);
1444 if (this.invalidateShadowRenderer()) {
1269 1445
1270 // We need to remove the real node from the DOM before updating the 1446 // We need to remove the real node from the DOM before updating the
1271 // pointers. This is so that that mutation event is dispatched before 1447 // pointers. This is so that that mutation event is dispatched before
1272 // the pointers have changed. 1448 // the pointers have changed.
1273 var thisFirstChild = this.firstChild; 1449 var thisFirstChild = this.firstChild;
1274 var thisLastChild = this.lastChild; 1450 var thisLastChild = this.lastChild;
1275 var childWrapperNextSibling = childWrapper.nextSibling; 1451 var childWrapperNextSibling = childWrapper.nextSibling;
1276 var childWrapperPreviousSibling = childWrapper.previousSibling; 1452 var childWrapperPreviousSibling = childWrapper.previousSibling;
1277 1453
1278 var childNode = unwrap(childWrapper); 1454 var parentNode = childNode.parentNode;
1279 var parentNode = childNode.parentNode; 1455 if (parentNode)
1280 if (parentNode) 1456 originalRemoveChild.call(parentNode, childNode);
1281 originalRemoveChild.call(parentNode, childNode);
1282 1457
1283 if (thisFirstChild === childWrapper) 1458 if (thisFirstChild === childWrapper)
1284 this.firstChild_ = childWrapperNextSibling; 1459 this.firstChild_ = childWrapperNextSibling;
1285 if (thisLastChild === childWrapper) 1460 if (thisLastChild === childWrapper)
1286 this.lastChild_ = childWrapperPreviousSibling; 1461 this.lastChild_ = childWrapperPreviousSibling;
1287 if (childWrapperPreviousSibling) 1462 if (childWrapperPreviousSibling)
1288 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling; 1463 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling;
1289 if (childWrapperNextSibling) 1464 if (childWrapperNextSibling) {
1290 childWrapperNextSibling.previousSibling_ = childWrapperPreviousSibling; 1465 childWrapperNextSibling.previousSibling_ =
1466 childWrapperPreviousSibling;
1467 }
1291 1468
1292 childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.p arentNode_ = null; 1469 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
1470 childWrapper.parentNode_ = undefined;
1471 } else {
1472 originalRemoveChild.call(this.impl, childNode);
1473 }
1293 1474
1294 return childWrapper; 1475 return childWrapper;
1295 }, 1476 },
1296 1477
1297 replaceChild: function(newChildWrapper, oldChildWrapper) { 1478 replaceChild: function(newChildWrapper, oldChildWrapper) {
1298 assertIsNodeWrapper(newChildWrapper); 1479 assertIsNodeWrapper(newChildWrapper);
1299 assertIsNodeWrapper(oldChildWrapper); 1480 assertIsNodeWrapper(oldChildWrapper);
1300 1481
1301 if (oldChildWrapper.parentNode !== this) { 1482 if (oldChildWrapper.parentNode !== this) {
1302 // TODO(arv): DOMException 1483 // TODO(arv): DOMException
1303 throw new Error('NotFoundError'); 1484 throw new Error('NotFoundError');
1304 } 1485 }
1305 1486
1306 this.invalidateShadowRenderer(); 1487 var oldChildNode = unwrap(oldChildWrapper);
1307 1488
1308 var previousNode = oldChildWrapper.previousSibling; 1489 if (this.invalidateShadowRenderer() ||
1309 var nextNode = oldChildWrapper.nextSibling; 1490 invalidateParent(newChildWrapper)) {
1310 if (nextNode === newChildWrapper) 1491 var previousNode = oldChildWrapper.previousSibling;
1311 nextNode = newChildWrapper.nextSibling; 1492 var nextNode = oldChildWrapper.nextSibling;
1312 var nodes = collectNodes(newChildWrapper, this, 1493 if (nextNode === newChildWrapper)
1313 previousNode, nextNode); 1494 nextNode = newChildWrapper.nextSibling;
1495 var nodes = collectNodes(newChildWrapper, this,
1496 previousNode, nextNode);
1314 1497
1315 if (this.firstChild === oldChildWrapper) 1498 if (this.firstChild === oldChildWrapper)
1316 this.firstChild_ = nodes[0]; 1499 this.firstChild_ = nodes[0];
1317 if (this.lastChild === oldChildWrapper) 1500 if (this.lastChild === oldChildWrapper)
1318 this.lastChild_ = nodes[nodes.length - 1]; 1501 this.lastChild_ = nodes[nodes.length - 1];
1319 1502
1320 oldChildWrapper.previousSibling_ = null; 1503 oldChildWrapper.previousSibling_ = oldChildWrapper.nextSibling_ =
1321 oldChildWrapper.nextSibling_ = null; 1504 oldChildWrapper.parentNode_ = undefined;
1322 oldChildWrapper.parentNode_ = null;
1323 1505
1324 // replaceChild no matter what the parent is? 1506 // replaceChild no matter what the parent is?
1325 var oldChildNode = unwrap(oldChildWrapper); 1507 if (oldChildNode.parentNode) {
1326 if (oldChildNode.parentNode) { 1508 originalReplaceChild.call(
1327 originalReplaceChild.call( 1509 oldChildNode.parentNode,
1328 oldChildNode.parentNode, 1510 unwrapNodesForInsertion(this, nodes),
1329 unwrapNodesForInsertion(nodes), 1511 oldChildNode);
1330 oldChildNode); 1512 }
1513 } else {
1514 ensureSameOwnerDocument(this, newChildWrapper);
1515 originalReplaceChild.call(this.impl, unwrap(newChildWrapper),
1516 oldChildNode);
1331 } 1517 }
1332 1518
1519 newChildWrapper.nodeWasAdded_();
1520
1333 return oldChildWrapper; 1521 return oldChildWrapper;
1334 }, 1522 },
1335 1523
1524 /**
1525 * Called after a node was added. Subclasses override this to invalidate
1526 * the renderer as needed.
1527 * @private
1528 */
1529 nodeWasAdded_: function() {},
1530
1336 hasChildNodes: function() { 1531 hasChildNodes: function() {
1337 return this.firstChild === null; 1532 return this.firstChild === null;
1338 }, 1533 },
1339 1534
1340 /** @type {Node} */ 1535 /** @type {Node} */
1341 get parentNode() { 1536 get parentNode() {
1342 // If the parentNode has not been overridden, use the original parentNode. 1537 // If the parentNode has not been overridden, use the original parentNode.
1343 return this.parentNode_ !== undefined ? 1538 return this.parentNode_ !== undefined ?
1344 this.parentNode_ : wrap(this.impl.parentNode); 1539 this.parentNode_ : wrap(this.impl.parentNode);
1345 }, 1540 },
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1379 get textContent() { 1574 get textContent() {
1380 // TODO(arv): This should fallback to this.impl.textContent if there 1575 // TODO(arv): This should fallback to this.impl.textContent if there
1381 // are no shadow trees below or above the context node. 1576 // are no shadow trees below or above the context node.
1382 var s = ''; 1577 var s = '';
1383 for (var child = this.firstChild; child; child = child.nextSibling) { 1578 for (var child = this.firstChild; child; child = child.nextSibling) {
1384 s += child.textContent; 1579 s += child.textContent;
1385 } 1580 }
1386 return s; 1581 return s;
1387 }, 1582 },
1388 set textContent(textContent) { 1583 set textContent(textContent) {
1389 removeAllChildNodes(this); 1584 if (this.invalidateShadowRenderer()) {
1390 this.invalidateShadowRenderer(); 1585 removeAllChildNodes(this);
1391 if (textContent !== '') { 1586 if (textContent !== '') {
1392 var textNode = this.impl.ownerDocument.createTextNode(textContent); 1587 var textNode = this.impl.ownerDocument.createTextNode(textContent);
1393 this.appendChild(textNode); 1588 this.appendChild(textNode);
1589 }
1590 } else {
1591 this.impl.textContent = textContent;
1394 } 1592 }
1395 }, 1593 },
1396 1594
1397 get childNodes() { 1595 get childNodes() {
1398 var wrapperList = new NodeList(); 1596 var wrapperList = new NodeList();
1399 var i = 0; 1597 var i = 0;
1400 for (var child = this.firstChild; child; child = child.nextSibling) { 1598 for (var child = this.firstChild; child; child = child.nextSibling) {
1401 wrapperList[i++] = child; 1599 wrapperList[i++] = child;
1402 } 1600 }
1403 wrapperList.length = i; 1601 wrapperList.length = i;
1404 return wrapperList; 1602 return wrapperList;
1405 }, 1603 },
1406 1604
1407 cloneNode: function(deep) { 1605 cloneNode: function(deep) {
1408 if (!this.invalidateShadowRenderer()) 1606 if (!this.invalidateShadowRenderer())
1409 return wrap(this.impl.cloneNode(deep)); 1607 return wrap(this.impl.cloneNode(deep));
1410 1608
1411 var clone = wrap(this.impl.cloneNode(false)); 1609 var clone = wrap(this.impl.cloneNode(false));
1412 if (deep) { 1610 if (deep) {
1413 for (var child = this.firstChild; child; child = child.nextSibling) { 1611 for (var child = this.firstChild; child; child = child.nextSibling) {
1414 clone.appendChild(child.cloneNode(true)); 1612 clone.appendChild(child.cloneNode(true));
1415 } 1613 }
1416 } 1614 }
1417 // TODO(arv): Some HTML elements also clone other data like value. 1615 // TODO(arv): Some HTML elements also clone other data like value.
1418 return clone; 1616 return clone;
1419 }, 1617 },
1420 1618
1421 // insertionParent is added in ShadowRender.js
1422
1423 contains: function(child) { 1619 contains: function(child) {
1424 if (!child) 1620 if (!child)
1425 return false; 1621 return false;
1426 1622
1623 child = wrapIfNeeded(child);
1624
1427 // TODO(arv): Optimize using ownerDocument etc. 1625 // TODO(arv): Optimize using ownerDocument etc.
1428 if (child === this) 1626 if (child === this)
1429 return true; 1627 return true;
1430 var parentNode = child.parentNode; 1628 var parentNode = child.parentNode;
1431 if (!parentNode) 1629 if (!parentNode)
1432 return false; 1630 return false;
1433 return this.contains(parentNode); 1631 return this.contains(parentNode);
1434 }, 1632 },
1435 1633
1436 compareDocumentPosition: function(otherNode) { 1634 compareDocumentPosition: function(otherNode) {
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
1591 return wrapperList; 1789 return wrapperList;
1592 } 1790 }
1593 }; 1791 };
1594 1792
1595 var ChildNodeInterface = { 1793 var ChildNodeInterface = {
1596 get nextElementSibling() { 1794 get nextElementSibling() {
1597 return forwardElement(this.nextSibling); 1795 return forwardElement(this.nextSibling);
1598 }, 1796 },
1599 1797
1600 get previousElementSibling() { 1798 get previousElementSibling() {
1601 return backwardsElement(this.nextSibling); 1799 return backwardsElement(this.previousSibling);
1602 } 1800 }
1603 }; 1801 };
1604 1802
1605 scope.ChildNodeInterface = ChildNodeInterface; 1803 scope.ChildNodeInterface = ChildNodeInterface;
1606 scope.ParentNodeInterface = ParentNodeInterface; 1804 scope.ParentNodeInterface = ParentNodeInterface;
1607 1805
1608 })(this.ShadowDOMPolyfill); 1806 })(this.ShadowDOMPolyfill);
1609 1807
1610 // Copyright 2013 The Polymer Authors. All rights reserved. 1808 // Copyright 2013 The Polymer Authors. All rights reserved.
1611 // Use of this source code is goverened by a BSD-style 1809 // Use of this source code is goverened by a BSD-style
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1649 (function(scope) { 1847 (function(scope) {
1650 'use strict'; 1848 'use strict';
1651 1849
1652 var ChildNodeInterface = scope.ChildNodeInterface; 1850 var ChildNodeInterface = scope.ChildNodeInterface;
1653 var GetElementsByInterface = scope.GetElementsByInterface; 1851 var GetElementsByInterface = scope.GetElementsByInterface;
1654 var Node = scope.wrappers.Node; 1852 var Node = scope.wrappers.Node;
1655 var ParentNodeInterface = scope.ParentNodeInterface; 1853 var ParentNodeInterface = scope.ParentNodeInterface;
1656 var SelectorsInterface = scope.SelectorsInterface; 1854 var SelectorsInterface = scope.SelectorsInterface;
1657 var addWrapNodeListMethod = scope.addWrapNodeListMethod; 1855 var addWrapNodeListMethod = scope.addWrapNodeListMethod;
1658 var mixin = scope.mixin; 1856 var mixin = scope.mixin;
1857 var oneOf = scope.oneOf;
1659 var registerWrapper = scope.registerWrapper; 1858 var registerWrapper = scope.registerWrapper;
1660 var wrappers = scope.wrappers; 1859 var wrappers = scope.wrappers;
1661 1860
1662 var shadowRootTable = new SideTable(); 1861 var shadowRootTable = new SideTable();
1663 var OriginalElement = window.Element; 1862 var OriginalElement = window.Element;
1664 1863
1665 var originalMatches = 1864
1666 OriginalElement.prototype.matches || 1865 var matchesName = oneOf(OriginalElement.prototype, [
1667 OriginalElement.prototype.mozMatchesSelector || 1866 'matches',
1668 OriginalElement.prototype.msMatchesSelector || 1867 'mozMatchesSelector',
1669 OriginalElement.prototype.webkitMatchesSelector; 1868 'msMatchesSelector',
1869 'webkitMatchesSelector',
1870 ]);
1871
1872 var originalMatches = OriginalElement.prototype[matchesName];
1873
1874 function invalidateRendererBasedOnAttribute(element, name) {
1875 // Only invalidate if parent node is a shadow host.
1876 var p = element.parentNode;
1877 if (!p || !p.shadowRoot)
1878 return;
1879
1880 var renderer = scope.getRendererForHost(p);
1881 if (renderer.dependsOnAttribute(name))
1882 renderer.invalidate();
1883 }
1670 1884
1671 function Element(node) { 1885 function Element(node) {
1672 Node.call(this, node); 1886 Node.call(this, node);
1673 } 1887 }
1674 Element.prototype = Object.create(Node.prototype); 1888 Element.prototype = Object.create(Node.prototype);
1675 mixin(Element.prototype, { 1889 mixin(Element.prototype, {
1676 createShadowRoot: function() { 1890 createShadowRoot: function() {
1677 var newShadowRoot = new wrappers.ShadowRoot(this); 1891 var newShadowRoot = new wrappers.ShadowRoot(this);
1678 shadowRootTable.set(this, newShadowRoot); 1892 shadowRootTable.set(this, newShadowRoot);
1679 1893
1680 scope.getRendererForHost(this); 1894 var renderer = scope.getRendererForHost(this);
1681 1895 renderer.invalidate();
1682 this.invalidateShadowRenderer(true);
1683 1896
1684 return newShadowRoot; 1897 return newShadowRoot;
1685 }, 1898 },
1686 1899
1687 get shadowRoot() { 1900 get shadowRoot() {
1688 return shadowRootTable.get(this) || null; 1901 return shadowRootTable.get(this) || null;
1689 }, 1902 },
1690 1903
1691 setAttribute: function(name, value) { 1904 setAttribute: function(name, value) {
1692 this.impl.setAttribute(name, value); 1905 this.impl.setAttribute(name, value);
1693 // This is a bit agressive. We need to invalidate if it affects 1906 invalidateRendererBasedOnAttribute(this, name);
1694 // the rendering content[select] or if it effects the value of a content 1907 },
1695 // select. 1908
1696 this.invalidateShadowRenderer(); 1909 removeAttribute: function(name) {
1910 this.impl.removeAttribute(name);
1911 invalidateRendererBasedOnAttribute(this, name);
1697 }, 1912 },
1698 1913
1699 matches: function(selector) { 1914 matches: function(selector) {
1700 return originalMatches.call(this.impl, selector); 1915 return originalMatches.call(this.impl, selector);
1701 } 1916 }
1702 }); 1917 });
1703 1918
1919 Element.prototype[matchesName] = function(selector) {
1920 return this.matches(selector);
1921 };
1922
1923 if (OriginalElement.prototype.webkitCreateShadowRoot) {
1924 Element.prototype.webkitCreateShadowRoot =
1925 Element.prototype.createShadowRoot;
1926 }
1927
1928 /**
1929 * Useful for generating the accessor pair for a property that reflects an
1930 * attribute.
1931 */
1932 function setterDirtiesAttribute(prototype, propertyName, opt_attrName) {
1933 var attrName = opt_attrName || propertyName;
1934 Object.defineProperty(prototype, propertyName, {
1935 get: function() {
1936 return this.impl[propertyName];
1937 },
1938 set: function(v) {
1939 this.impl[propertyName] = v;
1940 invalidateRendererBasedOnAttribute(this, attrName);
1941 },
1942 configurable: true,
1943 enumerable: true
1944 });
1945 }
1946
1947 setterDirtiesAttribute(Element.prototype, 'id');
1948 setterDirtiesAttribute(Element.prototype, 'className', 'class');
1949
1704 mixin(Element.prototype, ChildNodeInterface); 1950 mixin(Element.prototype, ChildNodeInterface);
1705 mixin(Element.prototype, GetElementsByInterface); 1951 mixin(Element.prototype, GetElementsByInterface);
1706 mixin(Element.prototype, ParentNodeInterface); 1952 mixin(Element.prototype, ParentNodeInterface);
1707 mixin(Element.prototype, SelectorsInterface); 1953 mixin(Element.prototype, SelectorsInterface);
1708 1954
1709 registerWrapper(OriginalElement, Element); 1955 registerWrapper(OriginalElement, Element);
1710 1956
1957 // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings
1958 // that reflect attributes.
1959 scope.matchesName = matchesName;
1711 scope.wrappers.Element = Element; 1960 scope.wrappers.Element = Element;
1712 })(this.ShadowDOMPolyfill); 1961 })(this.ShadowDOMPolyfill);
1713 1962
1714 // Copyright 2013 The Polymer Authors. All rights reserved. 1963 // Copyright 2013 The Polymer Authors. All rights reserved.
1715 // Use of this source code is goverened by a BSD-style 1964 // Use of this source code is goverened by a BSD-style
1716 // license that can be found in the LICENSE file. 1965 // license that can be found in the LICENSE file.
1717 1966
1718 (function(scope) { 1967 (function(scope) {
1719 'use strict'; 1968 'use strict';
1720 1969
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1795 var s = ''; 2044 var s = '';
1796 for (var child = node.firstChild; child; child = child.nextSibling) { 2045 for (var child = node.firstChild; child; child = child.nextSibling) {
1797 s += getOuterHTML(child); 2046 s += getOuterHTML(child);
1798 } 2047 }
1799 return s; 2048 return s;
1800 } 2049 }
1801 2050
1802 function setInnerHTML(node, value, opt_tagName) { 2051 function setInnerHTML(node, value, opt_tagName) {
1803 var tagName = opt_tagName || 'div'; 2052 var tagName = opt_tagName || 'div';
1804 node.textContent = ''; 2053 node.textContent = '';
1805 var tempElement =unwrap(node.ownerDocument.createElement(tagName)); 2054 var tempElement = unwrap(node.ownerDocument.createElement(tagName));
1806 tempElement.innerHTML = value; 2055 tempElement.innerHTML = value;
1807 var firstChild; 2056 var firstChild;
1808 while (firstChild = tempElement.firstChild) { 2057 while (firstChild = tempElement.firstChild) {
1809 node.appendChild(wrap(firstChild)); 2058 node.appendChild(wrap(firstChild));
1810 } 2059 }
1811 } 2060 }
1812 2061
1813 var OriginalHTMLElement = window.HTMLElement; 2062 var OriginalHTMLElement = window.HTMLElement;
1814 2063
1815 function HTMLElement(node) { 2064 function HTMLElement(node) {
1816 Element.call(this, node); 2065 Element.call(this, node);
1817 } 2066 }
1818 HTMLElement.prototype = Object.create(Element.prototype); 2067 HTMLElement.prototype = Object.create(Element.prototype);
1819 mixin(HTMLElement.prototype, { 2068 mixin(HTMLElement.prototype, {
1820 get innerHTML() { 2069 get innerHTML() {
1821 // TODO(arv): This should fallback to this.impl.innerHTML if there 2070 // TODO(arv): This should fallback to this.impl.innerHTML if there
1822 // are no shadow trees below or above the context node. 2071 // are no shadow trees below or above the context node.
1823 return getInnerHTML(this); 2072 return getInnerHTML(this);
1824 }, 2073 },
1825 set innerHTML(value) { 2074 set innerHTML(value) {
1826 setInnerHTML(this, value, this.tagName); 2075 if (this.invalidateShadowRenderer())
2076 setInnerHTML(this, value, this.tagName);
2077 else
2078 this.impl.innerHTML = value;
1827 }, 2079 },
1828 2080
1829 get outerHTML() { 2081 get outerHTML() {
1830 // TODO(arv): This should fallback to HTMLElement_prototype.outerHTML if t here 2082 // TODO(arv): This should fallback to HTMLElement_prototype.outerHTML if t here
1831 // are no shadow trees below or above the context node. 2083 // are no shadow trees below or above the context node.
1832 return getOuterHTML(this); 2084 return getOuterHTML(this);
1833 }, 2085 },
1834 set outerHTML(value) { 2086 set outerHTML(value) {
1835 if (!this.invalidateShadowRenderer()) { 2087 var p = this.parentNode;
2088 if (p) {
2089 p.invalidateShadowRenderer();
1836 this.impl.outerHTML = value; 2090 this.impl.outerHTML = value;
1837 } else {
1838 throw new Error('not implemented');
1839 } 2091 }
1840 } 2092 }
1841 }); 2093 });
1842 2094
1843 function getterRequiresRendering(name) { 2095 function getterRequiresRendering(name) {
1844 defineGetter(HTMLElement, name, function() { 2096 defineGetter(HTMLElement, name, function() {
1845 scope.renderAllPending(); 2097 scope.renderAllPending();
1846 return this.impl[name]; 2098 return this.impl[name];
1847 }); 2099 });
1848 } 2100 }
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
1938 'use strict'; 2190 'use strict';
1939 2191
1940 var HTMLElement = scope.wrappers.HTMLElement; 2192 var HTMLElement = scope.wrappers.HTMLElement;
1941 var mixin = scope.mixin; 2193 var mixin = scope.mixin;
1942 var registerWrapper = scope.registerWrapper; 2194 var registerWrapper = scope.registerWrapper;
1943 2195
1944 var OriginalHTMLShadowElement = window.HTMLShadowElement; 2196 var OriginalHTMLShadowElement = window.HTMLShadowElement;
1945 2197
1946 function HTMLShadowElement(node) { 2198 function HTMLShadowElement(node) {
1947 HTMLElement.call(this, node); 2199 HTMLElement.call(this, node);
1948 this.olderShadowRoot_ = null;
1949 } 2200 }
1950 HTMLShadowElement.prototype = Object.create(HTMLElement.prototype); 2201 HTMLShadowElement.prototype = Object.create(HTMLElement.prototype);
1951 mixin(HTMLShadowElement.prototype, { 2202 mixin(HTMLShadowElement.prototype, {
1952 get olderShadowRoot() {
1953 return this.olderShadowRoot_;
1954 },
1955
1956 invalidateShadowRenderer: function() {
1957 HTMLElement.prototype.invalidateShadowRenderer.call(this, true);
1958 },
1959
1960 // TODO: attribute boolean resetStyleInheritance; 2203 // TODO: attribute boolean resetStyleInheritance;
1961 }); 2204 });
1962 2205
1963 if (OriginalHTMLShadowElement) 2206 if (OriginalHTMLShadowElement)
1964 registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement); 2207 registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement);
1965 2208
1966 scope.wrappers.HTMLShadowElement = HTMLShadowElement; 2209 scope.wrappers.HTMLShadowElement = HTMLShadowElement;
1967 })(this.ShadowDOMPolyfill); 2210 })(this.ShadowDOMPolyfill);
2211
1968 // Copyright 2013 The Polymer Authors. All rights reserved. 2212 // Copyright 2013 The Polymer Authors. All rights reserved.
1969 // Use of this source code is goverened by a BSD-style 2213 // Use of this source code is goverened by a BSD-style
1970 // license that can be found in the LICENSE file. 2214 // license that can be found in the LICENSE file.
1971 2215
1972 (function(scope) { 2216 (function(scope) {
1973 'use strict'; 2217 'use strict';
1974 2218
1975 var HTMLElement = scope.wrappers.HTMLElement; 2219 var HTMLElement = scope.wrappers.HTMLElement;
1976 var getInnerHTML = scope.getInnerHTML; 2220 var getInnerHTML = scope.getInnerHTML;
1977 var mixin = scope.mixin; 2221 var mixin = scope.mixin;
1978 var registerWrapper = scope.registerWrapper; 2222 var registerWrapper = scope.registerWrapper;
1979 var setInnerHTML = scope.setInnerHTML; 2223 var setInnerHTML = scope.setInnerHTML;
2224 var unwrap = scope.unwrap;
1980 var wrap = scope.wrap; 2225 var wrap = scope.wrap;
1981 2226
1982 var contentTable = new SideTable(); 2227 var contentTable = new SideTable();
1983 var templateContentsOwnerTable = new SideTable(); 2228 var templateContentsOwnerTable = new SideTable();
1984 2229
1985 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html# dfn-template-contents-owner 2230 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html# dfn-template-contents-owner
1986 function getTemplateContentsOwner(doc) { 2231 function getTemplateContentsOwner(doc) {
1987 if (!doc.defaultView) 2232 if (!doc.defaultView)
1988 return doc; 2233 return doc;
1989 var d = templateContentsOwnerTable.get(doc); 2234 var d = templateContentsOwnerTable.get(doc);
1990 if (!d) { 2235 if (!d) {
1991 // TODO(arv): This should either be a Document or HTMLDocument depending 2236 // TODO(arv): This should either be a Document or HTMLDocument depending
1992 // on doc. 2237 // on doc.
1993 d = doc.implementation.createHTMLDocument(''); 2238 d = doc.implementation.createHTMLDocument('');
1994 while (d.lastChild) { 2239 while (d.lastChild) {
1995 d.removeChild(d.lastChild); 2240 d.removeChild(d.lastChild);
1996 } 2241 }
1997 templateContentsOwnerTable.set(doc, d); 2242 templateContentsOwnerTable.set(doc, d);
1998 } 2243 }
1999 return d; 2244 return d;
2000 } 2245 }
2001 2246
2002 function extractContent(templateElement) { 2247 function extractContent(templateElement) {
2248 // templateElement is not a wrapper here.
2003 var doc = getTemplateContentsOwner(templateElement.ownerDocument); 2249 var doc = getTemplateContentsOwner(templateElement.ownerDocument);
2004 var df = doc.createDocumentFragment(); 2250 var df = unwrap(doc.createDocumentFragment());
2005 var nextSibling;
2006 var child; 2251 var child;
2007 while (child = templateElement.firstChild) { 2252 while (child = templateElement.firstChild) {
2008 df.appendChild(child); 2253 df.appendChild(child);
2009 } 2254 }
2010 return df; 2255 return df;
2011 } 2256 }
2012 2257
2013 var OriginalHTMLTemplateElement = window.HTMLTemplateElement; 2258 var OriginalHTMLTemplateElement = window.HTMLTemplateElement;
2014 2259
2015 function HTMLTemplateElement(node) { 2260 function HTMLTemplateElement(node) {
2016 HTMLElement.call(this, node); 2261 HTMLElement.call(this, node);
2262 if (!OriginalHTMLTemplateElement) {
2263 var content = extractContent(node);
2264 contentTable.set(this, wrap(content));
2265 }
2017 } 2266 }
2018 HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype); 2267 HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);
2019 2268
2020 mixin(HTMLTemplateElement.prototype, { 2269 mixin(HTMLTemplateElement.prototype, {
2021 get content() { 2270 get content() {
2022 if (OriginalHTMLTemplateElement) 2271 if (OriginalHTMLTemplateElement)
2023 return wrap(this.impl.content); 2272 return wrap(this.impl.content);
2024 2273 return contentTable.get(this);
2025 // TODO(arv): This should be done in createCallback. I initially tried to
2026 // do this in the constructor but the wrapper is not yet created at that
2027 // point in time so we hit an iloop.
2028 var content = contentTable.get(this);
2029 if (!content) {
2030 content = extractContent(this);
2031 contentTable.set(this, content);
2032 }
2033 return content;
2034 }, 2274 },
2035 2275
2036 get innerHTML() { 2276 get innerHTML() {
2037 return getInnerHTML(this.content); 2277 return getInnerHTML(this.content);
2038 }, 2278 },
2039 set innerHTML(value) { 2279 set innerHTML(value) {
2040 setInnerHTML(this.content, value); 2280 setInnerHTML(this.content, value);
2041 this.invalidateShadowRenderer();
2042 } 2281 }
2043 2282
2044 // TODO(arv): cloneNode needs to clone content. 2283 // TODO(arv): cloneNode needs to clone content.
2045 2284
2046 }); 2285 });
2047 2286
2048 if (OriginalHTMLTemplateElement) 2287 if (OriginalHTMLTemplateElement)
2049 registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement); 2288 registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement);
2050 2289
2051 scope.wrappers.HTMLTemplateElement = HTMLTemplateElement; 2290 scope.wrappers.HTMLTemplateElement = HTMLTemplateElement;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
2117 2356
2118 var DocumentFragment = scope.wrappers.DocumentFragment; 2357 var DocumentFragment = scope.wrappers.DocumentFragment;
2119 var elementFromPoint = scope.elementFromPoint; 2358 var elementFromPoint = scope.elementFromPoint;
2120 var getInnerHTML = scope.getInnerHTML; 2359 var getInnerHTML = scope.getInnerHTML;
2121 var mixin = scope.mixin; 2360 var mixin = scope.mixin;
2122 var rewrap = scope.rewrap; 2361 var rewrap = scope.rewrap;
2123 var setInnerHTML = scope.setInnerHTML; 2362 var setInnerHTML = scope.setInnerHTML;
2124 var unwrap = scope.unwrap; 2363 var unwrap = scope.unwrap;
2125 2364
2126 var shadowHostTable = new SideTable(); 2365 var shadowHostTable = new SideTable();
2366 var nextOlderShadowTreeTable = new SideTable();
2127 2367
2128 function ShadowRoot(hostWrapper) { 2368 function ShadowRoot(hostWrapper) {
2129 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment()); 2369 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment());
2130 DocumentFragment.call(this, node); 2370 DocumentFragment.call(this, node);
2131 2371
2132 // createDocumentFragment associates the node with a wrapper 2372 // createDocumentFragment associates the node with a wrapper
2133 // DocumentFragment instance. Override that. 2373 // DocumentFragment instance. Override that.
2134 rewrap(node, this); 2374 rewrap(node, this);
2135 2375
2136 var oldShadowRoot = hostWrapper.shadowRoot; 2376 var oldShadowRoot = hostWrapper.shadowRoot;
2137 scope.nextOlderShadowTreeTable.set(this, oldShadowRoot); 2377 nextOlderShadowTreeTable.set(this, oldShadowRoot);
2138 2378
2139 shadowHostTable.set(this, hostWrapper); 2379 shadowHostTable.set(this, hostWrapper);
2140 } 2380 }
2141 ShadowRoot.prototype = Object.create(DocumentFragment.prototype); 2381 ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
2142 mixin(ShadowRoot.prototype, { 2382 mixin(ShadowRoot.prototype, {
2143 get innerHTML() { 2383 get innerHTML() {
2144 return getInnerHTML(this); 2384 return getInnerHTML(this);
2145 }, 2385 },
2146 set innerHTML(value) { 2386 set innerHTML(value) {
2147 setInnerHTML(this, value); 2387 setInnerHTML(this, value);
2148 this.invalidateShadowRenderer(); 2388 this.invalidateShadowRenderer();
2149 }, 2389 },
2150 2390
2391 get olderShadowRoot() {
2392 return nextOlderShadowTreeTable.get(this) || null;
2393 },
2394
2151 invalidateShadowRenderer: function() { 2395 invalidateShadowRenderer: function() {
2152 return shadowHostTable.get(this).invalidateShadowRenderer(); 2396 return shadowHostTable.get(this).invalidateShadowRenderer();
2153 }, 2397 },
2154 2398
2155 elementFromPoint: function(x, y) { 2399 elementFromPoint: function(x, y) {
2156 return elementFromPoint(this, this.ownerDocument, x, y); 2400 return elementFromPoint(this, this.ownerDocument, x, y);
2157 }, 2401 },
2158 2402
2159 getElementById: function(id) { 2403 getElementById: function(id) {
2160 return this.querySelector('#' + id); 2404 return this.querySelector('#' + id);
2161 } 2405 }
2162 }); 2406 });
2163 2407
2164 scope.wrappers.ShadowRoot = ShadowRoot; 2408 scope.wrappers.ShadowRoot = ShadowRoot;
2165 scope.getHostForShadowRoot = function(node) { 2409 scope.getHostForShadowRoot = function(node) {
2166 return shadowHostTable.get(node); 2410 return shadowHostTable.get(node);
2167 }; 2411 };
2168 })(this.ShadowDOMPolyfill); 2412 })(this.ShadowDOMPolyfill);
2169 // Copyright 2013 The Polymer Authors. All rights reserved. 2413 // Copyright 2013 The Polymer Authors. All rights reserved.
2170 // Use of this source code is governed by a BSD-style 2414 // Use of this source code is governed by a BSD-style
2171 // license that can be found in the LICENSE file. 2415 // license that can be found in the LICENSE file.
2172 2416
2173 (function(scope) { 2417 (function(scope) {
2174 'use strict'; 2418 'use strict';
2175 2419
2176 var HTMLContentElement = scope.wrappers.HTMLContentElement; 2420 var HTMLContentElement = scope.wrappers.HTMLContentElement;
2421 var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
2177 var Node = scope.wrappers.Node; 2422 var Node = scope.wrappers.Node;
2423 var ShadowRoot = scope.wrappers.ShadowRoot;
2178 var assert = scope.assert; 2424 var assert = scope.assert;
2425 var getHostForShadowRoot = scope.getHostForShadowRoot;
2179 var mixin = scope.mixin; 2426 var mixin = scope.mixin;
2427 var oneOf = scope.oneOf;
2180 var unwrap = scope.unwrap; 2428 var unwrap = scope.unwrap;
2181 var wrap = scope.wrap; 2429 var wrap = scope.wrap;
2182 2430
2183 /** 2431 /**
2184 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed. 2432 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed.
2185 * Up means parentNode 2433 * Up means parentNode
2186 * Sideways means previous and next sibling. 2434 * Sideways means previous and next sibling.
2187 * @param {!Node} wrapper 2435 * @param {!Node} wrapper
2188 */ 2436 */
2189 function updateWrapperUpAndSideways(wrapper) { 2437 function updateWrapperUpAndSideways(wrapper) {
(...skipping 22 matching lines...) Expand all
2212 updateWrapperDown(parentNodeWrapper); 2460 updateWrapperDown(parentNodeWrapper);
2213 } 2461 }
2214 2462
2215 // This object groups DOM operations. This is supposed to be the DOM as the 2463 // This object groups DOM operations. This is supposed to be the DOM as the
2216 // browser/render tree sees it. 2464 // browser/render tree sees it.
2217 // When changes are done to the visual DOM the logical DOM needs to be updated 2465 // When changes are done to the visual DOM the logical DOM needs to be updated
2218 // to reflect the correct tree. 2466 // to reflect the correct tree.
2219 function removeAllChildNodes(parentNodeWrapper) { 2467 function removeAllChildNodes(parentNodeWrapper) {
2220 var parentNode = unwrap(parentNodeWrapper); 2468 var parentNode = unwrap(parentNodeWrapper);
2221 updateAllChildNodes(parentNodeWrapper); 2469 updateAllChildNodes(parentNodeWrapper);
2222 parentNode.textContent = ''; 2470 if (parentNode.firstChild)
2471 parentNode.textContent = '';
2223 } 2472 }
2224 2473
2225 function appendChild(parentNodeWrapper, childWrapper) { 2474 function appendChild(parentNodeWrapper, childWrapper) {
2226 var parentNode = unwrap(parentNodeWrapper); 2475 var parentNode = unwrap(parentNodeWrapper);
2227 var child = unwrap(childWrapper); 2476 var child = unwrap(childWrapper);
2228 if (child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { 2477 if (child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
2229 updateAllChildNodes(childWrapper); 2478 updateAllChildNodes(childWrapper);
2230 2479
2231 } else { 2480 } else {
2232 remove(childWrapper); 2481 remove(childWrapper);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2267 function remove(nodeWrapper) { 2516 function remove(nodeWrapper) {
2268 var node = unwrap(nodeWrapper) 2517 var node = unwrap(nodeWrapper)
2269 var parentNode = node.parentNode; 2518 var parentNode = node.parentNode;
2270 if (parentNode) 2519 if (parentNode)
2271 removeChild(wrap(parentNode), nodeWrapper); 2520 removeChild(wrap(parentNode), nodeWrapper);
2272 } 2521 }
2273 2522
2274 var distributedChildNodesTable = new SideTable(); 2523 var distributedChildNodesTable = new SideTable();
2275 var eventParentsTable = new SideTable(); 2524 var eventParentsTable = new SideTable();
2276 var insertionParentTable = new SideTable(); 2525 var insertionParentTable = new SideTable();
2277 var nextOlderShadowTreeTable = new SideTable();
2278 var rendererForHostTable = new SideTable(); 2526 var rendererForHostTable = new SideTable();
2279 var shadowDOMRendererTable = new SideTable(); 2527 var shadowDOMRendererTable = new SideTable();
2280 2528
2281 var reprCounter = 0; 2529 var reprCounter = 0;
2282 2530
2283 function repr(node) { 2531 function repr(node) {
2284 if (!node.displayName) 2532 if (!node.displayName)
2285 node.displayName = node.nodeName + '-' + ++reprCounter; 2533 node.displayName = node.nodeName + '-' + ++reprCounter;
2286 return node.displayName; 2534 return node.displayName;
2287 } 2535 }
2288 2536
2289 function distributeChildToInsertionPoint(child, insertionPoint) { 2537 function distributeChildToInsertionPoint(child, insertionPoint) {
2290 getDistributedChildNodes(insertionPoint).push(child); 2538 getDistributedChildNodes(insertionPoint).push(child);
2291 insertionParentTable.set(child, insertionPoint); 2539 assignToInsertionPoint(child, insertionPoint);
2292 2540
2293 var eventParents = eventParentsTable.get(child); 2541 var eventParents = eventParentsTable.get(child);
2294 if (!eventParents) 2542 if (!eventParents)
2295 eventParentsTable.set(child, eventParents = []); 2543 eventParentsTable.set(child, eventParents = []);
2296 eventParents.push(insertionPoint); 2544 eventParents.push(insertionPoint);
2297 } 2545 }
2298 2546
2299 function resetDistributedChildNodes(insertionPoint) { 2547 function resetDistributedChildNodes(insertionPoint) {
2300 distributedChildNodesTable.set(insertionPoint, []); 2548 distributedChildNodesTable.set(insertionPoint, []);
2301 } 2549 }
(...skipping 24 matching lines...) Expand all
2326 var node = nodes[i]; 2574 var node = nodes[i];
2327 if (predicate(node)) { 2575 if (predicate(node)) {
2328 if (visitor(node) === false) 2576 if (visitor(node) === false)
2329 return; 2577 return;
2330 } else { 2578 } else {
2331 visit(node, predicate, visitor); 2579 visit(node, predicate, visitor);
2332 } 2580 }
2333 } 2581 }
2334 } 2582 }
2335 2583
2336 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn -distribution-algorithm
2337 function distribute(tree, pool) {
2338 var anyRemoved = false;
2339
2340 visit(tree, isActiveInsertionPoint,
2341 function(insertionPoint) {
2342 resetDistributedChildNodes(insertionPoint);
2343 for (var i = 0; i < pool.length; i++) { // 1.2
2344 var node = pool[i]; // 1.2.1
2345 if (node === undefined) // removed
2346 continue;
2347 if (matchesCriteria(node, insertionPoint)) { // 1.2.2
2348 distributeChildToInsertionPoint(node, insertionPoint); // 1.2.2.1
2349 pool[i] = undefined; // 1.2.2.2
2350 anyRemoved = true;
2351 }
2352 }
2353 });
2354
2355 if (!anyRemoved)
2356 return pool;
2357
2358 return pool.filter(function(item) {
2359 return item !== undefined;
2360 });
2361 }
2362
2363 // Matching Insertion Points 2584 // Matching Insertion Points
2364 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#mat ching-insertion-points 2585 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#mat ching-insertion-points
2365 2586
2366 // TODO(arv): Verify this... I don't remember why I picked this regexp. 2587 // TODO(arv): Verify this... I don't remember why I picked this regexp.
2367 var selectorMatchRegExp = /^[*.:#[a-zA-Z_|]/; 2588 var selectorMatchRegExp = /^[*.:#[a-zA-Z_|]/;
2368 2589
2369 var allowedPseudoRegExp = new RegExp('^:(' + [ 2590 var allowedPseudoRegExp = new RegExp('^:(' + [
2370 'link', 2591 'link',
2371 'visited', 2592 'visited',
2372 'target', 2593 'target',
2373 'enabled', 2594 'enabled',
2374 'disabled', 2595 'disabled',
2375 'checked', 2596 'checked',
2376 'indeterminate', 2597 'indeterminate',
2377 'nth-child', 2598 'nth-child',
2378 'nth-last-child', 2599 'nth-last-child',
2379 'nth-of-type', 2600 'nth-of-type',
2380 'nth-last-of-type', 2601 'nth-last-of-type',
2381 'first-child', 2602 'first-child',
2382 'last-child', 2603 'last-child',
2383 'first-of-type', 2604 'first-of-type',
2384 'last-of-type', 2605 'last-of-type',
2385 'only-of-type', 2606 'only-of-type',
2386 ].join('|') + ')'); 2607 ].join('|') + ')');
2387 2608
2388 2609
2389 function oneOf(object, propertyNames) {
2390 for (var i = 0; i < propertyNames.length; i++) {
2391 if (propertyNames[i] in object)
2392 return propertyNames[i];
2393 }
2394 }
2395
2396 /** 2610 /**
2397 * @param {Element} node 2611 * @param {Element} node
2398 * @oaram {Element} point The insertion point element. 2612 * @oaram {Element} point The insertion point element.
2399 * @return {boolean} Whether the node matches the insertion point. 2613 * @return {boolean} Whether the node matches the insertion point.
2400 */ 2614 */
2401 function matchesCriteria(node, point) { 2615 function matchesCriteria(node, point) {
2402 var select = point.getAttribute('select'); 2616 var select = point.getAttribute('select');
2403 if (!select) 2617 if (!select)
2404 return true; 2618 return true;
2405 2619
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2440 renderTimer = null; 2654 renderTimer = null;
2441 pendingDirtyRenderers.forEach(function(owner) { 2655 pendingDirtyRenderers.forEach(function(owner) {
2442 owner.render(); 2656 owner.render();
2443 }); 2657 });
2444 pendingDirtyRenderers = []; 2658 pendingDirtyRenderers = [];
2445 } 2659 }
2446 2660
2447 function ShadowRenderer(host) { 2661 function ShadowRenderer(host) {
2448 this.host = host; 2662 this.host = host;
2449 this.dirty = false; 2663 this.dirty = false;
2664 this.invalidateAttributes();
2450 this.associateNode(host); 2665 this.associateNode(host);
2451 } 2666 }
2452 2667
2668 /**
2669 * Returns existing shadow renderer for a host or creates it if it is needed.
2670 * @params {!Element} host
2671 * @return {!ShadowRenderer}
2672 */
2453 function getRendererForHost(host) { 2673 function getRendererForHost(host) {
2454 var renderer = rendererForHostTable.get(host); 2674 var renderer = rendererForHostTable.get(host);
2455 if (!renderer) { 2675 if (!renderer) {
2456 renderer = new ShadowRenderer(host); 2676 renderer = new ShadowRenderer(host);
2457 rendererForHostTable.set(host, renderer); 2677 rendererForHostTable.set(host, renderer);
2458 } 2678 }
2459 return renderer; 2679 return renderer;
2460 } 2680 }
2461 2681
2682 function getShadowRootAncestor(node) {
2683 for (; node; node = node.parentNode) {
2684 if (node instanceof ShadowRoot)
2685 return node;
2686 }
2687 return null;
2688 }
2689
2690 function getRendererForShadowRoot(shadowRoot) {
2691 return getRendererForHost(getHostForShadowRoot(shadowRoot));
2692 }
2693
2462 ShadowRenderer.prototype = { 2694 ShadowRenderer.prototype = {
2695
2463 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#r endering-shadow-trees 2696 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#r endering-shadow-trees
2464 render: function() { 2697 render: function() {
2465 if (!this.dirty) 2698 if (!this.dirty)
2466 return; 2699 return;
2467 2700
2701 this.invalidateAttributes();
2702 this.treeComposition();
2703
2468 var host = this.host; 2704 var host = this.host;
2469 this.treeComposition();
2470 var shadowDOM = host.shadowRoot; 2705 var shadowDOM = host.shadowRoot;
2471 if (!shadowDOM)
2472 return;
2473 2706
2474 this.removeAllChildNodes(this.host); 2707 this.removeAllChildNodes(this.host);
2475 2708
2476 var shadowDOMChildNodes = getChildNodesSnapshot(shadowDOM); 2709 var shadowDOMChildNodes = getChildNodesSnapshot(shadowDOM);
2477 shadowDOMChildNodes.forEach(function(node) { 2710 shadowDOMChildNodes.forEach(function(node) {
2478 this.renderNode(host, shadowDOM, node, false); 2711 this.renderNode(host, shadowDOM, node, false);
2479 }, this); 2712 }, this);
2480 2713
2481 this.dirty = false; 2714 this.dirty = false;
2482 }, 2715 },
(...skipping 16 matching lines...) Expand all
2499 renderer.render(); 2732 renderer.render();
2500 } else if (isInsertionPoint(node)) { 2733 } else if (isInsertionPoint(node)) {
2501 this.renderInsertionPoint(visualParent, tree, node, isNested); 2734 this.renderInsertionPoint(visualParent, tree, node, isNested);
2502 } else if (isShadowInsertionPoint(node)) { 2735 } else if (isShadowInsertionPoint(node)) {
2503 this.renderShadowInsertionPoint(visualParent, tree, node); 2736 this.renderShadowInsertionPoint(visualParent, tree, node);
2504 } else { 2737 } else {
2505 this.renderAsAnyDomTree(visualParent, tree, node, isNested); 2738 this.renderAsAnyDomTree(visualParent, tree, node, isNested);
2506 } 2739 }
2507 }, 2740 },
2508 2741
2509 renderAsAnyDomTree: function(visualParent, tree, child, isNested) { 2742 renderAsAnyDomTree: function(visualParent, tree, node, isNested) {
2510 this.appendChild(visualParent, child); 2743 this.appendChild(visualParent, node);
2511 2744
2512 if (isShadowHost(child)) { 2745 if (isShadowHost(node)) {
2513 render(child); 2746 render(node);
2514 } else { 2747 } else {
2515 var parent = child; 2748 var parent = node;
2516 var logicalChildNodes = getChildNodesSnapshot(parent); 2749 var logicalChildNodes = getChildNodesSnapshot(parent);
2750 // We associate the parent of a content/shadow with the renderer
2751 // because we may need to remove stale childNodes.
2752 if (shadowDOMRendererTable.get(parent))
2753 this.removeAllChildNodes(parent);
2517 logicalChildNodes.forEach(function(node) { 2754 logicalChildNodes.forEach(function(node) {
2518 this.renderNode(parent, tree, node, isNested); 2755 this.renderNode(parent, tree, node, isNested);
2519 }, this); 2756 }, this);
2520 } 2757 }
2521 }, 2758 },
2522 2759
2523 renderInsertionPoint: function(visualParent, tree, insertionPoint, isNested) { 2760 renderInsertionPoint: function(visualParent, tree, insertionPoint, isNested) {
2524 var distributedChildNodes = getDistributedChildNodes(insertionPoint); 2761 var distributedChildNodes = getDistributedChildNodes(insertionPoint);
2525 if (distributedChildNodes.length) { 2762 if (distributedChildNodes.length) {
2526 this.removeAllChildNodes(insertionPoint); 2763 this.removeAllChildNodes(insertionPoint);
2527 2764
2528 distributedChildNodes.forEach(function(child) { 2765 distributedChildNodes.forEach(function(child) {
2529 if (isInsertionPoint(child) && isNested) 2766 if (isInsertionPoint(child) && isNested)
2530 this.renderInsertionPoint(visualParent, tree, child, isNested); 2767 this.renderInsertionPoint(visualParent, tree, child, isNested);
2531 else 2768 else
2532 this.renderAsAnyDomTree(visualParent, tree, child, isNested); 2769 this.renderAsAnyDomTree(visualParent, tree, child, isNested);
2533 }, this); 2770 }, this);
2534 } else { 2771 } else {
2535 this.renderFallbackContent(visualParent, insertionPoint); 2772 this.renderFallbackContent(visualParent, insertionPoint);
2536 } 2773 }
2537 this.remove(insertionPoint); 2774 this.remove(insertionPoint);
2538 }, 2775 },
2539 2776
2540 renderShadowInsertionPoint: function(visualParent, tree, shadowInsertionPoin t) { 2777 renderShadowInsertionPoint: function(visualParent, tree, shadowInsertionPoin t) {
2541 var nextOlderTree = getNextOlderTree(tree); 2778 var nextOlderTree = tree.olderShadowRoot;
2542 if (nextOlderTree) { 2779 if (nextOlderTree) {
2543 // This makes ShadowRoot have its insertionParent be the <shadow>. 2780 assignToInsertionPoint(nextOlderTree, shadowInsertionPoint);
2544 insertionParentTable.set(nextOlderTree, shadowInsertionPoint);
2545 shadowInsertionPoint.olderShadowRoot_ = nextOlderTree;
2546 this.remove(shadowInsertionPoint); 2781 this.remove(shadowInsertionPoint);
2547 var shadowDOMChildNodes = getChildNodesSnapshot(nextOlderTree); 2782 var shadowDOMChildNodes = getChildNodesSnapshot(nextOlderTree);
2548 shadowDOMChildNodes.forEach(function(node) { 2783 shadowDOMChildNodes.forEach(function(node) {
2549 this.renderNode(visualParent, nextOlderTree, node, true); 2784 this.renderNode(visualParent, nextOlderTree, node, true);
2550 }, this); 2785 }, this);
2551 } else { 2786 } else {
2552 this.renderFallbackContent(visualParent, shadowInsertionPoint); 2787 this.renderFallbackContent(visualParent, shadowInsertionPoint);
2553 } 2788 }
2554 }, 2789 },
2555 2790
2556 renderFallbackContent: function (visualParent, fallbackHost) { 2791 renderFallbackContent: function (visualParent, fallbackHost) {
2557 var logicalChildNodes = getChildNodesSnapshot(fallbackHost); 2792 var logicalChildNodes = getChildNodesSnapshot(fallbackHost);
2793 this.associateNode(fallbackHost);
2794 this.remove(fallbackHost);
2558 logicalChildNodes.forEach(function(node) { 2795 logicalChildNodes.forEach(function(node) {
2559 this.appendChild(visualParent, node); 2796 this.appendChild(visualParent, node);
2560 }, this); 2797 }, this);
2561 }, 2798 },
2562 2799
2800 /**
2801 * Invalidates the attributes used to keep track of which attributes may
2802 * cause the renderer to be invalidated.
2803 */
2804 invalidateAttributes: function() {
2805 this.attributes = Object.create(null);
2806 },
2807
2808 /**
2809 * Parses the selector and makes this renderer dependent on the attribute
2810 * being used in the selector.
2811 * @param {string} selector
2812 */
2813 updateDependentAttributes: function(selector) {
2814 if (!selector)
2815 return;
2816
2817 var attributes = this.attributes;
2818
2819 // .class
2820 if (/\.\w+/.test(selector))
2821 attributes['class'] = true;
2822
2823 // #id
2824 if (/#\w+/.test(selector))
2825 attributes['id'] = true;
2826
2827 selector.replace(/\[\s*([^\s=\|~\]]+)/g, function(_, name) {
2828 attributes[name] = true;
2829 });
2830
2831 // Pseudo selectors have been removed from the spec.
2832 },
2833
2834 dependsOnAttribute: function(name) {
2835 return this.attributes[name];
2836 },
2837
2838 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-distribution-algorithm
2839 distribute: function(tree, pool) {
2840 var anyRemoved = false;
2841 var self = this;
2842
2843 visit(tree, isActiveInsertionPoint,
2844 function(insertionPoint) {
2845 resetDistributedChildNodes(insertionPoint);
2846 self.updateDependentAttributes(
2847 insertionPoint.getAttribute('select'));
2848
2849 for (var i = 0; i < pool.length; i++) { // 1.2
2850 var node = pool[i]; // 1.2.1
2851 if (node === undefined) // removed
2852 continue;
2853 if (matchesCriteria(node, insertionPoint)) { // 1.2.2
2854 distributeChildToInsertionPoint(node, insertionPoint); // 1.2.2 .1
2855 pool[i] = undefined; // 1.2.2.2
2856 anyRemoved = true;
2857 }
2858 }
2859 });
2860
2861 if (!anyRemoved)
2862 return pool;
2863
2864 return pool.filter(function(item) {
2865 return item !== undefined;
2866 });
2867 },
2868
2563 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-tree-composition 2869 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-tree-composition
2564 treeComposition: function () { 2870 treeComposition: function () {
2565 var shadowHost = this.host; 2871 var shadowHost = this.host;
2566 var tree = shadowHost.shadowRoot; // 1. 2872 var tree = shadowHost.shadowRoot; // 1.
2567 var pool = []; // 2. 2873 var pool = []; // 2.
2568 var shadowHostChildNodes = getChildNodesSnapshot(shadowHost); 2874 var shadowHostChildNodes = getChildNodesSnapshot(shadowHost);
2569 shadowHostChildNodes.forEach(function(child) { // 3. 2875 shadowHostChildNodes.forEach(function(child) { // 3.
2570 if (isInsertionPoint(child)) { // 3.2. 2876 if (isInsertionPoint(child)) { // 3.2.
2571 var reprojected = getDistributedChildNodes(child); // 3.2.1. 2877 var reprojected = getDistributedChildNodes(child); // 3.2.1.
2572 // if reprojected is undef... reset it? 2878 // if reprojected is undef... reset it?
2573 if (!reprojected || !reprojected.length) // 3.2.2. 2879 if (!reprojected || !reprojected.length) // 3.2.2.
2574 reprojected = getChildNodesSnapshot(child); 2880 reprojected = getChildNodesSnapshot(child);
2575 pool.push.apply(pool, reprojected); // 3.2.3. 2881 pool.push.apply(pool, reprojected); // 3.2.3.
2576 } else { 2882 } else {
2577 pool.push(child); // 3.3. 2883 pool.push(child); // 3.3.
2578 } 2884 }
2579 }); 2885 });
2580 2886
2581 var shadowInsertionPoint, point; 2887 var shadowInsertionPoint, point;
2582 while (tree) { // 4. 2888 while (tree) { // 4.
2583 // 4.1. 2889 // 4.1.
2584 shadowInsertionPoint = undefined; // Reset every iteration. 2890 shadowInsertionPoint = undefined; // Reset every iteration.
2585 visit(tree, isActiveShadowInsertionPoint, function(point) { 2891 visit(tree, isActiveShadowInsertionPoint, function(point) {
2586 shadowInsertionPoint = point; 2892 shadowInsertionPoint = point;
2587 return false; 2893 return false;
2588 }); 2894 });
2589 point = shadowInsertionPoint; 2895 point = shadowInsertionPoint;
2590 2896
2591 pool = distribute(tree, pool); // 4.2. 2897 pool = this.distribute(tree, pool); // 4.2.
2592 if (point) { // 4.3. 2898 if (point) { // 4.3.
2593 var nextOlderTree = getNextOlderTree(tree); // 4.3.1. 2899 var nextOlderTree = tree.olderShadowRoot; // 4.3.1.
2594 if (!nextOlderTree) { 2900 if (!nextOlderTree) {
2595 break; // 4.3.1.1. 2901 break; // 4.3.1.1.
2596 } else { 2902 } else {
2597 tree = nextOlderTree; // 4.3.2.2. 2903 tree = nextOlderTree; // 4.3.2.2.
2598 assignShadowTreeToShadowInsertionPoint(tree, point); // 4.3.2.2. 2904 assignToInsertionPoint(tree, point); // 4.3.2.2.
2599 continue; // 4.3.2.3. 2905 continue; // 4.3.2.3.
2600 } 2906 }
2601 } else { 2907 } else {
2602 break; // 4.4. 2908 break; // 4.4.
2603 } 2909 }
2604 } 2910 }
2605 }, 2911 },
2606 2912
2607 // Visual DOM mutation.
2608 appendChild: function(parent, child) { 2913 appendChild: function(parent, child) {
2914 // this.associateNode(child);
2915 this.associateNode(parent);
2609 appendChild(parent, child); 2916 appendChild(parent, child);
2610 this.associateNode(child);
2611 }, 2917 },
2612 2918
2613 remove: function(node) { 2919 remove: function(node) {
2920 // this.associateNode(node);
2921 this.associateNode(node.parentNode);
2614 remove(node); 2922 remove(node);
2615 this.associateNode(node);
2616 }, 2923 },
2617 2924
2618 removeAllChildNodes: function(parent) { 2925 removeAllChildNodes: function(parent) {
2926 this.associateNode(parent);
2619 removeAllChildNodes(parent); 2927 removeAllChildNodes(parent);
2620 // TODO(arv): Does this need to associate all the nodes with this renderer ?
2621 }, 2928 },
2622 2929
2623 associateNode: function(node) { 2930 associateNode: function(node) {
2624 // TODO: Clear when moved out of shadow tree.
2625 shadowDOMRendererTable.set(node, this); 2931 shadowDOMRendererTable.set(node, this);
2626 } 2932 }
2627 }; 2933 };
2628 2934
2629 function isInsertionPoint(node) { 2935 function isInsertionPoint(node) {
2630 // Should this include <shadow>? 2936 // Should this include <shadow>?
2631 return node.localName === 'content'; 2937 return node.localName === 'content';
2632 } 2938 }
2633 2939
2634 function isActiveInsertionPoint(node) { 2940 function isActiveInsertionPoint(node) {
2635 // <content> inside another <content> or <shadow> is considered inactive. 2941 // <content> inside another <content> or <shadow> is considered inactive.
2636 return node.localName === 'content'; 2942 return node.localName === 'content';
2637 } 2943 }
2638 2944
2639 function isShadowInsertionPoint(node) { 2945 function isShadowInsertionPoint(node) {
2640 return node.localName === 'shadow'; 2946 return node.localName === 'shadow';
2641 } 2947 }
2642 2948
2643 function isActiveShadowInsertionPoint(node) { 2949 function isActiveShadowInsertionPoint(node) {
2644 // <shadow> inside another <content> or <shadow> is considered inactive. 2950 // <shadow> inside another <content> or <shadow> is considered inactive.
2645 return node.localName === 'shadow'; 2951 return node.localName === 'shadow';
2646 } 2952 }
2647 2953
2648 function isShadowHost(shadowHost) { 2954 function isShadowHost(shadowHost) {
2649 return !!shadowHost.shadowRoot; 2955 return shadowHost.shadowRoot;
2650 }
2651
2652 /**
2653 * @param {WrapperShadowRoot} tree
2654 */
2655 function getNextOlderTree(tree) {
2656 return nextOlderShadowTreeTable.get(tree);
2657 } 2956 }
2658 2957
2659 function getShadowTrees(host) { 2958 function getShadowTrees(host) {
2660 var trees = []; 2959 var trees = [];
2661 2960
2662 for (var tree = host.shadowRoot; 2961 for (var tree = host.shadowRoot; tree; tree = tree.olderShadowRoot) {
2663 tree;
2664 tree = nextOlderShadowTreeTable.get(tree)) {
2665 trees.push(tree); 2962 trees.push(tree);
2666 } 2963 }
2667 return trees; 2964 return trees;
2668 } 2965 }
2669 2966
2670 function assignShadowTreeToShadowInsertionPoint(tree, point) { 2967 function assignToInsertionPoint(tree, point) {
2671 insertionParentTable.set(tree, point); 2968 insertionParentTable.set(tree, point);
2672 } 2969 }
2673 2970
2674 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ren dering-shadow-trees 2971 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ren dering-shadow-trees
2675 function render(host) { 2972 function render(host) {
2676 new ShadowRenderer(host).render(); 2973 new ShadowRenderer(host).render();
2677 }; 2974 };
2678 2975
2976 // Need to rerender shadow host when:
2977 //
2978 // - a direct child to the ShadowRoot is added or removed
2979 // - a direct child to the host is added or removed
2980 // - a new shadow root is created
2981 // - a direct child to a content/shadow element is added or removed
2982 // - a sibling to a content/shadow element is added or removed
2983 // - content[select] is changed
2984 // - an attribute in a direct child to a host is modified
2985
2986 /**
2987 * This gets called when a node was added or removed to it.
2988 */
2679 Node.prototype.invalidateShadowRenderer = function(force) { 2989 Node.prototype.invalidateShadowRenderer = function(force) {
2680 // TODO: If this is in light DOM we only need to invalidate renderer if this
2681 // is a direct child of a ShadowRoot.
2682 // Maybe we should only associate renderers with direct child nodes of a
2683 // shadow root (and all nodes in the shadow dom).
2684 var renderer = shadowDOMRendererTable.get(this); 2990 var renderer = shadowDOMRendererTable.get(this);
2685 if (!renderer) 2991 if (renderer) {
2686 return false;
2687
2688 var p;
2689 if (force || this.shadowRoot ||
2690 (p = this.parentNode) && (p.shadowRoot || p instanceof ShadowRoot)) {
2691 renderer.invalidate(); 2992 renderer.invalidate();
2993 return true;
2692 } 2994 }
2693 2995
2694 return true; 2996 return false;
2695 }; 2997 };
2696 2998
2697 HTMLContentElement.prototype.getDistributedNodes = function() { 2999 HTMLContentElement.prototype.getDistributedNodes = function() {
2698 // TODO(arv): We should associate the element with the shadow root so we 3000 var renderer = shadowDOMRendererTable.get(this);
2699 // only have to rerender this ShadowRenderer. 3001 if (renderer)
2700 renderAllPending(); 3002 renderer.render();
2701 return getDistributedChildNodes(this); 3003 return getDistributedChildNodes(this);
2702 }; 3004 };
2703 3005
2704 mixin(Node.prototype, { 3006 HTMLShadowElement.prototype.nodeWasAdded_ =
2705 get insertionParent() { 3007 HTMLContentElement.prototype.nodeWasAdded_ = function() {
2706 return insertionParentTable.get(this) || null; 3008 // Invalidate old renderer if any.
2707 } 3009 this.invalidateShadowRenderer();
2708 }); 3010
3011 var shadowRoot = getShadowRootAncestor(this);
3012 var renderer;
3013 if (shadowRoot)
3014 renderer = getRendererForShadowRoot(shadowRoot);
3015 shadowDOMRendererTable.set(this, renderer);
3016 if (renderer)
3017 renderer.invalidate();
3018 };
2709 3019
2710 scope.eventParentsTable = eventParentsTable; 3020 scope.eventParentsTable = eventParentsTable;
2711 scope.getRendererForHost = getRendererForHost; 3021 scope.getRendererForHost = getRendererForHost;
2712 scope.getShadowTrees = getShadowTrees; 3022 scope.getShadowTrees = getShadowTrees;
2713 scope.nextOlderShadowTreeTable = nextOlderShadowTreeTable; 3023 scope.insertionParentTable = insertionParentTable;
2714 scope.renderAllPending = renderAllPending; 3024 scope.renderAllPending = renderAllPending;
2715 3025
2716 // Exposed for testing 3026 // Exposed for testing
2717 scope.visual = { 3027 scope.visual = {
2718 removeAllChildNodes: removeAllChildNodes, 3028 removeAllChildNodes: removeAllChildNodes,
2719 appendChild: appendChild, 3029 appendChild: appendChild,
2720 removeChild: removeChild 3030 removeChild: removeChild
2721 }; 3031 };
2722 3032
2723 })(this.ShadowDOMPolyfill); 3033 })(this.ShadowDOMPolyfill);
2724 // Copyright 2013 The Polymer Authors. All rights reserved. 3034 // Copyright 2013 The Polymer Authors. All rights reserved.
2725 // Use of this source code is goverened by a BSD-style 3035 // Use of this source code is goverened by a BSD-style
2726 // license that can be found in the LICENSE file. 3036 // license that can be found in the LICENSE file.
2727 3037
2728 (function(scope) { 3038 (function(scope) {
2729 'use strict'; 3039 'use strict';
2730 3040
3041 var HTMLElement = scope.wrappers.HTMLElement;
3042 var assert = scope.assert;
3043 var mixin = scope.mixin;
3044 var registerWrapper = scope.registerWrapper;
3045 var unwrap = scope.unwrap;
3046 var wrap = scope.wrap;
3047
3048 var elementsWithFormProperty = [
3049 'HTMLButtonElement',
3050 'HTMLFieldSetElement',
3051 'HTMLInputElement',
3052 'HTMLKeygenElement',
3053 'HTMLLabelElement',
3054 'HTMLLegendElement',
3055 'HTMLObjectElement',
3056 'HTMLOptionElement',
3057 'HTMLOutputElement',
3058 'HTMLSelectElement',
3059 'HTMLTextAreaElement',
3060 ];
3061
3062 function createWrapperConstructor(name) {
3063 if (!window[name])
3064 return;
3065
3066 // Ensure we are not overriding an already existing constructor.
3067 assert(!scope.wrappers[name]);
3068
3069 var GeneratedWrapper = function(node) {
3070 // At this point all of them extend HTMLElement.
3071 HTMLElement.call(this, node);
3072 }
3073 GeneratedWrapper.prototype = Object.create(HTMLElement.prototype);
3074 mixin(GeneratedWrapper.prototype, {
3075 get form() {
3076 return wrap(unwrap(this).form);
3077 },
3078 });
3079
3080 registerWrapper(window[name], GeneratedWrapper,
3081 document.createElement(name.slice(4, -7)));
3082 scope.wrappers[name] = GeneratedWrapper;
3083 }
3084
3085 elementsWithFormProperty.forEach(createWrapperConstructor);
3086
3087 })(this.ShadowDOMPolyfill);
3088
3089 // Copyright 2013 The Polymer Authors. All rights reserved.
3090 // Use of this source code is goverened by a BSD-style
3091 // license that can be found in the LICENSE file.
3092
3093 (function(scope) {
3094 'use strict';
3095
2731 var GetElementsByInterface = scope.GetElementsByInterface; 3096 var GetElementsByInterface = scope.GetElementsByInterface;
2732 var Node = scope.wrappers.Node; 3097 var Node = scope.wrappers.Node;
2733 var ParentNodeInterface = scope.ParentNodeInterface; 3098 var ParentNodeInterface = scope.ParentNodeInterface;
2734 var SelectorsInterface = scope.SelectorsInterface; 3099 var SelectorsInterface = scope.SelectorsInterface;
3100 var ShadowRoot = scope.wrappers.ShadowRoot;
2735 var defineWrapGetter = scope.defineWrapGetter; 3101 var defineWrapGetter = scope.defineWrapGetter;
2736 var elementFromPoint = scope.elementFromPoint; 3102 var elementFromPoint = scope.elementFromPoint;
2737 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; 3103 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
3104 var matchesName = scope.matchesName;
2738 var mixin = scope.mixin; 3105 var mixin = scope.mixin;
2739 var registerWrapper = scope.registerWrapper; 3106 var registerWrapper = scope.registerWrapper;
2740 var unwrap = scope.unwrap; 3107 var unwrap = scope.unwrap;
2741 var wrap = scope.wrap; 3108 var wrap = scope.wrap;
2742 var wrapEventTargetMethods = scope.wrapEventTargetMethods; 3109 var wrapEventTargetMethods = scope.wrapEventTargetMethods;
2743 var wrapNodeList = scope.wrapNodeList; 3110 var wrapNodeList = scope.wrapNodeList;
2744 3111
2745 var implementationTable = new SideTable(); 3112 var implementationTable = new SideTable();
2746 3113
2747 function Document(node) { 3114 function Document(node) {
(...skipping 12 matching lines...) Expand all
2760 // directly on the instance. 3127 // directly on the instance.
2761 3128
2762 function wrapMethod(name) { 3129 function wrapMethod(name) {
2763 var original = document[name]; 3130 var original = document[name];
2764 Document.prototype[name] = function() { 3131 Document.prototype[name] = function() {
2765 return wrap(original.apply(this.impl, arguments)); 3132 return wrap(original.apply(this.impl, arguments));
2766 }; 3133 };
2767 } 3134 }
2768 3135
2769 [ 3136 [
2770 'getElementById', 3137 'createComment',
3138 'createDocumentFragment',
2771 'createElement', 3139 'createElement',
2772 'createElementNS', 3140 'createElementNS',
2773 'createTextNode',
2774 'createDocumentFragment',
2775 'createEvent', 3141 'createEvent',
2776 'createEventNS', 3142 'createEventNS',
3143 'createRange',
3144 'createTextNode',
3145 'getElementById',
2777 ].forEach(wrapMethod); 3146 ].forEach(wrapMethod);
2778 3147
2779 var originalAdoptNode = document.adoptNode; 3148 var originalAdoptNode = document.adoptNode;
2780 var originalWrite = document.write; 3149
3150 function adoptNodeNoRemove(node, doc) {
3151 originalAdoptNode.call(doc.impl, unwrap(node));
3152 adoptSubtree(node, doc);
3153 }
3154
3155 function adoptSubtree(node, doc) {
3156 if (node.shadowRoot)
3157 doc.adoptNode(node.shadowRoot);
3158 if (node instanceof ShadowRoot)
3159 adoptOlderShadowRoots(node, doc);
3160 for (var child = node.firstChild; child; child = child.nextSibling) {
3161 adoptSubtree(child, doc);
3162 }
3163 }
3164
3165 function adoptOlderShadowRoots(shadowRoot, doc) {
3166 var oldShadowRoot = shadowRoot.olderShadowRoot;
3167 if (oldShadowRoot)
3168 doc.adoptNode(oldShadowRoot);
3169 }
2781 3170
2782 mixin(Document.prototype, { 3171 mixin(Document.prototype, {
2783 adoptNode: function(node) { 3172 adoptNode: function(node) {
2784 originalAdoptNode.call(this.impl, unwrap(node)); 3173 if (node.parentNode)
3174 node.parentNode.removeChild(node);
3175 adoptNodeNoRemove(node, this);
2785 return node; 3176 return node;
2786 }, 3177 },
2787 elementFromPoint: function(x, y) { 3178 elementFromPoint: function(x, y) {
2788 return elementFromPoint(this, this, x, y); 3179 return elementFromPoint(this, this, x, y);
2789 },
2790 write: function(s) {
2791 var all = this.querySelectorAll('*');
2792 var last = all[all.length - 1];
2793 while (last.nextSibling) {
2794 last = last.nextSibling;
2795 }
2796 var p = last.parentNode;
2797 p.lastChild_ = undefined;
2798 last.nextSibling_ = undefined;
2799 originalWrite.call(this.impl, s);
2800 } 3180 }
2801 }); 3181 });
2802 3182
3183 if (document.register) {
3184 var originalRegister = document.register;
3185 Document.prototype.register = function(tagName, object) {
3186 var prototype = object.prototype;
3187
3188 // If we already used the object as a prototype for another custom
3189 // element.
3190 if (scope.nativePrototypeTable.get(prototype)) {
3191 // TODO(arv): DOMException
3192 throw new Error('NotSupportedError');
3193 }
3194
3195 // Find first object on the prototype chain that already have a native
3196 // prototype. Keep track of all the objects before that so we can create
3197 // a similar structure for the native case.
3198 var proto = Object.getPrototypeOf(prototype);
3199 var nativePrototype;
3200 var prototypes = [];
3201 while (proto) {
3202 nativePrototype = scope.nativePrototypeTable.get(proto);
3203 if (nativePrototype)
3204 break;
3205 prototypes.push(proto);
3206 proto = Object.getPrototypeOf(proto);
3207 }
3208
3209 if (!nativePrototype) {
3210 // TODO(arv): DOMException
3211 throw new Error('NotSupportedError');
3212 }
3213
3214 // This works by creating a new prototype object that is empty, but has
3215 // the native prototype as its proto. The original prototype object
3216 // passed into register is used as the wrapper prototype.
3217
3218 var newPrototype = Object.create(nativePrototype);
3219 for (var i = prototypes.length - 1; i >= 0; i--) {
3220 newPrototype = Object.create(newPrototype);
3221 }
3222
3223 // Add callbacks if present.
3224 // Names are taken from:
3225 // https://code.google.com/p/chromium/codesearch#chromium/src/third_part y/WebKit/Source/bindings/v8/CustomElementConstructorBuilder.cpp&sq=package:chrom ium&type=cs&l=156
3226 // and not from the spec since the spec is out of date.
3227 [
3228 'createdCallback',
3229 'enteredDocumentCallback',
3230 'leftDocumentCallback',
3231 'attributeChangedCallback',
3232 ].forEach(function(name) {
3233 var f = prototype[name];
3234 if (!f)
3235 return;
3236 newPrototype[name] = function() {
3237 f.apply(wrap(this), arguments);
3238 };
3239 });
3240
3241 var nativeConstructor = originalRegister.call(unwrap(this), tagName,
3242 {prototype: newPrototype});
3243
3244 function GeneratedWrapper(node) {
3245 if (!node)
3246 return document.createElement(tagName);
3247 this.impl = node;
3248 }
3249 GeneratedWrapper.prototype = prototype;
3250 GeneratedWrapper.prototype.constructor = GeneratedWrapper;
3251
3252 scope.constructorTable.set(newPrototype, GeneratedWrapper);
3253 scope.nativePrototypeTable.set(prototype, newPrototype);
3254
3255 return GeneratedWrapper;
3256 };
3257
3258 forwardMethodsToWrapper([
3259 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocume nt
3260 ], [
3261 'register',
3262 ]);
3263 }
3264
2803 // We also override some of the methods on document.body and document.head 3265 // We also override some of the methods on document.body and document.head
2804 // for convenience. 3266 // for convenience.
2805 forwardMethodsToWrapper([ 3267 forwardMethodsToWrapper([
2806 window.HTMLBodyElement, 3268 window.HTMLBodyElement,
2807 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument 3269 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
2808 window.HTMLHeadElement, 3270 window.HTMLHeadElement,
3271 window.HTMLHtmlElement,
2809 ], [ 3272 ], [
2810 'appendChild', 3273 'appendChild',
2811 'compareDocumentPosition', 3274 'compareDocumentPosition',
3275 'contains',
2812 'getElementsByClassName', 3276 'getElementsByClassName',
2813 'getElementsByTagName', 3277 'getElementsByTagName',
2814 'getElementsByTagNameNS', 3278 'getElementsByTagNameNS',
2815 'insertBefore', 3279 'insertBefore',
2816 'querySelector', 3280 'querySelector',
2817 'querySelectorAll', 3281 'querySelectorAll',
2818 'removeChild', 3282 'removeChild',
2819 'replaceChild', 3283 'replaceChild',
3284 matchesName,
2820 ]); 3285 ]);
2821 3286
2822 forwardMethodsToWrapper([ 3287 forwardMethodsToWrapper([
2823 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument 3288 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
2824 ], [ 3289 ], [
2825 'adoptNode', 3290 'adoptNode',
3291 'contains',
3292 'createComment',
2826 'createDocumentFragment', 3293 'createDocumentFragment',
2827 'createElement', 3294 'createElement',
2828 'createElementNS', 3295 'createElementNS',
2829 'createEvent', 3296 'createEvent',
2830 'createEventNS', 3297 'createEventNS',
3298 'createRange',
2831 'createTextNode', 3299 'createTextNode',
2832 'elementFromPoint', 3300 'elementFromPoint',
2833 'getElementById', 3301 'getElementById',
2834 'write',
2835 ]); 3302 ]);
2836 3303
2837 mixin(Document.prototype, GetElementsByInterface); 3304 mixin(Document.prototype, GetElementsByInterface);
2838 mixin(Document.prototype, ParentNodeInterface); 3305 mixin(Document.prototype, ParentNodeInterface);
2839 mixin(Document.prototype, SelectorsInterface); 3306 mixin(Document.prototype, SelectorsInterface);
2840 3307
2841 mixin(Document.prototype, { 3308 mixin(Document.prototype, {
2842 get implementation() { 3309 get implementation() {
2843 var implementation = implementationTable.get(this); 3310 var implementation = implementationTable.get(this);
2844 if (implementation) 3311 if (implementation)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
2891 3358
2892 forwardMethodsToWrapper([ 3359 forwardMethodsToWrapper([
2893 window.DOMImplementation, 3360 window.DOMImplementation,
2894 ], [ 3361 ], [
2895 'createDocumentType', 3362 'createDocumentType',
2896 'createDocument', 3363 'createDocument',
2897 'createHTMLDocument', 3364 'createHTMLDocument',
2898 'hasFeature', 3365 'hasFeature',
2899 ]); 3366 ]);
2900 3367
3368 scope.adoptNodeNoRemove = adoptNodeNoRemove;
3369 scope.wrappers.DOMImplementation = DOMImplementation;
2901 scope.wrappers.Document = Document; 3370 scope.wrappers.Document = Document;
2902 scope.wrappers.DOMImplementation = DOMImplementation;
2903 3371
2904 })(this.ShadowDOMPolyfill); 3372 })(this.ShadowDOMPolyfill);
2905 3373
2906 // Copyright 2013 The Polymer Authors. All rights reserved. 3374 // Copyright 2013 The Polymer Authors. All rights reserved.
2907 // Use of this source code is goverened by a BSD-style 3375 // Use of this source code is goverened by a BSD-style
2908 // license that can be found in the LICENSE file. 3376 // license that can be found in the LICENSE file.
2909 3377
2910 (function(scope) { 3378 (function(scope) {
2911 'use strict'; 3379 'use strict';
2912 3380
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
3039 3507
3040 })(this.ShadowDOMPolyfill); 3508 })(this.ShadowDOMPolyfill);
3041 3509
3042 // Copyright 2013 The Polymer Authors. All rights reserved. 3510 // Copyright 2013 The Polymer Authors. All rights reserved.
3043 // Use of this source code is goverened by a BSD-style 3511 // Use of this source code is goverened by a BSD-style
3044 // license that can be found in the LICENSE file. 3512 // license that can be found in the LICENSE file.
3045 3513
3046 (function(scope) { 3514 (function(scope) {
3047 'use strict'; 3515 'use strict';
3048 3516
3517 var registerWrapper = scope.registerWrapper;
3518 var unwrap = scope.unwrap;
3519 var unwrapIfNeeded = scope.unwrapIfNeeded;
3520 var wrap = scope.wrap;
3521
3522 var OriginalRange = window.Range;
3523
3524 function Range(impl) {
3525 this.impl = impl;
3526 }
3527 Range.prototype = {
3528 get startContainer() {
3529 return wrap(this.impl.startContainer);
3530 },
3531 get endContainer() {
3532 return wrap(this.impl.endContainer);
3533 },
3534 get commonAncestorContainer() {
3535 return wrap(this.impl.commonAncestorContainer);
3536 },
3537 setStart: function(refNode,offset) {
3538 this.impl.setStart(unwrapIfNeeded(refNode), offset);
3539 },
3540 setEnd: function(refNode,offset) {
3541 this.impl.setEnd(unwrapIfNeeded(refNode), offset);
3542 },
3543 setStartBefore: function(refNode) {
3544 this.impl.setStartBefore(unwrapIfNeeded(refNode));
3545 },
3546 setStartAfter: function(refNode) {
3547 this.impl.setStartAfter(unwrapIfNeeded(refNode));
3548 },
3549 setEndBefore: function(refNode) {
3550 this.impl.setEndBefore(unwrapIfNeeded(refNode));
3551 },
3552 setEndAfter: function(refNode) {
3553 this.impl.setEndAfter(unwrapIfNeeded(refNode));
3554 },
3555 selectNode: function(refNode) {
3556 this.impl.selectNode(unwrapIfNeeded(refNode));
3557 },
3558 selectNodeContents: function(refNode) {
3559 this.impl.selectNodeContents(unwrapIfNeeded(refNode));
3560 },
3561 compareBoundaryPoints: function(how, sourceRange) {
3562 return this.impl.compareBoundaryPoints(how, unwrap(sourceRange));
3563 },
3564 extractContents: function() {
3565 return wrap(this.impl.extractContents());
3566 },
3567 cloneContents: function() {
3568 return wrap(this.impl.cloneContents());
3569 },
3570 insertNode: function(node) {
3571 this.impl.insertNode(unwrapIfNeeded(node));
3572 },
3573 surroundContents: function(newParent) {
3574 this.impl.surroundContents(unwrapIfNeeded(newParent));
3575 },
3576 cloneRange: function() {
3577 return wrap(this.impl.cloneRange());
3578 },
3579 isPointInRange: function(node, offset) {
3580 return this.impl.isPointInRange(unwrapIfNeeded(node), offset);
3581 },
3582 comparePoint: function(node, offset) {
3583 return this.impl.comparePoint(unwrapIfNeeded(node), offset);
3584 },
3585 intersectsNode: function(node) {
3586 return this.impl.intersectsNode(unwrapIfNeeded(node));
3587 }
3588 };
3589
3590 // IE9 does not have createContextualFragment.
3591 if (OriginalRange.prototype.createContextualFragment) {
3592 Range.prototype.createContextualFragment = function(html) {
3593 return wrap(this.impl.createContextualFragment(html));
3594 };
3595 }
3596
3597 registerWrapper(window.Range, Range);
3598
3599 scope.wrappers.Range = Range;
3600
3601 })(this.ShadowDOMPolyfill);
3602
3603 // Copyright 2013 The Polymer Authors. All rights reserved.
3604 // Use of this source code is goverened by a BSD-style
3605 // license that can be found in the LICENSE file.
3606
3607 (function(scope) {
3608 'use strict';
3609
3049 var isWrapperFor = scope.isWrapperFor; 3610 var isWrapperFor = scope.isWrapperFor;
3050 3611
3051 // This is a list of the elements we currently override the global constructor 3612 // This is a list of the elements we currently override the global constructor
3052 // for. 3613 // for.
3053 var elements = { 3614 var elements = {
3054 'a': 'HTMLAnchorElement', 3615 'a': 'HTMLAnchorElement',
3055 'applet': 'HTMLAppletElement', 3616 'applet': 'HTMLAppletElement',
3056 'area': 'HTMLAreaElement', 3617 'area': 'HTMLAreaElement',
3057 'audio': 'HTMLAudioElement', 3618 'audio': 'HTMLAudioElement',
3058 'br': 'HTMLBRElement', 3619 'br': 'HTMLBRElement',
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
3164 }); 3725 });
3165 3726
3166 //TODO(sjmiles): review method alias with Arv 3727 //TODO(sjmiles): review method alias with Arv
3167 HTMLElement.prototype.webkitCreateShadowRoot = 3728 HTMLElement.prototype.webkitCreateShadowRoot =
3168 HTMLElement.prototype.createShadowRoot; 3729 HTMLElement.prototype.createShadowRoot;
3169 3730
3170 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?) 3731 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?)
3171 window.dartExperimentalFixupGetTag = function(originalGetTag) { 3732 window.dartExperimentalFixupGetTag = function(originalGetTag) {
3172 var NodeList = ShadowDOMPolyfill.wrappers.NodeList; 3733 var NodeList = ShadowDOMPolyfill.wrappers.NodeList;
3173 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot; 3734 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot;
3174 var isWrapper = ShadowDOMPolyfill.isWrapper; 3735 var unwrapIfNeeded = ShadowDOMPolyfill.unwrapIfNeeded;
3175 var unwrap = ShadowDOMPolyfill.unwrap;
3176 function getTag(obj) { 3736 function getTag(obj) {
3737 // TODO(jmesserly): do we still need these?
3177 if (obj instanceof NodeList) return 'NodeList'; 3738 if (obj instanceof NodeList) return 'NodeList';
3178 if (obj instanceof ShadowRoot) return 'ShadowRoot'; 3739 if (obj instanceof ShadowRoot) return 'ShadowRoot';
3179 if (obj instanceof MutationRecord) return 'MutationRecord'; 3740 if (obj instanceof MutationRecord) return 'MutationRecord';
3180 if (obj instanceof MutationObserver) return 'MutationObserver'; 3741 if (obj instanceof MutationObserver) return 'MutationObserver';
3181 3742
3182 if (isWrapper(obj)) { 3743 var unwrapped = unwrapIfNeeded(obj);
3183 obj = unwrap(obj); 3744 if (obj !== unwrapped) {
3184 3745 // Fix up class names for Firefox.
3185 // Fix up class names for Firefox. For some of them like 3746 // For some of them (like HTMLFormElement and HTMLInputElement),
3186 // HTMLFormElement and HTMLInputElement, the "constructor" property of 3747 // the "constructor" property of the unwrapped nodes points at the
3187 // the unwrapped nodes points at the wrapper for some reason. 3748 // wrapper.
3188 // TODO(jmesserly): figure out why this is happening. 3749 // Note: it is safe to check for the GeneratedWrapper string because
3750 // we know it is some kind of Shadow DOM wrapper object.
3189 var ctor = obj.constructor; 3751 var ctor = obj.constructor;
3190 if (ctor && ctor._ShadowDOMPolyfill$isGeneratedWrapper) { 3752 if (ctor && ctor.name == 'GeneratedWrapper') {
3191 var name = ctor._ShadowDOMPolyfill$cacheTag_; 3753 var name = ctor._ShadowDOMPolyfill$cacheTag_;
3192 if (!name) { 3754 if (!name) {
3193 name = Object.prototype.toString.call(obj); 3755 name = Object.prototype.toString.call(unwrapped);
3194 name = name.substring(8, name.length - 1); 3756 name = name.substring(8, name.length - 1);
3195 ctor._ShadowDOMPolyfill$cacheTag_ = name; 3757 ctor._ShadowDOMPolyfill$cacheTag_ = name;
3196 } 3758 }
3197 return name; 3759 return name;
3198 } 3760 }
3761
3762 obj = unwrapped;
3199 } 3763 }
3200 return originalGetTag(obj); 3764 return originalGetTag(obj);
3201 } 3765 }
3202 3766
3203 return getTag; 3767 return getTag;
3204 }; 3768 };
3205 })(); 3769 })();
3206 3770
3207 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 3771 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
3208 // for details. All rights reserved. Use of this source code is governed by a 3772 // for details. All rights reserved. Use of this source code is governed by a
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
3722 css.push(cssRules[i].cssText); 4286 css.push(cssRules[i].cssText);
3723 } 4287 }
3724 return css.join('\n\n'); 4288 return css.join('\n\n');
3725 } 4289 }
3726 4290
3727 // exports 4291 // exports
3728 scope.ShadowCSS.shimShadowDOMStyling2 = shimShadowDOMStyling2; 4292 scope.ShadowCSS.shimShadowDOMStyling2 = shimShadowDOMStyling2;
3729 })(window.Platform); 4293 })(window.Platform);
3730 4294
3731 } 4295 }
OLDNEW
« no previous file with comments | « no previous file | pkg/shadow_dom/lib/shadow_dom.min.js » ('j') | pkg/shadow_dom/lib/shadow_dom.min.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698