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

Side by Side Diff: lib/shadowdom.debug.js

Issue 22962005: Merge pull request #581 from kevmoo/polymer (Closed) Base URL: https://github.com/dart-lang/web-ui.git@polymer
Patch Set: Created 7 years, 4 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
« no previous file with comments | « lib/scoped_css.dart ('k') | lib/shadowdom.min.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 if ((!HTMLElement.prototype.createShadowRoot &&
2 !HTMLElement.prototype.webkitCreateShadowRoot) ||
3 window.__forceShadowDomPolyfill) {
4
5 /*
6 * Copyright 2013 The Polymer Authors. All rights reserved.
7 * Use of this source code is governed by a BSD-style
8 * license that can be found in the LICENSE file.
9 */
10 (function() {
11 // TODO(jmesserly): fix dart:html to use unprefixed name
12 if (Element.prototype.webkitCreateShadowRoot) {
13 Element.prototype.webkitCreateShadowRoot = function() {
14 return window.ShadowDOMPolyfill.wrapIfNeeded(this).createShadowRoot();
15 };
16 }
17 })();
18
19 /*
20 * Copyright 2012 The Polymer Authors. All rights reserved.
21 * Use of this source code is goverened by a BSD-style
22 * license that can be found in the LICENSE file.
23 */
24
25 // SideTable is a weak map where possible. If WeakMap is not available the
26 // association is stored as an expando property.
27 var SideTable;
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) {
30 SideTable = WeakMap;
31 } else {
32 (function() {
33 var defineProperty = Object.defineProperty;
34 var hasOwnProperty = Object.hasOwnProperty;
35 var counter = new Date().getTime() % 1e9;
36
37 SideTable = function() {
38 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
39 };
40
41 SideTable.prototype = {
42 set: function(key, value) {
43 defineProperty(key, this.name, {value: value, writable: true});
44 },
45 get: function(key) {
46 return hasOwnProperty.call(key, this.name) ? key[this.name] : undefined;
47 },
48 delete: function(key) {
49 this.set(key, undefined);
50 }
51 }
52 })();
53 }
54
55 // Copyright 2012 The Polymer Authors. All rights reserved.
56 // Use of this source code is goverened by a BSD-style
57 // license that can be found in the LICENSE file.
58
59 var ShadowDOMPolyfill = {};
60
61 (function(scope) {
62 'use strict';
63
64 var wrapperTable = new SideTable();
65 var constructorTable = new SideTable();
66 var wrappers = Object.create(null);
67
68 function assert(b) {
69 if (!b)
70 throw new Error('Assertion failed');
71 };
72
73 function mixin(to, from) {
74 Object.getOwnPropertyNames(from).forEach(function(name) {
75 Object.defineProperty(to, name,
76 Object.getOwnPropertyDescriptor(from, name));
77 });
78 return to;
79 };
80
81 function mixinStatics(to, from) {
82 Object.getOwnPropertyNames(from).forEach(function(name) {
83 switch (name) {
84 case 'arguments':
85 case 'caller':
86 case 'length':
87 case 'name':
88 case 'prototype':
89 case 'toString':
90 return;
91 }
92 Object.defineProperty(to, name,
93 Object.getOwnPropertyDescriptor(from, name));
94 });
95 return to;
96 };
97
98 // Mozilla's old DOM bindings are bretty busted:
99 // https://bugzilla.mozilla.org/show_bug.cgi?id=855844
100 // Make sure they are create before we start modifying things.
101 Object.getOwnPropertyNames(window);
102
103 function getWrapperConstructor(node) {
104 var nativePrototype = node.__proto__ || Object.getPrototypeOf(node);
105 var wrapperConstructor = constructorTable.get(nativePrototype);
106 if (wrapperConstructor)
107 return wrapperConstructor;
108
109 var parentWrapperConstructor = getWrapperConstructor(nativePrototype);
110
111 var GeneratedWrapper = createWrapperConstructor(parentWrapperConstructor);
112 registerInternal(nativePrototype, GeneratedWrapper, node);
113
114 return GeneratedWrapper;
115 }
116
117 function addForwardingProperties(nativePrototype, wrapperPrototype) {
118 installProperty(nativePrototype, wrapperPrototype, true);
119 }
120
121 function registerInstanceProperties(wrapperPrototype, instanceObject) {
122 installProperty(instanceObject, wrapperPrototype, false);
123 }
124
125 var isFirefox = /Firefox/.test(navigator.userAgent);
126
127 // This is used as a fallback when getting the descriptor fails in
128 // installProperty.
129 var dummyDescriptor = {
130 get: function() {},
131 set: function(v) {},
132 configurable: true,
133 enumerable: true
134 };
135
136 function installProperty(source, target, allowMethod) {
137 Object.getOwnPropertyNames(source).forEach(function(name) {
138 if (name in target)
139 return;
140
141 if (isFirefox) {
142 // Tickle Firefox's old bindings.
143 source.__lookupGetter__(name);
144 }
145 var descriptor;
146 try {
147 descriptor = Object.getOwnPropertyDescriptor(source, name);
148 } catch (ex) {
149 // JSC and V8 both use data properties instead accessors which can cause
150 // getting the property desciptor throw an exception.
151 // https://bugs.webkit.org/show_bug.cgi?id=49739
152 descriptor = dummyDescriptor;
153 }
154 var getter, setter;
155 if (allowMethod && typeof descriptor.value === 'function') {
156 target[name] = function() {
157 return this.impl[name].apply(this.impl, arguments);
158 };
159 return;
160 }
161
162 getter = function() {
163 return this.impl[name];
164 };
165
166 if (descriptor.writable || descriptor.set) {
167 setter = function(value) {
168 this.impl[name] = value;
169 };
170 }
171
172 Object.defineProperty(target, name, {
173 get: getter,
174 set: setter,
175 configurable: descriptor.configurable,
176 enumerable: descriptor.enumerable
177 });
178 });
179 }
180
181 /**
182 * @param {Function} nativeConstructor
183 * @param {Function} wrapperConstructor
184 * @param {string|Object=} opt_instance If present, this is used to extract
185 * properties from an instance object. If this is a string
186 * |document.createElement| is used to create an instance.
187 */
188 function register(nativeConstructor, wrapperConstructor, opt_instance) {
189 var nativePrototype = nativeConstructor.prototype;
190 registerInternal(nativePrototype, wrapperConstructor, opt_instance);
191 mixinStatics(wrapperConstructor, nativeConstructor);
192 }
193
194 function registerInternal(nativePrototype, wrapperConstructor, opt_instance) {
195 var wrapperPrototype = wrapperConstructor.prototype;
196 assert(constructorTable.get(nativePrototype) === undefined);
197 constructorTable.set(nativePrototype, wrapperConstructor);
198 addForwardingProperties(nativePrototype, wrapperPrototype);
199 if (opt_instance)
200 registerInstanceProperties(wrapperPrototype, opt_instance);
201 }
202
203 function isWrapperFor(wrapperConstructor, nativeConstructor) {
204 return constructorTable.get(nativeConstructor.prototype) ===
205 wrapperConstructor;
206 }
207
208 /**
209 * Creates a generic wrapper constructor based on |object| and its
210 * constructor.
211 * Sometimes the constructor does not have an associated instance
212 * (CharacterData for example). In that case you can pass the constructor that
213 * you want to map the object to using |opt_nativeConstructor|.
214 * @param {Node} object
215 * @param {Function=} opt_nativeConstructor
216 * @return {Function} The generated constructor.
217 */
218 function registerObject(object) {
219 var nativePrototype = Object.getPrototypeOf(object);
220
221 var superWrapperConstructor = getWrapperConstructor(nativePrototype);
222 var GeneratedWrapper = createWrapperConstructor(superWrapperConstructor);
223 registerInternal(nativePrototype, GeneratedWrapper, object);
224
225 return GeneratedWrapper;
226 }
227
228 function createWrapperConstructor(superWrapperConstructor) {
229 function GeneratedWrapper(node) {
230 superWrapperConstructor.call(this, node);
231 }
232 GeneratedWrapper.prototype =
233 Object.create(superWrapperConstructor.prototype);
234 GeneratedWrapper.prototype.constructor = GeneratedWrapper;
235
236 return GeneratedWrapper;
237 }
238
239 var OriginalDOMImplementation = DOMImplementation;
240 var OriginalEvent = Event;
241 var OriginalNode = Node;
242 var OriginalWindow = Window;
243
244 function isWrapper(object) {
245 return object instanceof wrappers.EventTarget ||
246 object instanceof wrappers.Event ||
247 object instanceof wrappers.DOMImplementation;
248 }
249
250 function isNative(object) {
251 return object instanceof OriginalNode ||
252 object instanceof OriginalEvent ||
253 object instanceof OriginalWindow ||
254 object instanceof OriginalDOMImplementation;
255 }
256
257 /**
258 * Wraps a node in a WrapperNode. If there already exists a wrapper for the
259 * |node| that wrapper is returned instead.
260 * @param {Node} node
261 * @return {WrapperNode}
262 */
263 function wrap(impl) {
264 if (impl === null)
265 return null;
266
267 assert(isNative(impl));
268 var wrapper = wrapperTable.get(impl);
269 if (!wrapper) {
270 var wrapperConstructor = getWrapperConstructor(impl);
271 wrapper = new wrapperConstructor(impl);
272 wrapperTable.set(impl, wrapper);
273 }
274 return wrapper;
275 }
276
277 /**
278 * Unwraps a wrapper and returns the node it is wrapping.
279 * @param {WrapperNode} wrapper
280 * @return {Node}
281 */
282 function unwrap(wrapper) {
283 if (wrapper === null)
284 return null;
285 assert(isWrapper(wrapper));
286 return wrapper.impl;
287 }
288
289 /**
290 * Unwraps object if it is a wrapper.
291 * @param {Object} object
292 * @return {Object} The native implementation object.
293 */
294 function unwrapIfNeeded(object) {
295 return object && isWrapper(object) ? unwrap(object) : object;
296 }
297
298 /**
299 * Wraps object if it is not a wrapper.
300 * @param {Object} object
301 * @return {Object} The wrapper for object.
302 */
303 function wrapIfNeeded(object) {
304 return object && !isWrapper(object) ? wrap(object) : object;
305 }
306
307 /**
308 * Overrides the current wrapper (if any) for node.
309 * @param {Node} node
310 * @param {WrapperNode=} wrapper If left out the wrapper will be created as
311 * needed next time someone wraps the node.
312 */
313 function rewrap(node, wrapper) {
314 if (wrapper === null)
315 return;
316 assert(isNative(node));
317 assert(wrapper === undefined || isWrapper(wrapper));
318 wrapperTable.set(node, wrapper);
319 }
320
321 function defineGetter(constructor, name, getter) {
322 Object.defineProperty(constructor.prototype, name, {
323 get: getter,
324 configurable: true,
325 enumerable: true
326 });
327 }
328
329 function defineWrapGetter(constructor, name) {
330 defineGetter(constructor, name, function() {
331 return wrap(this.impl[name]);
332 });
333 }
334
335 /**
336 * Forwards existing methods on the native object to the wrapper methods.
337 * This does not wrap any of the arguments or the return value since the
338 * wrapper implementation already takes care of that.
339 * @param {Array.<Function>} constructors
340 * @parem {Array.<string>} names
341 */
342 function forwardMethodsToWrapper(constructors, names) {
343 constructors.forEach(function(constructor) {
344 names.forEach(function(name) {
345 constructor.prototype[name] = function() {
346 var w = wrap(this);
347 return w[name].apply(w, arguments);
348 };
349 });
350 });
351 }
352
353 scope.assert = assert;
354 scope.defineGetter = defineGetter;
355 scope.defineWrapGetter = defineWrapGetter;
356 scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
357 scope.isWrapper = isWrapper;
358 scope.isWrapperFor = isWrapperFor;
359 scope.mixin = mixin;
360 scope.registerObject = registerObject;
361 scope.registerWrapper = register;
362 scope.rewrap = rewrap;
363 scope.unwrap = unwrap;
364 scope.unwrapIfNeeded = unwrapIfNeeded;
365 scope.wrap = wrap;
366 scope.wrapIfNeeded = wrapIfNeeded;
367 scope.wrappers = wrappers;
368
369 })(this.ShadowDOMPolyfill);
370 // Copyright 2013 The Polymer Authors. All rights reserved.
371 // Use of this source code is goverened by a BSD-style
372 // license that can be found in the LICENSE file.
373
374 (function(scope) {
375 'use strict';
376
377 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
378 var mixin = scope.mixin;
379 var registerWrapper = scope.registerWrapper;
380 var unwrap = scope.unwrap;
381 var wrap = scope.wrap;
382 var wrappers = scope.wrappers;
383
384 var wrappedFuns = new SideTable();
385 var listenersTable = new SideTable();
386 var handledEventsTable = new SideTable();
387 var targetTable = new SideTable();
388 var currentTargetTable = new SideTable();
389 var relatedTargetTable = new SideTable();
390 var eventPhaseTable = new SideTable();
391 var stopPropagationTable = new SideTable();
392 var stopImmediatePropagationTable = new SideTable();
393
394 function isShadowRoot(node) {
395 return node instanceof wrappers.ShadowRoot;
396 }
397
398 function isInsertionPoint(node) {
399 var localName = node.localName;
400 return localName === 'content' || localName === 'shadow';
401 }
402
403 function isShadowHost(node) {
404 return !!node.shadowRoot;
405 }
406
407 function getEventParent(node) {
408 var dv;
409 return node.parentNode || (dv = node.defaultView) && wrap(dv) || null;
410 }
411
412 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-parent
413 function calculateParents(node, context, ancestors) {
414 if (ancestors.length)
415 return ancestors.shift();
416
417 // 1.
418 if (isShadowRoot(node))
419 return node.insertionParent || scope.getHostForShadowRoot(node);
420
421 // 2.
422 var eventParents = scope.eventParentsTable.get(node);
423 if (eventParents) {
424 // Copy over the remaining event parents for next iteration.
425 for (var i = 1; i < eventParents.length; i++) {
426 ancestors[i - 1] = eventParents[i];
427 }
428 return eventParents[0];
429 }
430
431 // 3.
432 if (context && isInsertionPoint(node)) {
433 var parentNode = node.parentNode;
434 if (parentNode && isShadowHost(parentNode)) {
435 var trees = scope.getShadowTrees(parentNode);
436 var p = context.insertionParent;
437 for (var i = 0; i < trees.length; i++) {
438 if (trees[i].contains(p))
439 return p;
440 }
441 }
442 }
443
444 return getEventParent(node);
445 }
446
447 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ev ent-retargeting
448 function retarget(node) {
449 var stack = []; // 1.
450 var ancestor = node; // 2.
451 var targets = [];
452 var ancestors = [];
453 while (ancestor) { // 3.
454 var context = null; // 3.2.
455 // TODO(arv): Change order of these. If the stack is empty we always end
456 // up pushing ancestor, no matter what.
457 if (isInsertionPoint(ancestor)) { // 3.1.
458 context = topMostNotInsertionPoint(stack); // 3.1.1.
459 var top = stack[stack.length - 1] || ancestor; // 3.1.2.
460 stack.push(top);
461 } else if (!stack.length) {
462 stack.push(ancestor); // 3.3.
463 }
464 var target = stack[stack.length - 1]; // 3.4.
465 targets.push({target: target, currentTarget: ancestor}); // 3.5.
466 if (isShadowRoot(ancestor)) // 3.6.
467 stack.pop(); // 3.6.1.
468
469 ancestor = calculateParents(ancestor, context, ancestors); // 3.7.
470 }
471 return targets;
472 }
473
474 function topMostNotInsertionPoint(stack) {
475 for (var i = stack.length - 1; i >= 0; i--) {
476 if (!isInsertionPoint(stack[i]))
477 return stack[i];
478 }
479 return null;
480 }
481
482 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-related-target
483 function adjustRelatedTarget(target, related) {
484 var ancestors = [];
485 while (target) { // 3.
486 var stack = []; // 3.1.
487 var ancestor = related; // 3.2.
488 var last = undefined; // 3.3. Needs to be reset every iteration.
489 while (ancestor) {
490 var context = null;
491 if (!stack.length) {
492 stack.push(ancestor);
493 } else {
494 if (isInsertionPoint(ancestor)) { // 3.4.3.
495 context = topMostNotInsertionPoint(stack);
496 // isDistributed is more general than checking whether last is
497 // assigned into ancestor.
498 if (isDistributed(last)) { // 3.4.3.2.
499 var head = stack[stack.length - 1];
500 stack.push(head);
501 }
502 }
503 }
504
505 if (inSameTree(ancestor, target)) // 3.4.4.
506 return stack[stack.length - 1];
507
508 if (isShadowRoot(ancestor)) // 3.4.5.
509 stack.pop();
510
511 last = ancestor; // 3.4.6.
512 ancestor = calculateParents(ancestor, context, ancestors); // 3.4.7.
513 }
514 if (isShadowRoot(target)) // 3.5.
515 target = scope.getHostForShadowRoot(target);
516 else
517 target = target.parentNode; // 3.6.
518 }
519 }
520
521 function isDistributed(node) {
522 return node.insertionParent;
523 }
524
525 function rootOfNode(node) {
526 var p;
527 while (p = node.parentNode) {
528 node = p;
529 }
530 return node;
531 }
532
533 function inSameTree(a, b) {
534 return rootOfNode(a) === rootOfNode(b);
535 }
536
537 function isMutationEvent(type) {
538 switch (type) {
539 case 'DOMAttrModified':
540 case 'DOMAttributeNameChanged':
541 case 'DOMCharacterDataModified':
542 case 'DOMElementNameChanged':
543 case 'DOMNodeInserted':
544 case 'DOMNodeInsertedIntoDocument':
545 case 'DOMNodeRemoved':
546 case 'DOMNodeRemovedFromDocument':
547 case 'DOMSubtreeModified':
548 return true;
549 }
550 return false;
551 }
552
553 function dispatchOriginalEvent(originalEvent) {
554 // Make sure this event is only dispatched once.
555 if (handledEventsTable.get(originalEvent))
556 return;
557 handledEventsTable.set(originalEvent, true);
558
559 // Don't do rendering if this is a mutation event since rendering might
560 // mutate the DOM which would fire more events and we would most likely
561 // just iloop.
562 if (!isMutationEvent(originalEvent.type))
563 scope.renderAllPending();
564
565 var target = wrap(originalEvent.target);
566 var event = wrap(originalEvent);
567 return dispatchEvent(event, target);
568 }
569
570 function dispatchEvent(event, originalWrapperTarget) {
571 var eventPath = retarget(originalWrapperTarget);
572
573 // For window load events the load event is dispatched at the window but
574 // the target is set to the document.
575 //
576 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end
577 //
578 // TODO(arv): Find a loess hacky way to do this.
579 if (event.type === 'load' &&
580 eventPath.length === 2 &&
581 eventPath[0].target instanceof wrappers.Document) {
582 eventPath.shift();
583 }
584
585 if (dispatchCapturing(event, eventPath)) {
586 if (dispatchAtTarget(event, eventPath)) {
587 dispatchBubbling(event, eventPath);
588 }
589 }
590
591 eventPhaseTable.set(event, Event.NONE);
592 currentTargetTable.set(event, null);
593
594 return event.defaultPrevented;
595 }
596
597 function dispatchCapturing(event, eventPath) {
598 var phase;
599
600 for (var i = eventPath.length - 1; i > 0; i--) {
601 var target = eventPath[i].target;
602 var currentTarget = eventPath[i].currentTarget;
603 if (target === currentTarget)
604 continue;
605
606 phase = Event.CAPTURING_PHASE;
607 if (!invoke(eventPath[i], event, phase))
608 return false;
609 }
610
611 return true;
612 }
613
614 function dispatchAtTarget(event, eventPath) {
615 var phase = Event.AT_TARGET;
616 return invoke(eventPath[0], event, phase);
617 }
618
619 function dispatchBubbling(event, eventPath) {
620 var bubbles = event.bubbles;
621 var phase;
622
623 for (var i = 1; i < eventPath.length; i++) {
624 var target = eventPath[i].target;
625 var currentTarget = eventPath[i].currentTarget;
626 if (target === currentTarget)
627 phase = Event.AT_TARGET;
628 else if (bubbles && !stopImmediatePropagationTable.get(event))
629 phase = Event.BUBBLING_PHASE;
630 else
631 continue;
632
633 if (!invoke(eventPath[i], event, phase))
634 return;
635 }
636 }
637
638 function invoke(tuple, event, phase) {
639 var target = tuple.target;
640 var currentTarget = tuple.currentTarget;
641
642 var listeners = listenersTable.get(currentTarget);
643 if (!listeners)
644 return true;
645
646 if ('relatedTarget' in event) {
647 var originalEvent = unwrap(event);
648 var relatedTarget = wrap(originalEvent.relatedTarget);
649
650 var adjusted = adjustRelatedTarget(currentTarget, relatedTarget);
651 if (adjusted === target)
652 return true;
653
654 relatedTargetTable.set(event, adjusted);
655 }
656
657 eventPhaseTable.set(event, phase);
658 var type = event.type;
659
660 var anyRemoved = false;
661 targetTable.set(event, target);
662 currentTargetTable.set(event, currentTarget);
663
664 for (var i = 0; i < listeners.length; i++) {
665 var listener = listeners[i];
666 if (listener.removed) {
667 anyRemoved = true;
668 continue;
669 }
670
671 if (listener.type !== type ||
672 !listener.capture && phase === Event.CAPTURING_PHASE ||
673 listener.capture && phase === Event.BUBBLING_PHASE) {
674 continue;
675 }
676
677 try {
678 if (typeof listener.handler === 'function')
679 listener.handler.call(currentTarget, event);
680 else
681 listener.handler.handleEvent(event);
682
683 if (stopImmediatePropagationTable.get(event))
684 return false;
685
686 } catch (ex) {
687 if (window.onerror)
688 window.onerror(ex.message);
689 else
690 console.error(ex);
691 }
692 }
693
694 if (anyRemoved) {
695 var copy = listeners.slice();
696 listeners.length = 0;
697 for (var i = 0; i < copy.length; i++) {
698 if (!copy[i].removed)
699 listeners.push(copy[i]);
700 }
701 }
702
703 return !stopPropagationTable.get(event);
704 }
705
706 function Listener(type, handler, capture) {
707 this.type = type;
708 this.handler = handler;
709 this.capture = Boolean(capture);
710 }
711 Listener.prototype = {
712 equals: function(that) {
713 return this.handler === that.handler && this.type === that.type &&
714 this.capture === that.capture;
715 },
716 get removed() {
717 return this.handler === null;
718 },
719 remove: function() {
720 this.handler = null;
721 }
722 };
723
724 var OriginalEvent = window.Event;
725
726 /**
727 * Creates a new Event wrapper or wraps an existin native Event object.
728 * @param {string|Event} type
729 * @param {Object=} options
730 * @constructor
731 */
732 function Event(type, options) {
733 if (type instanceof OriginalEvent)
734 this.impl = type;
735 else
736 return wrap(constructEvent(OriginalEvent, 'Event', type, options));
737 }
738 Event.prototype = {
739 get target() {
740 return targetTable.get(this);
741 },
742 get currentTarget() {
743 return currentTargetTable.get(this);
744 },
745 get eventPhase() {
746 return eventPhaseTable.get(this);
747 },
748 stopPropagation: function() {
749 stopPropagationTable.set(this, true);
750 },
751 stopImmediatePropagation: function() {
752 stopPropagationTable.set(this, true);
753 stopImmediatePropagationTable.set(this, true);
754 }
755 };
756 registerWrapper(OriginalEvent, Event, document.createEvent('Event'));
757
758 function unwrapOptions(options) {
759 if (!options || !options.relatedTarget)
760 return options;
761 return Object.create(options, {
762 relatedTarget: {value: unwrap(options.relatedTarget)}
763 });
764 }
765
766 function registerGenericEvent(name, SuperEvent, prototype) {
767 var OriginalEvent = window[name];
768 var GenericEvent = function(type, options) {
769 if (type instanceof OriginalEvent)
770 this.impl = type;
771 else
772 return wrap(constructEvent(OriginalEvent, name, type, options));
773 };
774 GenericEvent.prototype = Object.create(SuperEvent.prototype);
775 if (prototype)
776 mixin(GenericEvent.prototype, prototype);
777 // Firefox does not support FocusEvent
778 // https://bugzilla.mozilla.org/show_bug.cgi?id=855741
779 if (OriginalEvent)
780 registerWrapper(OriginalEvent, GenericEvent, document.createEvent(name));
781 return GenericEvent;
782 }
783
784 var UIEvent = registerGenericEvent('UIEvent', Event);
785 var CustomEvent = registerGenericEvent('CustomEvent', Event);
786
787 var relatedTargetProto = {
788 get relatedTarget() {
789 return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget);
790 }
791 };
792
793 function getInitFunction(name, relatedTargetIndex) {
794 return function() {
795 arguments[relatedTargetIndex] = unwrap(arguments[relatedTargetIndex]);
796 var impl = unwrap(this);
797 impl[name].apply(impl, arguments);
798 };
799 }
800
801 var mouseEventProto = mixin({
802 initMouseEvent: getInitFunction('initMouseEvent', 14)
803 }, relatedTargetProto);
804
805 var focusEventProto = mixin({
806 initFocusEvent: getInitFunction('initFocusEvent', 5)
807 }, relatedTargetProto);
808
809 var MouseEvent = registerGenericEvent('MouseEvent', UIEvent, mouseEventProto);
810 var FocusEvent = registerGenericEvent('FocusEvent', UIEvent, focusEventProto);
811
812 var MutationEvent = registerGenericEvent('MutationEvent', Event, {
813 initMutationEvent: getInitFunction('initMutationEvent', 3),
814 get relatedNode() {
815 return wrap(this.impl.relatedNode);
816 },
817 });
818
819 // In case the browser does not support event constructors we polyfill that
820 // by calling `createEvent('Foo')` and `initFooEvent` where the arguments to
821 // `initFooEvent` are derived from the registered default event init dict.
822 var defaultInitDicts = Object.create(null);
823
824 var supportsEventConstructors = (function() {
825 try {
826 new window.MouseEvent('click');
827 } catch (ex) {
828 return false;
829 }
830 return true;
831 })();
832
833 /**
834 * Constructs a new native event.
835 */
836 function constructEvent(OriginalEvent, name, type, options) {
837 if (supportsEventConstructors)
838 return new OriginalEvent(type, unwrapOptions(options));
839
840 // Create the arguments from the default dictionary.
841 var event = unwrap(document.createEvent(name));
842 var defaultDict = defaultInitDicts[name];
843 var args = [type];
844 Object.keys(defaultDict).forEach(function(key) {
845 var v = options != null && key in options ?
846 options[key] : defaultDict[key];
847 if (key === 'relatedTarget')
848 v = unwrap(v);
849 args.push(v);
850 });
851 event['init' + name].apply(event, args);
852 return event;
853 }
854
855 if (!supportsEventConstructors) {
856 var configureEventConstructor = function(name, initDict, superName) {
857 if (superName) {
858 var superDict = defaultInitDicts[superName];
859 initDict = mixin(mixin({}, superDict), initDict);
860 }
861
862 defaultInitDicts[name] = initDict;
863 };
864
865 // The order of the default event init dictionary keys is important, the
866 // arguments to initFooEvent is derived from that.
867 configureEventConstructor('Event', {bubbles: false, cancelable: false});
868 configureEventConstructor('CustomEvent', {detail: null}, 'Event');
869 configureEventConstructor('UIEvent', {view: null, detail: 0}, 'Event');
870 configureEventConstructor('MouseEvent', {
871 screenX: 0,
872 screenY: 0,
873 clientX: 0,
874 clientY: 0,
875 ctrlKey: false,
876 altKey: false,
877 shiftKey: false,
878 metaKey: false,
879 button: 0,
880 relatedTarget: null
881 }, 'UIEvent');
882 configureEventConstructor('FocusEvent', {relatedTarget: null}, 'UIEvent');
883 }
884
885 function isValidListener(fun) {
886 if (typeof fun === 'function')
887 return true;
888 return fun && fun.handleEvent;
889 }
890
891 var OriginalEventTarget = window.EventTarget;
892
893 /**
894 * This represents a wrapper for an EventTarget.
895 * @param {!EventTarget} impl The original event target.
896 * @constructor
897 */
898 function EventTarget(impl) {
899 this.impl = impl;
900 }
901
902 // Node and Window have different internal type checks in WebKit so we cannot
903 // use the same method as the original function.
904 var methodNames = [
905 'addEventListener',
906 'removeEventListener',
907 'dispatchEvent'
908 ];
909
910 [Element, Window, Document].forEach(function(constructor) {
911 var p = constructor.prototype;
912 methodNames.forEach(function(name) {
913 Object.defineProperty(p, name + '_', {value: p[name]});
914 });
915 });
916
917 function getTargetToListenAt(wrapper) {
918 if (wrapper instanceof wrappers.ShadowRoot)
919 wrapper = scope.getHostForShadowRoot(wrapper);
920 return unwrap(wrapper);
921 }
922
923 EventTarget.prototype = {
924 addEventListener: function(type, fun, capture) {
925 if (!isValidListener(fun))
926 return;
927
928 var listener = new Listener(type, fun, capture);
929 var listeners = listenersTable.get(this);
930 if (!listeners) {
931 listeners = [];
932 listenersTable.set(this, listeners);
933 } else {
934 // Might have a duplicate.
935 for (var i = 0; i < listeners.length; i++) {
936 if (listener.equals(listeners[i]))
937 return;
938 }
939 }
940
941 listeners.push(listener);
942
943 var target = getTargetToListenAt(this);
944 target.addEventListener_(type, dispatchOriginalEvent, true);
945 },
946 removeEventListener: function(type, fun, capture) {
947 capture = Boolean(capture);
948 var listeners = listenersTable.get(this);
949 if (!listeners)
950 return;
951 var count = 0, found = false;
952 for (var i = 0; i < listeners.length; i++) {
953 if (listeners[i].type === type && listeners[i].capture === capture) {
954 count++;
955 if (listeners[i].handler === fun) {
956 found = true;
957 listeners[i].remove();
958 }
959 }
960 }
961
962 if (found && count === 1) {
963 var target = getTargetToListenAt(this);
964 target.removeEventListener_(type, dispatchOriginalEvent, true);
965 }
966 },
967 dispatchEvent: function(event) {
968 scope.renderAllPending();
969 var target = getTargetToListenAt(this);
970 return target.dispatchEvent_(unwrap(event));
971 }
972 };
973
974 if (OriginalEventTarget)
975 registerWrapper(OriginalEventTarget, EventTarget);
976
977 function wrapEventTargetMethods(constructors) {
978 forwardMethodsToWrapper(constructors, methodNames);
979 }
980
981
982 var originalElementFromPoint = document.elementFromPoint;
983
984 function elementFromPoint(self, document, x, y) {
985 scope.renderAllPending();
986
987 var element = wrap(originalElementFromPoint.call(document.impl, x, y));
988 var targets = retarget(element, this)
989 for (var i = 0; i < targets.length; i++) {
990 var target = targets[i];
991 if (target.currentTarget === self)
992 return target.target;
993 }
994 return null;
995 }
996
997 scope.adjustRelatedTarget = adjustRelatedTarget;
998 scope.elementFromPoint = elementFromPoint;
999 scope.wrapEventTargetMethods = wrapEventTargetMethods;
1000 scope.wrappers.CustomEvent = CustomEvent;
1001 scope.wrappers.Event = Event;
1002 scope.wrappers.EventTarget = EventTarget;
1003 scope.wrappers.FocusEvent = FocusEvent;
1004 scope.wrappers.MouseEvent = MouseEvent;
1005 scope.wrappers.MutationEvent = MutationEvent;
1006 scope.wrappers.UIEvent = UIEvent;
1007
1008 })(this.ShadowDOMPolyfill);
1009
1010 // Copyright 2012 The Polymer Authors. All rights reserved.
1011 // Use of this source code is goverened by a BSD-style
1012 // license that can be found in the LICENSE file.
1013
1014 (function(scope) {
1015 'use strict';
1016
1017 var wrap = scope.wrap;
1018
1019 function nonEnum(obj, prop) {
1020 Object.defineProperty(obj, prop, {enumerable: false});
1021 }
1022
1023 function NodeList() {
1024 this.length = 0;
1025 nonEnum(this, 'length');
1026 }
1027 NodeList.prototype = {
1028 item: function(index) {
1029 return this[index];
1030 }
1031 };
1032 nonEnum(NodeList.prototype, 'item');
1033
1034 function wrapNodeList(list) {
1035 if (list == null)
1036 return list;
1037 var wrapperList = new NodeList();
1038 for (var i = 0, length = list.length; i < length; i++) {
1039 wrapperList[i] = wrap(list[i]);
1040 }
1041 wrapperList.length = length;
1042 return wrapperList;
1043 }
1044
1045 function addWrapNodeListMethod(wrapperConstructor, name) {
1046 wrapperConstructor.prototype[name] = function() {
1047 return wrapNodeList(this.impl[name].apply(this.impl, arguments));
1048 };
1049 }
1050
1051 scope.wrappers.NodeList = NodeList;
1052 scope.addWrapNodeListMethod = addWrapNodeListMethod;
1053 scope.wrapNodeList = wrapNodeList;
1054
1055 })(this.ShadowDOMPolyfill);
1056 // Copyright 2012 The Polymer Authors. All rights reserved.
1057 // Use of this source code is goverened by a BSD-style
1058 // license that can be found in the LICENSE file.
1059
1060 (function(scope) {
1061 'use strict';
1062
1063 var EventTarget = scope.wrappers.EventTarget;
1064 var NodeList = scope.wrappers.NodeList;
1065 var defineWrapGetter = scope.defineWrapGetter;
1066 var assert = scope.assert;
1067 var mixin = scope.mixin;
1068 var registerWrapper = scope.registerWrapper;
1069 var unwrap = scope.unwrap;
1070 var wrap = scope.wrap;
1071
1072 function assertIsNodeWrapper(node) {
1073 assert(node instanceof Node);
1074 }
1075
1076 /**
1077 * Collects nodes from a DocumentFragment or a Node for removal followed
1078 * by an insertion.
1079 *
1080 * This updates the internal pointers for node, previousNode and nextNode.
1081 */
1082 function collectNodes(node, parentNode, previousNode, nextNode) {
1083 if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
1084 if (node.parentNode)
1085 node.parentNode.removeChild(node);
1086 node.parentNode_ = parentNode;
1087 node.previousSibling_ = previousNode;
1088 node.nextSibling_ = nextNode;
1089 if (previousNode)
1090 previousNode.nextSibling_ = node;
1091 if (nextNode)
1092 nextNode.previousSibling_ = node;
1093 return [node];
1094 }
1095
1096 var nodes = [];
1097 var firstChild;
1098 while (firstChild = node.firstChild) {
1099 node.removeChild(firstChild);
1100 nodes.push(firstChild);
1101 firstChild.parentNode_ = parentNode;
1102 }
1103
1104 for (var i = 0; i < nodes.length; i++) {
1105 nodes[i].previousSibling_ = nodes[i - 1] || previousNode;
1106 nodes[i].nextSibling_ = nodes[i + 1] || nextNode;
1107 }
1108
1109 if (previousNode)
1110 previousNode.nextSibling_ = nodes[0];
1111 if (nextNode)
1112 nextNode.previousSibling_ = nodes[nodes.length - 1];
1113
1114 return nodes;
1115 }
1116
1117 function unwrapNodesForInsertion(nodes) {
1118 if (nodes.length === 1)
1119 return unwrap(nodes[0]);
1120
1121 var df = unwrap(document.createDocumentFragment());
1122 for (var i = 0; i < nodes.length; i++) {
1123 df.appendChild(unwrap(nodes[i]));
1124 }
1125 return df;
1126 }
1127
1128 function removeAllChildNodes(wrapper) {
1129 var childWrapper = wrapper.firstChild;
1130 while (childWrapper) {
1131 assert(childWrapper.parentNode === wrapper);
1132 var nextSibling = childWrapper.nextSibling;
1133 var childNode = unwrap(childWrapper);
1134 var parentNode = childNode.parentNode;
1135 if (parentNode)
1136 originalRemoveChild.call(parentNode, childNode);
1137 childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.p arentNode_ = null;
1138 childWrapper = nextSibling;
1139 }
1140 wrapper.firstChild_ = wrapper.lastChild_ = null;
1141 }
1142
1143 var OriginalNode = window.Node;
1144
1145 /**
1146 * This represents a wrapper of a native DOM node.
1147 * @param {!Node} original The original DOM node, aka, the visual DOM node.
1148 * @constructor
1149 * @extends {EventTarget}
1150 */
1151 function Node(original) {
1152 assert(original instanceof OriginalNode);
1153
1154 EventTarget.call(this, original);
1155
1156 // These properties are used to override the visual references with the
1157 // logical ones. If the value is undefined it means that the logical is the
1158 // same as the visual.
1159
1160 /**
1161 * @type {Node|undefined}
1162 * @private
1163 */
1164 this.parentNode_ = undefined;
1165
1166 /**
1167 * @type {Node|undefined}
1168 * @private
1169 */
1170 this.firstChild_ = undefined;
1171
1172 /**
1173 * @type {Node|undefined}
1174 * @private
1175 */
1176 this.lastChild_ = undefined;
1177
1178 /**
1179 * @type {Node|undefined}
1180 * @private
1181 */
1182 this.nextSibling_ = undefined;
1183
1184 /**
1185 * @type {Node|undefined}
1186 * @private
1187 */
1188 this.previousSibling_ = undefined;
1189 };
1190
1191 var originalAppendChild = OriginalNode.prototype.appendChild;
1192 var originalInsertBefore = OriginalNode.prototype.insertBefore;
1193 var originalReplaceChild = OriginalNode.prototype.replaceChild;
1194 var originalRemoveChild = OriginalNode.prototype.removeChild;
1195 var originalCompareDocumentPosition =
1196 OriginalNode.prototype.compareDocumentPosition;
1197
1198 Node.prototype = Object.create(EventTarget.prototype);
1199 mixin(Node.prototype, {
1200 appendChild: function(childWrapper) {
1201 assertIsNodeWrapper(childWrapper);
1202
1203 this.invalidateShadowRenderer();
1204
1205 var previousNode = this.lastChild;
1206 var nextNode = null;
1207 var nodes = collectNodes(childWrapper, this,
1208 previousNode, nextNode);
1209
1210 this.lastChild_ = nodes[nodes.length - 1];
1211 if (!previousNode)
1212 this.firstChild_ = nodes[0];
1213
1214 // TODO(arv): It is unclear if we need to update the visual DOM here.
1215 // A better aproach might be to make sure we only get here for nodes that
1216 // are related to a shadow host and then invalidate that and re-render
1217 // the host (on reflow?).
1218 originalAppendChild.call(this.impl, unwrapNodesForInsertion(nodes));
1219
1220 return childWrapper;
1221 },
1222
1223 insertBefore: function(childWrapper, refWrapper) {
1224 // TODO(arv): Unify with appendChild
1225 if (!refWrapper)
1226 return this.appendChild(childWrapper);
1227
1228 assertIsNodeWrapper(childWrapper);
1229 assertIsNodeWrapper(refWrapper);
1230 assert(refWrapper.parentNode === this);
1231
1232 this.invalidateShadowRenderer();
1233
1234 var previousNode = refWrapper.previousSibling;
1235 var nextNode = refWrapper;
1236 var nodes = collectNodes(childWrapper, this,
1237 previousNode, nextNode);
1238
1239
1240 if (this.firstChild === refWrapper)
1241 this.firstChild_ = nodes[0];
1242
1243 // insertBefore refWrapper no matter what the parent is?
1244 var refNode = unwrap(refWrapper);
1245 var parentNode = refNode.parentNode;
1246 if (parentNode) {
1247 originalInsertBefore.call(
1248 parentNode,
1249 unwrapNodesForInsertion(nodes),
1250 refNode);
1251 }
1252
1253 return childWrapper;
1254 },
1255
1256 removeChild: function(childWrapper) {
1257 assertIsNodeWrapper(childWrapper);
1258 if (childWrapper.parentNode !== this) {
1259 // TODO(arv): DOMException
1260 throw new Error('NotFoundError');
1261 }
1262
1263 this.invalidateShadowRenderer();
1264
1265 // We need to remove the real node from the DOM before updating the
1266 // pointers. This is so that that mutation event is dispatched before
1267 // the pointers have changed.
1268 var thisFirstChild = this.firstChild;
1269 var thisLastChild = this.lastChild;
1270 var childWrapperNextSibling = childWrapper.nextSibling;
1271 var childWrapperPreviousSibling = childWrapper.previousSibling;
1272
1273 var childNode = unwrap(childWrapper);
1274 var parentNode = childNode.parentNode;
1275 if (parentNode)
1276 originalRemoveChild.call(parentNode, childNode);
1277
1278 if (thisFirstChild === childWrapper)
1279 this.firstChild_ = childWrapperNextSibling;
1280 if (thisLastChild === childWrapper)
1281 this.lastChild_ = childWrapperPreviousSibling;
1282 if (childWrapperPreviousSibling)
1283 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling;
1284 if (childWrapperNextSibling)
1285 childWrapperNextSibling.previousSibling_ = childWrapperPreviousSibling;
1286
1287 childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.p arentNode_ = null;
1288
1289 return childWrapper;
1290 },
1291
1292 replaceChild: function(newChildWrapper, oldChildWrapper) {
1293 assertIsNodeWrapper(newChildWrapper);
1294 assertIsNodeWrapper(oldChildWrapper);
1295
1296 if (oldChildWrapper.parentNode !== this) {
1297 // TODO(arv): DOMException
1298 throw new Error('NotFoundError');
1299 }
1300
1301 this.invalidateShadowRenderer();
1302
1303 var previousNode = oldChildWrapper.previousSibling;
1304 var nextNode = oldChildWrapper.nextSibling;
1305 if (nextNode === newChildWrapper)
1306 nextNode = newChildWrapper.nextSibling;
1307 var nodes = collectNodes(newChildWrapper, this,
1308 previousNode, nextNode);
1309
1310 if (this.firstChild === oldChildWrapper)
1311 this.firstChild_ = nodes[0];
1312 if (this.lastChild === oldChildWrapper)
1313 this.lastChild_ = nodes[nodes.length - 1];
1314
1315 oldChildWrapper.previousSibling_ = null;
1316 oldChildWrapper.nextSibling_ = null;
1317 oldChildWrapper.parentNode_ = null;
1318
1319 // replaceChild no matter what the parent is?
1320 var oldChildNode = unwrap(oldChildWrapper);
1321 if (oldChildNode.parentNode) {
1322 originalReplaceChild.call(
1323 oldChildNode.parentNode,
1324 unwrapNodesForInsertion(nodes),
1325 oldChildNode);
1326 }
1327
1328 return oldChildWrapper;
1329 },
1330
1331 hasChildNodes: function() {
1332 return this.firstChild === null;
1333 },
1334
1335 /** @type {Node} */
1336 get parentNode() {
1337 // If the parentNode has not been overridden, use the original parentNode.
1338 return this.parentNode_ !== undefined ?
1339 this.parentNode_ : wrap(this.impl.parentNode);
1340 },
1341
1342 /** @type {Node} */
1343 get firstChild() {
1344 return this.firstChild_ !== undefined ?
1345 this.firstChild_ : wrap(this.impl.firstChild);
1346 },
1347
1348 /** @type {Node} */
1349 get lastChild() {
1350 return this.lastChild_ !== undefined ?
1351 this.lastChild_ : wrap(this.impl.lastChild);
1352 },
1353
1354 /** @type {Node} */
1355 get nextSibling() {
1356 return this.nextSibling_ !== undefined ?
1357 this.nextSibling_ : wrap(this.impl.nextSibling);
1358 },
1359
1360 /** @type {Node} */
1361 get previousSibling() {
1362 return this.previousSibling_ !== undefined ?
1363 this.previousSibling_ : wrap(this.impl.previousSibling);
1364 },
1365
1366 get parentElement() {
1367 var p = this.parentNode;
1368 while (p && p.nodeType !== Node.ELEMENT_NODE) {
1369 p = p.parentNode;
1370 }
1371 return p;
1372 },
1373
1374 get textContent() {
1375 // TODO(arv): This should fallback to this.impl.textContent if there
1376 // are no shadow trees below or above the context node.
1377 var s = '';
1378 for (var child = this.firstChild; child; child = child.nextSibling) {
1379 s += child.textContent;
1380 }
1381 return s;
1382 },
1383 set textContent(textContent) {
1384 removeAllChildNodes(this);
1385 this.invalidateShadowRenderer();
1386 if (textContent !== '') {
1387 var textNode = this.impl.ownerDocument.createTextNode(textContent);
1388 this.appendChild(textNode);
1389 }
1390 },
1391
1392 get childNodes() {
1393 var wrapperList = new NodeList();
1394 var i = 0;
1395 for (var child = this.firstChild; child; child = child.nextSibling) {
1396 wrapperList[i++] = child;
1397 }
1398 wrapperList.length = i;
1399 return wrapperList;
1400 },
1401
1402 cloneNode: function(deep) {
1403 if (!this.invalidateShadowRenderer())
1404 return wrap(this.impl.cloneNode(deep));
1405
1406 var clone = wrap(this.impl.cloneNode(false));
1407 if (deep) {
1408 for (var child = this.firstChild; child; child = child.nextSibling) {
1409 clone.appendChild(child.cloneNode(true));
1410 }
1411 }
1412 // TODO(arv): Some HTML elements also clone other data like value.
1413 return clone;
1414 },
1415
1416 // insertionParent is added in ShadowRender.js
1417
1418 contains: function(child) {
1419 if (!child)
1420 return false;
1421
1422 // TODO(arv): Optimize using ownerDocument etc.
1423 if (child === this)
1424 return true;
1425 var parentNode = child.parentNode;
1426 if (!parentNode)
1427 return false;
1428 return this.contains(parentNode);
1429 },
1430
1431 compareDocumentPosition: function(otherNode) {
1432 // This only wraps, it therefore only operates on the composed DOM and not
1433 // the logical DOM.
1434 return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode));
1435 }
1436 });
1437
1438 defineWrapGetter(Node, 'ownerDocument');
1439
1440 // We use a DocumentFragment as a base and then delete the properties of
1441 // DocumentFragment.prototype from the wrapper Node. Since delete makes
1442 // objects slow in some JS engines we recreate the prototype object.
1443 registerWrapper(OriginalNode, Node, document.createDocumentFragment());
1444 delete Node.prototype.querySelector;
1445 delete Node.prototype.querySelectorAll;
1446 Node.prototype = mixin(Object.create(EventTarget.prototype), Node.prototype);
1447
1448 scope.wrappers.Node = Node;
1449
1450 })(this.ShadowDOMPolyfill);
1451
1452 // Copyright 2013 The Polymer Authors. All rights reserved.
1453 // Use of this source code is governed by a BSD-style
1454 // license that can be found in the LICENSE file.
1455
1456 (function(scope) {
1457 'use strict';
1458
1459 function findOne(node, selector) {
1460 var m, el = node.firstElementChild;
1461 while (el) {
1462 if (el.matches(selector))
1463 return el;
1464 m = findOne(el, selector);
1465 if (m)
1466 return m;
1467 el = el.nextElementSibling;
1468 }
1469 return null;
1470 }
1471
1472 function findAll(node, selector, results) {
1473 var el = node.firstElementChild;
1474 while (el) {
1475 if (el.matches(selector))
1476 results[results.length++] = el;
1477 findAll(el, selector, results);
1478 el = el.nextElementSibling;
1479 }
1480 return results;
1481 }
1482
1483 // find and findAll will only match Simple Selectors,
1484 // Structural Pseudo Classes are not guarenteed to be correct
1485 // http://www.w3.org/TR/css3-selectors/#simple-selectors
1486
1487 var SelectorsInterface = {
1488 querySelector: function(selector) {
1489 return findOne(this, selector);
1490 },
1491 querySelectorAll: function(selector) {
1492 return findAll(this, selector, new NodeList())
1493 }
1494 };
1495
1496 var GetElementsByInterface = {
1497 getElementsByTagName: function(tagName) {
1498 // TODO(arv): Check tagName?
1499 return this.querySelectorAll(tagName);
1500 },
1501 getElementsByClassName: function(className) {
1502 // TODO(arv): Check className?
1503 return this.querySelectorAll('.' + className);
1504 },
1505 getElementsByTagNameNS: function(ns, tagName) {
1506 if (ns === '*')
1507 return this.getElementsByTagName(tagName);
1508
1509 // TODO(arv): Check tagName?
1510 var result = new NodeList;
1511 var els = this.getElementsByTagName(tagName);
1512 for (var i = 0, j = 0; i < els.length; i++) {
1513 if (els[i].namespaceURI === ns)
1514 result[j++] = els[i];
1515 }
1516 result.length = j;
1517 return result;
1518 }
1519 };
1520
1521 scope.GetElementsByInterface = GetElementsByInterface;
1522 scope.SelectorsInterface = SelectorsInterface;
1523
1524 })(this.ShadowDOMPolyfill);
1525
1526 // Copyright 2013 The Polymer Authors. All rights reserved.
1527 // Use of this source code is goverened by a BSD-style
1528 // license that can be found in the LICENSE file.
1529
1530 (function(scope) {
1531 'use strict';
1532
1533 var NodeList = scope.wrappers.NodeList;
1534
1535 function forwardElement(node) {
1536 while (node && node.nodeType !== Node.ELEMENT_NODE) {
1537 node = node.nextSibling;
1538 }
1539 return node;
1540 }
1541
1542 function backwardsElement(node) {
1543 while (node && node.nodeType !== Node.ELEMENT_NODE) {
1544 node = node.previousSibling;
1545 }
1546 return node;
1547 }
1548
1549 var ParentNodeInterface = {
1550 get firstElementChild() {
1551 return forwardElement(this.firstChild);
1552 },
1553
1554 get lastElementChild() {
1555 return backwardsElement(this.lastChild);
1556 },
1557
1558 get childElementCount() {
1559 var count = 0;
1560 for (var child = this.firstElementChild;
1561 child;
1562 child = child.nextElementSibling) {
1563 count++;
1564 }
1565 return count;
1566 },
1567
1568 get children() {
1569 var wrapperList = new NodeList();
1570 var i = 0;
1571 for (var child = this.firstElementChild;
1572 child;
1573 child = child.nextElementSibling) {
1574 wrapperList[i++] = child;
1575 }
1576 wrapperList.length = i;
1577 return wrapperList;
1578 }
1579 };
1580
1581 var ChildNodeInterface = {
1582 get nextElementSibling() {
1583 return forwardElement(this.nextSibling);
1584 },
1585
1586 get previousElementSibling() {
1587 return backwardsElement(this.nextSibling);
1588 }
1589 };
1590
1591 scope.ChildNodeInterface = ChildNodeInterface;
1592 scope.ParentNodeInterface = ParentNodeInterface;
1593
1594 })(this.ShadowDOMPolyfill);
1595
1596 // Copyright 2013 The Polymer Authors. All rights reserved.
1597 // Use of this source code is goverened by a BSD-style
1598 // license that can be found in the LICENSE file.
1599
1600 (function(scope) {
1601 'use strict';
1602
1603 var ChildNodeInterface = scope.ChildNodeInterface;
1604 var Node = scope.wrappers.Node;
1605 var mixin = scope.mixin;
1606 var registerWrapper = scope.registerWrapper;
1607
1608 var OriginalCharacterData = window.CharacterData;
1609
1610 function CharacterData(node) {
1611 Node.call(this, node);
1612 }
1613 CharacterData.prototype = Object.create(Node.prototype);
1614 mixin(CharacterData.prototype, {
1615 get textContent() {
1616 return this.data;
1617 },
1618 set textContent(value) {
1619 this.data = value;
1620 }
1621 });
1622
1623 mixin(CharacterData.prototype, ChildNodeInterface);
1624
1625 registerWrapper(OriginalCharacterData, CharacterData,
1626 document.createTextNode(''));
1627
1628 scope.wrappers.CharacterData = CharacterData;
1629 })(this.ShadowDOMPolyfill);
1630
1631 // Copyright 2013 The Polymer Authors. All rights reserved.
1632 // Use of this source code is goverened by a BSD-style
1633 // license that can be found in the LICENSE file.
1634
1635 (function(scope) {
1636 'use strict';
1637
1638 var ChildNodeInterface = scope.ChildNodeInterface;
1639 var GetElementsByInterface = scope.GetElementsByInterface;
1640 var Node = scope.wrappers.Node;
1641 var ParentNodeInterface = scope.ParentNodeInterface;
1642 var SelectorsInterface = scope.SelectorsInterface;
1643 var addWrapNodeListMethod = scope.addWrapNodeListMethod;
1644 var mixin = scope.mixin;
1645 var registerWrapper = scope.registerWrapper;
1646 var wrappers = scope.wrappers;
1647
1648 var shadowRootTable = new SideTable();
1649 var OriginalElement = window.Element;
1650
1651 var originalMatches =
1652 OriginalElement.prototype.matches ||
1653 OriginalElement.prototype.mozMatchesSelector ||
1654 OriginalElement.prototype.msMatchesSelector ||
1655 OriginalElement.prototype.webkitMatchesSelector;
1656
1657 function Element(node) {
1658 Node.call(this, node);
1659 }
1660 Element.prototype = Object.create(Node.prototype);
1661 mixin(Element.prototype, {
1662 createShadowRoot: function() {
1663 var newShadowRoot = new wrappers.ShadowRoot(this);
1664 shadowRootTable.set(this, newShadowRoot);
1665
1666 scope.getRendererForHost(this);
1667
1668 this.invalidateShadowRenderer(true);
1669
1670 return newShadowRoot;
1671 },
1672
1673 get shadowRoot() {
1674 return shadowRootTable.get(this) || null;
1675 },
1676
1677 setAttribute: function(name, value) {
1678 this.impl.setAttribute(name, value);
1679 // This is a bit agressive. We need to invalidate if it affects
1680 // the rendering content[select] or if it effects the value of a content
1681 // select.
1682 this.invalidateShadowRenderer();
1683 },
1684
1685 matches: function(selector) {
1686 return originalMatches.call(this.impl, selector);
1687 }
1688 });
1689
1690 mixin(Element.prototype, ChildNodeInterface);
1691 mixin(Element.prototype, GetElementsByInterface);
1692 mixin(Element.prototype, ParentNodeInterface);
1693 mixin(Element.prototype, SelectorsInterface);
1694
1695 registerWrapper(OriginalElement, Element);
1696
1697 scope.wrappers.Element = Element;
1698 })(this.ShadowDOMPolyfill);
1699
1700 // Copyright 2013 The Polymer Authors. All rights reserved.
1701 // Use of this source code is goverened by a BSD-style
1702 // license that can be found in the LICENSE file.
1703
1704 (function(scope) {
1705 'use strict';
1706
1707 var Element = scope.wrappers.Element;
1708 var defineGetter = scope.defineGetter;
1709 var mixin = scope.mixin;
1710 var registerWrapper = scope.registerWrapper;
1711 var unwrap = scope.unwrap;
1712 var wrap = scope.wrap;
1713
1714 /////////////////////////////////////////////////////////////////////////////
1715 // innerHTML and outerHTML
1716
1717 var escapeRegExp = /&|<|"/g;
1718
1719 function escapeReplace(c) {
1720 switch (c) {
1721 case '&':
1722 return '&amp;';
1723 case '<':
1724 return '&lt;';
1725 case '"':
1726 return '&quot;'
1727 }
1728 }
1729
1730 function escape(s) {
1731 return s.replace(escapeRegExp, escapeReplace);
1732 }
1733
1734 // http://www.whatwg.org/specs/web-apps/current-work/#void-elements
1735 var voidElements = {
1736 'area': true,
1737 'base': true,
1738 'br': true,
1739 'col': true,
1740 'command': true,
1741 'embed': true,
1742 'hr': true,
1743 'img': true,
1744 'input': true,
1745 'keygen': true,
1746 'link': true,
1747 'meta': true,
1748 'param': true,
1749 'source': true,
1750 'track': true,
1751 'wbr': true
1752 };
1753
1754 function getOuterHTML(node) {
1755 switch (node.nodeType) {
1756 case Node.ELEMENT_NODE:
1757 var tagName = node.tagName.toLowerCase();
1758 var s = '<' + tagName;
1759 var attrs = node.attributes;
1760 for (var i = 0, attr; attr = attrs[i]; i++) {
1761 s += ' ' + attr.name + '="' + escape(attr.value) + '"';
1762 }
1763 s += '>';
1764 if (voidElements[tagName])
1765 return s;
1766
1767 return s + getInnerHTML(node) + '</' + tagName + '>';
1768
1769 case Node.TEXT_NODE:
1770 return escape(node.nodeValue);
1771
1772 case Node.COMMENT_NODE:
1773 return '<!--' + escape(node.nodeValue) + '-->';
1774 default:
1775 console.error(node);
1776 throw new Error('not implemented');
1777 }
1778 }
1779
1780 function getInnerHTML(node) {
1781 var s = '';
1782 for (var child = node.firstChild; child; child = child.nextSibling) {
1783 s += getOuterHTML(child);
1784 }
1785 return s;
1786 }
1787
1788 function setInnerHTML(node, value, opt_tagName) {
1789 var tagName = opt_tagName || 'div';
1790 node.textContent = '';
1791 var tempElement =unwrap(node.ownerDocument.createElement(tagName));
1792 tempElement.innerHTML = value;
1793 var firstChild;
1794 while (firstChild = tempElement.firstChild) {
1795 node.appendChild(wrap(firstChild));
1796 }
1797 }
1798
1799 var OriginalHTMLElement = window.HTMLElement;
1800
1801 function HTMLElement(node) {
1802 Element.call(this, node);
1803 }
1804 HTMLElement.prototype = Object.create(Element.prototype);
1805 mixin(HTMLElement.prototype, {
1806 get innerHTML() {
1807 // TODO(arv): This should fallback to this.impl.innerHTML if there
1808 // are no shadow trees below or above the context node.
1809 return getInnerHTML(this);
1810 },
1811 set innerHTML(value) {
1812 setInnerHTML(this, value, this.tagName);
1813 },
1814
1815 get outerHTML() {
1816 // TODO(arv): This should fallback to HTMLElement_prototype.outerHTML if t here
1817 // are no shadow trees below or above the context node.
1818 return getOuterHTML(this);
1819 },
1820 set outerHTML(value) {
1821 if (!this.invalidateShadowRenderer()) {
1822 this.impl.outerHTML = value;
1823 } else {
1824 throw new Error('not implemented');
1825 }
1826 }
1827 });
1828
1829 function getterRequiresRendering(name) {
1830 defineGetter(HTMLElement, name, function() {
1831 scope.renderAllPending();
1832 return this.impl[name];
1833 });
1834 }
1835
1836 [
1837 'clientHeight',
1838 'clientLeft',
1839 'clientTop',
1840 'clientWidth',
1841 'offsetHeight',
1842 'offsetLeft',
1843 'offsetTop',
1844 'offsetWidth',
1845 'scrollHeight',
1846 'scrollLeft',
1847 'scrollTop',
1848 'scrollWidth',
1849 ].forEach(getterRequiresRendering);
1850
1851 function methodRequiresRendering(name) {
1852 Object.defineProperty(HTMLElement.prototype, name, {
1853 value: function() {
1854 scope.renderAllPending();
1855 return this.impl[name].apply(this.impl, arguments);
1856 },
1857 configurable: true,
1858 enumerable: true
1859 });
1860 }
1861
1862 [
1863 'getBoundingClientRect',
1864 'getClientRects',
1865 'scrollIntoView'
1866 ].forEach(methodRequiresRendering);
1867
1868 // HTMLElement is abstract so we use a subclass that has no members.
1869 registerWrapper(OriginalHTMLElement, HTMLElement,
1870 document.createElement('b'));
1871
1872 scope.wrappers.HTMLElement = HTMLElement;
1873
1874 // TODO: Find a better way to share these two with WrapperShadowRoot.
1875 scope.getInnerHTML = getInnerHTML;
1876 scope.setInnerHTML = setInnerHTML
1877 })(this.ShadowDOMPolyfill);
1878 // Copyright 2013 The Polymer Authors. All rights reserved.
1879 // Use of this source code is goverened by a BSD-style
1880 // license that can be found in the LICENSE file.
1881
1882 (function(scope) {
1883 'use strict';
1884
1885 var HTMLElement = scope.wrappers.HTMLElement;
1886 var mixin = scope.mixin;
1887 var registerWrapper = scope.registerWrapper;
1888
1889 var OriginalHTMLContentElement = window.HTMLContentElement;
1890
1891 function HTMLContentElement(node) {
1892 HTMLElement.call(this, node);
1893 }
1894 HTMLContentElement.prototype = Object.create(HTMLElement.prototype);
1895 mixin(HTMLContentElement.prototype, {
1896 get select() {
1897 return this.getAttribute('select');
1898 },
1899 set select(value) {
1900 this.setAttribute('select', value);
1901 },
1902
1903 setAttribute: function(n, v) {
1904 HTMLElement.prototype.setAttribute.call(this, n, v);
1905 if (String(n).toLowerCase() === 'select')
1906 this.invalidateShadowRenderer(true);
1907 }
1908
1909 // getDistributedNodes is added in ShadowRenderer
1910
1911 // TODO: attribute boolean resetStyleInheritance;
1912 });
1913
1914 if (OriginalHTMLContentElement)
1915 registerWrapper(OriginalHTMLContentElement, HTMLContentElement);
1916
1917 scope.wrappers.HTMLContentElement = HTMLContentElement;
1918 })(this.ShadowDOMPolyfill);
1919 // Copyright 2013 The Polymer Authors. All rights reserved.
1920 // Use of this source code is goverened by a BSD-style
1921 // license that can be found in the LICENSE file.
1922
1923 (function(scope) {
1924 'use strict';
1925
1926 var HTMLElement = scope.wrappers.HTMLElement;
1927 var mixin = scope.mixin;
1928 var registerWrapper = scope.registerWrapper;
1929
1930 var OriginalHTMLShadowElement = window.HTMLShadowElement;
1931
1932 function HTMLShadowElement(node) {
1933 HTMLElement.call(this, node);
1934 this.olderShadowRoot_ = null;
1935 }
1936 HTMLShadowElement.prototype = Object.create(HTMLElement.prototype);
1937 mixin(HTMLShadowElement.prototype, {
1938 get olderShadowRoot() {
1939 return this.olderShadowRoot_;
1940 },
1941
1942 invalidateShadowRenderer: function() {
1943 HTMLElement.prototype.invalidateShadowRenderer.call(this, true);
1944 },
1945
1946 // TODO: attribute boolean resetStyleInheritance;
1947 });
1948
1949 if (OriginalHTMLShadowElement)
1950 registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement);
1951
1952 scope.wrappers.HTMLShadowElement = HTMLShadowElement;
1953 })(this.ShadowDOMPolyfill);
1954 // Copyright 2013 The Polymer Authors. All rights reserved.
1955 // Use of this source code is goverened by a BSD-style
1956 // license that can be found in the LICENSE file.
1957
1958 (function(scope) {
1959 'use strict';
1960
1961 var HTMLElement = scope.wrappers.HTMLElement;
1962 var getInnerHTML = scope.getInnerHTML;
1963 var mixin = scope.mixin;
1964 var registerWrapper = scope.registerWrapper;
1965 var setInnerHTML = scope.setInnerHTML;
1966 var wrap = scope.wrap;
1967
1968 var contentTable = new SideTable();
1969 var templateContentsOwnerTable = new SideTable();
1970
1971 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html# dfn-template-contents-owner
1972 function getTemplateContentsOwner(doc) {
1973 if (!doc.defaultView)
1974 return doc;
1975 var d = templateContentsOwnerTable.get(doc);
1976 if (!d) {
1977 // TODO(arv): This should either be a Document or HTMLDocument depending
1978 // on doc.
1979 d = doc.implementation.createHTMLDocument('');
1980 while (d.lastChild) {
1981 d.removeChild(d.lastChild);
1982 }
1983 templateContentsOwnerTable.set(doc, d);
1984 }
1985 return d;
1986 }
1987
1988 function extractContent(templateElement) {
1989 var doc = getTemplateContentsOwner(templateElement.ownerDocument);
1990 var df = doc.createDocumentFragment();
1991 var nextSibling;
1992 var child;
1993 while (child = templateElement.firstChild) {
1994 df.appendChild(child);
1995 }
1996 return df;
1997 }
1998
1999 var OriginalHTMLTemplateElement = window.HTMLTemplateElement;
2000
2001 function HTMLTemplateElement(node) {
2002 HTMLElement.call(this, node);
2003 }
2004 HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);
2005
2006 mixin(HTMLTemplateElement.prototype, {
2007 get content() {
2008 if (OriginalHTMLTemplateElement)
2009 return wrap(this.impl.content);
2010
2011 // TODO(arv): This should be done in createCallback. I initially tried to
2012 // do this in the constructor but the wrapper is not yet created at that
2013 // point in time so we hit an iloop.
2014 var content = contentTable.get(this);
2015 if (!content) {
2016 content = extractContent(this);
2017 contentTable.set(this, content);
2018 }
2019 return content;
2020 },
2021
2022 get innerHTML() {
2023 return getInnerHTML(this.content);
2024 },
2025 set innerHTML(value) {
2026 setInnerHTML(this.content, value);
2027 this.invalidateShadowRenderer();
2028 }
2029
2030 // TODO(arv): cloneNode needs to clone content.
2031
2032 });
2033
2034 if (OriginalHTMLTemplateElement)
2035 registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement);
2036
2037 scope.wrappers.HTMLTemplateElement = HTMLTemplateElement;
2038 })(this.ShadowDOMPolyfill);
2039 // Copyright 2013 The Polymer Authors. All rights reserved.
2040 // Use of this source code is goverened by a BSD-style
2041 // license that can be found in the LICENSE file.
2042
2043 (function(scope) {
2044 'use strict';
2045
2046 var HTMLContentElement = scope.wrappers.HTMLContentElement;
2047 var HTMLElement = scope.wrappers.HTMLElement;
2048 var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
2049 var HTMLTemplateElement = scope.wrappers.HTMLTemplateElement;
2050 var mixin = scope.mixin;
2051 var registerWrapper = scope.registerWrapper;
2052
2053 var OriginalHTMLUnknownElement = window.HTMLUnknownElement;
2054
2055 function HTMLUnknownElement(node) {
2056 switch (node.localName) {
2057 case 'content':
2058 return new HTMLContentElement(node);
2059 case 'shadow':
2060 return new HTMLShadowElement(node);
2061 case 'template':
2062 return new HTMLTemplateElement(node);
2063 }
2064 HTMLElement.call(this, node);
2065 }
2066 HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype);
2067 registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement);
2068 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement;
2069 })(this.ShadowDOMPolyfill);
2070 // Copyright 2013 The Polymer Authors. All rights reserved.
2071 // Use of this source code is goverened by a BSD-style
2072 // license that can be found in the LICENSE file.
2073
2074 (function(scope) {
2075 'use strict';
2076
2077 var GetElementsByInterface = scope.GetElementsByInterface;
2078 var ParentNodeInterface = scope.ParentNodeInterface;
2079 var SelectorsInterface = scope.SelectorsInterface;
2080 var mixin = scope.mixin;
2081 var registerObject = scope.registerObject;
2082
2083 var DocumentFragment = registerObject(document.createDocumentFragment());
2084 mixin(DocumentFragment.prototype, ParentNodeInterface);
2085 mixin(DocumentFragment.prototype, SelectorsInterface);
2086 mixin(DocumentFragment.prototype, GetElementsByInterface);
2087
2088 var Text = registerObject(document.createTextNode(''));
2089 var Comment = registerObject(document.createComment(''));
2090
2091 scope.wrappers.Comment = Comment;
2092 scope.wrappers.DocumentFragment = DocumentFragment;
2093 scope.wrappers.Text = Text;
2094
2095 })(this.ShadowDOMPolyfill);
2096
2097 // Copyright 2013 The Polymer Authors. All rights reserved.
2098 // Use of this source code is goverened by a BSD-style
2099 // license that can be found in the LICENSE file.
2100
2101 (function(scope) {
2102 'use strict';
2103
2104 var DocumentFragment = scope.wrappers.DocumentFragment;
2105 var elementFromPoint = scope.elementFromPoint;
2106 var getInnerHTML = scope.getInnerHTML;
2107 var mixin = scope.mixin;
2108 var rewrap = scope.rewrap;
2109 var setInnerHTML = scope.setInnerHTML;
2110 var unwrap = scope.unwrap;
2111
2112 var shadowHostTable = new SideTable();
2113
2114 function ShadowRoot(hostWrapper) {
2115 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment());
2116 DocumentFragment.call(this, node);
2117
2118 // createDocumentFragment associates the node with a wrapper
2119 // DocumentFragment instance. Override that.
2120 rewrap(node, this);
2121
2122 var oldShadowRoot = hostWrapper.shadowRoot;
2123 scope.nextOlderShadowTreeTable.set(this, oldShadowRoot);
2124
2125 shadowHostTable.set(this, hostWrapper);
2126 }
2127 ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
2128 mixin(ShadowRoot.prototype, {
2129 get innerHTML() {
2130 return getInnerHTML(this);
2131 },
2132 set innerHTML(value) {
2133 setInnerHTML(this, value);
2134 this.invalidateShadowRenderer();
2135 },
2136
2137 invalidateShadowRenderer: function() {
2138 return shadowHostTable.get(this).invalidateShadowRenderer();
2139 },
2140
2141 elementFromPoint: function(x, y) {
2142 return elementFromPoint(this, this.ownerDocument, x, y);
2143 },
2144
2145 getElementById: function(id) {
2146 return this.querySelector('#' + id);
2147 }
2148 });
2149
2150 scope.wrappers.ShadowRoot = ShadowRoot;
2151 scope.getHostForShadowRoot = function(node) {
2152 return shadowHostTable.get(node);
2153 };
2154 })(this.ShadowDOMPolyfill);
2155 // Copyright 2013 The Polymer Authors. All rights reserved.
2156 // Use of this source code is governed by a BSD-style
2157 // license that can be found in the LICENSE file.
2158
2159 (function(scope) {
2160 'use strict';
2161
2162 var HTMLContentElement = scope.wrappers.HTMLContentElement;
2163 var Node = scope.wrappers.Node;
2164 var assert = scope.assert;
2165 var mixin = scope.mixin;
2166 var unwrap = scope.unwrap;
2167 var wrap = scope.wrap;
2168
2169 /**
2170 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed.
2171 * Up means parentNode
2172 * Sideways means previous and next sibling.
2173 * @param {!Node} wrapper
2174 */
2175 function updateWrapperUpAndSideways(wrapper) {
2176 wrapper.previousSibling_ = wrapper.previousSibling;
2177 wrapper.nextSibling_ = wrapper.nextSibling;
2178 wrapper.parentNode_ = wrapper.parentNode;
2179 }
2180
2181 /**
2182 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed.
2183 * Down means first and last child
2184 * @param {!Node} wrapper
2185 */
2186 function updateWrapperDown(wrapper) {
2187 wrapper.firstChild_ = wrapper.firstChild;
2188 wrapper.lastChild_ = wrapper.lastChild;
2189 }
2190
2191 function updateAllChildNodes(parentNodeWrapper) {
2192 assert(parentNodeWrapper instanceof Node);
2193 for (var childWrapper = parentNodeWrapper.firstChild;
2194 childWrapper;
2195 childWrapper = childWrapper.nextSibling) {
2196 updateWrapperUpAndSideways(childWrapper);
2197 }
2198 updateWrapperDown(parentNodeWrapper);
2199 }
2200
2201 // This object groups DOM operations. This is supposed to be the DOM as the
2202 // browser/render tree sees it.
2203 // When changes are done to the visual DOM the logical DOM needs to be updated
2204 // to reflect the correct tree.
2205 function removeAllChildNodes(parentNodeWrapper) {
2206 var parentNode = unwrap(parentNodeWrapper);
2207 updateAllChildNodes(parentNodeWrapper);
2208 parentNode.textContent = '';
2209 }
2210
2211 function appendChild(parentNodeWrapper, childWrapper) {
2212 var parentNode = unwrap(parentNodeWrapper);
2213 var child = unwrap(childWrapper);
2214 if (child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
2215 updateAllChildNodes(childWrapper);
2216
2217 } else {
2218 remove(childWrapper);
2219 updateWrapperUpAndSideways(childWrapper);
2220 }
2221
2222 parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild;
2223 if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild)
2224 parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild;
2225
2226 var lastChildWrapper = wrap(parentNode.lastChild);
2227 if (lastChildWrapper) {
2228 lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling;
2229 }
2230
2231 parentNode.appendChild(child);
2232 }
2233
2234 function removeChild(parentNodeWrapper, childWrapper) {
2235 var parentNode = unwrap(parentNodeWrapper);
2236 var child = unwrap(childWrapper);
2237
2238 updateWrapperUpAndSideways(childWrapper);
2239
2240 if (childWrapper.previousSibling)
2241 childWrapper.previousSibling.nextSibling_ = childWrapper;
2242 if (childWrapper.nextSibling)
2243 childWrapper.nextSibling.previousSibling_ = childWrapper;
2244
2245 if (parentNodeWrapper.lastChild === childWrapper)
2246 parentNodeWrapper.lastChild_ = childWrapper;
2247 if (parentNodeWrapper.firstChild === childWrapper)
2248 parentNodeWrapper.firstChild_ = childWrapper;
2249
2250 parentNode.removeChild(child);
2251 }
2252
2253 function remove(nodeWrapper) {
2254 var node = unwrap(nodeWrapper)
2255 var parentNode = node.parentNode;
2256 if (parentNode)
2257 removeChild(wrap(parentNode), nodeWrapper);
2258 }
2259
2260 var distributedChildNodesTable = new SideTable();
2261 var eventParentsTable = new SideTable();
2262 var insertionParentTable = new SideTable();
2263 var nextOlderShadowTreeTable = new SideTable();
2264 var rendererForHostTable = new SideTable();
2265 var shadowDOMRendererTable = new SideTable();
2266
2267 var reprCounter = 0;
2268
2269 function repr(node) {
2270 if (!node.displayName)
2271 node.displayName = node.nodeName + '-' + ++reprCounter;
2272 return node.displayName;
2273 }
2274
2275 function distributeChildToInsertionPoint(child, insertionPoint) {
2276 getDistributedChildNodes(insertionPoint).push(child);
2277 insertionParentTable.set(child, insertionPoint);
2278
2279 var eventParents = eventParentsTable.get(child);
2280 if (!eventParents)
2281 eventParentsTable.set(child, eventParents = []);
2282 eventParents.push(insertionPoint);
2283 }
2284
2285 function resetDistributedChildNodes(insertionPoint) {
2286 distributedChildNodesTable.set(insertionPoint, []);
2287 }
2288
2289 function getDistributedChildNodes(insertionPoint) {
2290 return distributedChildNodesTable.get(insertionPoint);
2291 }
2292
2293 function getChildNodesSnapshot(node) {
2294 var result = [], i = 0;
2295 for (var child = node.firstChild; child; child = child.nextSibling) {
2296 result[i++] = child;
2297 }
2298 return result;
2299 }
2300
2301 /**
2302 * Visits all nodes in the tree that fulfils the |predicate|. If the |visitor|
2303 * function returns |false| the traversal is aborted.
2304 * @param {!Node} tree
2305 * @param {function(!Node) : boolean} predicate
2306 * @param {function(!Node) : *} visitor
2307 */
2308 function visit(tree, predicate, visitor) {
2309 // This operates on logical DOM.
2310 var nodes = getChildNodesSnapshot(tree);
2311 for (var i = 0; i < nodes.length; i++) {
2312 var node = nodes[i];
2313 if (predicate(node)) {
2314 if (visitor(node) === false)
2315 return;
2316 } else {
2317 visit(node, predicate, visitor);
2318 }
2319 }
2320 }
2321
2322 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn -distribution-algorithm
2323 function distribute(tree, pool) {
2324 var anyRemoved = false;
2325
2326 visit(tree, isActiveInsertionPoint,
2327 function(insertionPoint) {
2328 resetDistributedChildNodes(insertionPoint);
2329 for (var i = 0; i < pool.length; i++) { // 1.2
2330 var node = pool[i]; // 1.2.1
2331 if (node === undefined) // removed
2332 continue;
2333 if (matchesCriteria(node, insertionPoint)) { // 1.2.2
2334 distributeChildToInsertionPoint(node, insertionPoint); // 1.2.2.1
2335 pool[i] = undefined; // 1.2.2.2
2336 anyRemoved = true;
2337 }
2338 }
2339 });
2340
2341 if (!anyRemoved)
2342 return pool;
2343
2344 return pool.filter(function(item) {
2345 return item !== undefined;
2346 });
2347 }
2348
2349 // Matching Insertion Points
2350 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#mat ching-insertion-points
2351
2352 // TODO(arv): Verify this... I don't remember why I picked this regexp.
2353 var selectorMatchRegExp = /^[*.:#[a-zA-Z_|]/;
2354
2355 var allowedPseudoRegExp = new RegExp('^:(' + [
2356 'link',
2357 'visited',
2358 'target',
2359 'enabled',
2360 'disabled',
2361 'checked',
2362 'indeterminate',
2363 'nth-child',
2364 'nth-last-child',
2365 'nth-of-type',
2366 'nth-last-of-type',
2367 'first-child',
2368 'last-child',
2369 'first-of-type',
2370 'last-of-type',
2371 'only-of-type',
2372 ].join('|') + ')');
2373
2374
2375 function oneOf(object, propertyNames) {
2376 for (var i = 0; i < propertyNames.length; i++) {
2377 if (propertyNames[i] in object)
2378 return propertyNames[i];
2379 }
2380 }
2381
2382 /**
2383 * @param {Element} node
2384 * @oaram {Element} point The insertion point element.
2385 * @return {boolean} Whether the node matches the insertion point.
2386 */
2387 function matchesCriteria(node, point) {
2388 var select = point.getAttribute('select');
2389 if (!select)
2390 return true;
2391
2392 // Here we know the select attribute is a non empty string.
2393 select = select.trim();
2394 if (!select)
2395 return true;
2396
2397 if (node.nodeType !== Node.ELEMENT_NODE)
2398 return false;
2399
2400 // TODO(arv): This does not seem right. Need to check for a simple selector.
2401 if (!selectorMatchRegExp.test(select))
2402 return false;
2403
2404 if (select[0] === ':' &&!allowedPseudoRegExp.test(select))
2405 return false;
2406
2407 try {
2408 return node.matches(select);
2409 } catch (ex) {
2410 // Invalid selector.
2411 return false;
2412 }
2413 }
2414
2415 var request = oneOf(window, [
2416 'requestAnimationFrame',
2417 'mozRequestAnimationFrame',
2418 'webkitRequestAnimationFrame',
2419 'setTimeout'
2420 ]);
2421
2422 var pendingDirtyRenderers = [];
2423 var renderTimer;
2424
2425 function renderAllPending() {
2426 renderTimer = null;
2427 pendingDirtyRenderers.forEach(function(owner) {
2428 owner.render();
2429 });
2430 pendingDirtyRenderers = [];
2431 }
2432
2433 function ShadowRenderer(host) {
2434 this.host = host;
2435 this.dirty = false;
2436 this.associateNode(host);
2437 }
2438
2439 function getRendererForHost(host) {
2440 var renderer = rendererForHostTable.get(host);
2441 if (!renderer) {
2442 renderer = new ShadowRenderer(host);
2443 rendererForHostTable.set(host, renderer);
2444 }
2445 return renderer;
2446 }
2447
2448 ShadowRenderer.prototype = {
2449 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#r endering-shadow-trees
2450 render: function() {
2451 if (!this.dirty)
2452 return;
2453
2454 var host = this.host;
2455 this.treeComposition();
2456 var shadowDOM = host.shadowRoot;
2457 if (!shadowDOM)
2458 return;
2459
2460 this.removeAllChildNodes(this.host);
2461
2462 var shadowDOMChildNodes = getChildNodesSnapshot(shadowDOM);
2463 shadowDOMChildNodes.forEach(function(node) {
2464 this.renderNode(host, shadowDOM, node, false);
2465 }, this);
2466
2467 this.dirty = false;
2468 },
2469
2470 invalidate: function() {
2471 if (!this.dirty) {
2472 this.dirty = true;
2473 pendingDirtyRenderers.push(this);
2474 if (renderTimer)
2475 return;
2476 renderTimer = window[request](renderAllPending, 0);
2477 }
2478 },
2479
2480 renderNode: function(visualParent, tree, node, isNested) {
2481 if (isShadowHost(node)) {
2482 this.appendChild(visualParent, node);
2483 var renderer = getRendererForHost(node);
2484 renderer.dirty = true; // Need to rerender due to reprojection.
2485 renderer.render();
2486 } else if (isInsertionPoint(node)) {
2487 this.renderInsertionPoint(visualParent, tree, node, isNested);
2488 } else if (isShadowInsertionPoint(node)) {
2489 this.renderShadowInsertionPoint(visualParent, tree, node);
2490 } else {
2491 this.renderAsAnyDomTree(visualParent, tree, node, isNested);
2492 }
2493 },
2494
2495 renderAsAnyDomTree: function(visualParent, tree, child, isNested) {
2496 this.appendChild(visualParent, child);
2497
2498 if (isShadowHost(child)) {
2499 render(child);
2500 } else {
2501 var parent = child;
2502 var logicalChildNodes = getChildNodesSnapshot(parent);
2503 logicalChildNodes.forEach(function(node) {
2504 this.renderNode(parent, tree, node, isNested);
2505 }, this);
2506 }
2507 },
2508
2509 renderInsertionPoint: function(visualParent, tree, insertionPoint, isNested) {
2510 var distributedChildNodes = getDistributedChildNodes(insertionPoint);
2511 if (distributedChildNodes.length) {
2512 this.removeAllChildNodes(insertionPoint);
2513
2514 distributedChildNodes.forEach(function(child) {
2515 if (isInsertionPoint(child) && isNested)
2516 this.renderInsertionPoint(visualParent, tree, child, isNested);
2517 else
2518 this.renderAsAnyDomTree(visualParent, tree, child, isNested);
2519 }, this);
2520 } else {
2521 this.renderFallbackContent(visualParent, insertionPoint);
2522 }
2523 this.remove(insertionPoint);
2524 },
2525
2526 renderShadowInsertionPoint: function(visualParent, tree, shadowInsertionPoin t) {
2527 var nextOlderTree = getNextOlderTree(tree);
2528 if (nextOlderTree) {
2529 // This makes ShadowRoot have its insertionParent be the <shadow>.
2530 insertionParentTable.set(nextOlderTree, shadowInsertionPoint);
2531 shadowInsertionPoint.olderShadowRoot_ = nextOlderTree;
2532 this.remove(shadowInsertionPoint);
2533 var shadowDOMChildNodes = getChildNodesSnapshot(nextOlderTree);
2534 shadowDOMChildNodes.forEach(function(node) {
2535 this.renderNode(visualParent, nextOlderTree, node, true);
2536 }, this);
2537 } else {
2538 this.renderFallbackContent(visualParent, shadowInsertionPoint);
2539 }
2540 },
2541
2542 renderFallbackContent: function (visualParent, fallbackHost) {
2543 var logicalChildNodes = getChildNodesSnapshot(fallbackHost);
2544 logicalChildNodes.forEach(function(node) {
2545 this.appendChild(visualParent, node);
2546 }, this);
2547 },
2548
2549 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-tree-composition
2550 treeComposition: function () {
2551 var shadowHost = this.host;
2552 var tree = shadowHost.shadowRoot; // 1.
2553 var pool = []; // 2.
2554 var shadowHostChildNodes = getChildNodesSnapshot(shadowHost);
2555 shadowHostChildNodes.forEach(function(child) { // 3.
2556 if (isInsertionPoint(child)) { // 3.2.
2557 var reprojected = getDistributedChildNodes(child); // 3.2.1.
2558 // if reprojected is undef... reset it?
2559 if (!reprojected || !reprojected.length) // 3.2.2.
2560 reprojected = getChildNodesSnapshot(child);
2561 pool.push.apply(pool, reprojected); // 3.2.3.
2562 } else {
2563 pool.push(child); // 3.3.
2564 }
2565 });
2566
2567 var shadowInsertionPoint, point;
2568 while (tree) { // 4.
2569 // 4.1.
2570 shadowInsertionPoint = undefined; // Reset every iteration.
2571 visit(tree, isActiveShadowInsertionPoint, function(point) {
2572 shadowInsertionPoint = point;
2573 return false;
2574 });
2575 point = shadowInsertionPoint;
2576
2577 pool = distribute(tree, pool); // 4.2.
2578 if (point) { // 4.3.
2579 var nextOlderTree = getNextOlderTree(tree); // 4.3.1.
2580 if (!nextOlderTree) {
2581 break; // 4.3.1.1.
2582 } else {
2583 tree = nextOlderTree; // 4.3.2.2.
2584 assignShadowTreeToShadowInsertionPoint(tree, point); // 4.3.2.2.
2585 continue; // 4.3.2.3.
2586 }
2587 } else {
2588 break; // 4.4.
2589 }
2590 }
2591 },
2592
2593 // Visual DOM mutation.
2594 appendChild: function(parent, child) {
2595 appendChild(parent, child);
2596 this.associateNode(child);
2597 },
2598
2599 remove: function(node) {
2600 remove(node);
2601 this.associateNode(node);
2602 },
2603
2604 removeAllChildNodes: function(parent) {
2605 removeAllChildNodes(parent);
2606 // TODO(arv): Does this need to associate all the nodes with this renderer ?
2607 },
2608
2609 associateNode: function(node) {
2610 // TODO: Clear when moved out of shadow tree.
2611 shadowDOMRendererTable.set(node, this);
2612 }
2613 };
2614
2615 function isInsertionPoint(node) {
2616 // Should this include <shadow>?
2617 return node.localName === 'content';
2618 }
2619
2620 function isActiveInsertionPoint(node) {
2621 // <content> inside another <content> or <shadow> is considered inactive.
2622 return node.localName === 'content';
2623 }
2624
2625 function isShadowInsertionPoint(node) {
2626 return node.localName === 'shadow';
2627 }
2628
2629 function isActiveShadowInsertionPoint(node) {
2630 // <shadow> inside another <content> or <shadow> is considered inactive.
2631 return node.localName === 'shadow';
2632 }
2633
2634 function isShadowHost(shadowHost) {
2635 return !!shadowHost.shadowRoot;
2636 }
2637
2638 /**
2639 * @param {WrapperShadowRoot} tree
2640 */
2641 function getNextOlderTree(tree) {
2642 return nextOlderShadowTreeTable.get(tree);
2643 }
2644
2645 function getShadowTrees(host) {
2646 var trees = [];
2647
2648 for (var tree = host.shadowRoot;
2649 tree;
2650 tree = nextOlderShadowTreeTable.get(tree)) {
2651 trees.push(tree);
2652 }
2653 return trees;
2654 }
2655
2656 function assignShadowTreeToShadowInsertionPoint(tree, point) {
2657 insertionParentTable.set(tree, point);
2658 }
2659
2660 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ren dering-shadow-trees
2661 function render(host) {
2662 new ShadowRenderer(host).render();
2663 };
2664
2665 Node.prototype.invalidateShadowRenderer = function(force) {
2666 // TODO: If this is in light DOM we only need to invalidate renderer if this
2667 // is a direct child of a ShadowRoot.
2668 // Maybe we should only associate renderers with direct child nodes of a
2669 // shadow root (and all nodes in the shadow dom).
2670 var renderer = shadowDOMRendererTable.get(this);
2671 if (!renderer)
2672 return false;
2673
2674 var p;
2675 if (force || this.shadowRoot ||
2676 (p = this.parentNode) && (p.shadowRoot || p instanceof ShadowRoot)) {
2677 renderer.invalidate();
2678 }
2679
2680 return true;
2681 };
2682
2683 HTMLContentElement.prototype.getDistributedNodes = function() {
2684 // TODO(arv): We should associate the element with the shadow root so we
2685 // only have to rerender this ShadowRenderer.
2686 renderAllPending();
2687 return getDistributedChildNodes(this);
2688 };
2689
2690 mixin(Node.prototype, {
2691 get insertionParent() {
2692 return insertionParentTable.get(this) || null;
2693 }
2694 });
2695
2696 scope.eventParentsTable = eventParentsTable;
2697 scope.getRendererForHost = getRendererForHost;
2698 scope.getShadowTrees = getShadowTrees;
2699 scope.nextOlderShadowTreeTable = nextOlderShadowTreeTable;
2700 scope.renderAllPending = renderAllPending;
2701
2702 // Exposed for testing
2703 scope.visual = {
2704 removeAllChildNodes: removeAllChildNodes,
2705 appendChild: appendChild,
2706 removeChild: removeChild
2707 };
2708
2709 })(this.ShadowDOMPolyfill);
2710 // Copyright 2013 The Polymer Authors. All rights reserved.
2711 // Use of this source code is goverened by a BSD-style
2712 // license that can be found in the LICENSE file.
2713
2714 (function(scope) {
2715 'use strict';
2716
2717 var GetElementsByInterface = scope.GetElementsByInterface;
2718 var Node = scope.wrappers.Node;
2719 var ParentNodeInterface = scope.ParentNodeInterface;
2720 var SelectorsInterface = scope.SelectorsInterface;
2721 var defineWrapGetter = scope.defineWrapGetter;
2722 var elementFromPoint = scope.elementFromPoint;
2723 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
2724 var mixin = scope.mixin;
2725 var registerWrapper = scope.registerWrapper;
2726 var unwrap = scope.unwrap;
2727 var wrap = scope.wrap;
2728 var wrapEventTargetMethods = scope.wrapEventTargetMethods;
2729 var wrapNodeList = scope.wrapNodeList;
2730
2731 var implementationTable = new SideTable();
2732
2733 function Document(node) {
2734 Node.call(this, node);
2735 }
2736 Document.prototype = Object.create(Node.prototype);
2737
2738 defineWrapGetter(Document, 'documentElement');
2739
2740 // Conceptually both body and head can be in a shadow but suporting that seems
2741 // overkill at this point.
2742 defineWrapGetter(Document, 'body');
2743 defineWrapGetter(Document, 'head');
2744
2745 // document cannot be overridden so we override a bunch of its methods
2746 // directly on the instance.
2747
2748 function wrapMethod(name) {
2749 var original = document[name];
2750 Document.prototype[name] = function() {
2751 return wrap(original.apply(this.impl, arguments));
2752 };
2753 }
2754
2755 [
2756 'getElementById',
2757 'createElement',
2758 'createElementNS',
2759 'createTextNode',
2760 'createDocumentFragment',
2761 'createEvent',
2762 'createEventNS',
2763 ].forEach(wrapMethod);
2764
2765 var originalAdoptNode = document.adoptNode;
2766 var originalWrite = document.write;
2767
2768 mixin(Document.prototype, {
2769 adoptNode: function(node) {
2770 originalAdoptNode.call(this.impl, unwrap(node));
2771 return node;
2772 },
2773 elementFromPoint: function(x, y) {
2774 return elementFromPoint(this, this, x, y);
2775 },
2776 write: function(s) {
2777 var all = this.querySelectorAll('*');
2778 var last = all[all.length - 1];
2779 while (last.nextSibling) {
2780 last = last.nextSibling;
2781 }
2782 var p = last.parentNode;
2783 p.lastChild_ = undefined;
2784 last.nextSibling_ = undefined;
2785 originalWrite.call(this.impl, s);
2786 }
2787 });
2788
2789 // We also override some of the methods on document.body and document.head
2790 // for convenience.
2791 forwardMethodsToWrapper([
2792 window.HTMLBodyElement,
2793 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
2794 window.HTMLHeadElement,
2795 ], [
2796 'appendChild',
2797 'compareDocumentPosition',
2798 'getElementsByClassName',
2799 'getElementsByTagName',
2800 'getElementsByTagNameNS',
2801 'insertBefore',
2802 'querySelector',
2803 'querySelectorAll',
2804 'removeChild',
2805 'replaceChild',
2806 ]);
2807
2808 forwardMethodsToWrapper([
2809 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
2810 ], [
2811 'adoptNode',
2812 'createDocumentFragment',
2813 'createElement',
2814 'createElementNS',
2815 'createEvent',
2816 'createEventNS',
2817 'createTextNode',
2818 'elementFromPoint',
2819 'getElementById',
2820 'write',
2821 ]);
2822
2823 mixin(Document.prototype, GetElementsByInterface);
2824 mixin(Document.prototype, ParentNodeInterface);
2825 mixin(Document.prototype, SelectorsInterface);
2826
2827 mixin(Document.prototype, {
2828 get implementation() {
2829 var implementation = implementationTable.get(this);
2830 if (implementation)
2831 return implementation;
2832 implementation =
2833 new DOMImplementation(unwrap(this).implementation);
2834 implementationTable.set(this, implementation);
2835 return implementation;
2836 }
2837 });
2838
2839 registerWrapper(window.Document, Document,
2840 document.implementation.createHTMLDocument(''));
2841
2842 // Both WebKit and Gecko uses HTMLDocument for document. HTML5/DOM only has
2843 // one Document interface and IE implements the standard correctly.
2844 if (window.HTMLDocument)
2845 registerWrapper(window.HTMLDocument, Document);
2846
2847 wrapEventTargetMethods([
2848 window.HTMLBodyElement,
2849 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
2850 window.HTMLHeadElement,
2851 ]);
2852
2853 function DOMImplementation(impl) {
2854 this.impl = impl;
2855 }
2856
2857 function wrapImplMethod(constructor, name) {
2858 var original = document.implementation[name];
2859 constructor.prototype[name] = function() {
2860 return wrap(original.apply(this.impl, arguments));
2861 };
2862 }
2863
2864 function forwardImplMethod(constructor, name) {
2865 var original = document.implementation[name];
2866 constructor.prototype[name] = function() {
2867 return original.apply(this.impl, arguments);
2868 };
2869 }
2870
2871 wrapImplMethod(DOMImplementation, 'createDocumentType');
2872 wrapImplMethod(DOMImplementation, 'createDocument');
2873 wrapImplMethod(DOMImplementation, 'createHTMLDocument');
2874 forwardImplMethod(DOMImplementation, 'hasFeature');
2875
2876 registerWrapper(window.DOMImplementation, DOMImplementation);
2877
2878 forwardMethodsToWrapper([
2879 window.DOMImplementation,
2880 ], [
2881 'createDocumentType',
2882 'createDocument',
2883 'createHTMLDocument',
2884 'hasFeature',
2885 ]);
2886
2887 scope.wrappers.Document = Document;
2888 scope.wrappers.DOMImplementation = DOMImplementation;
2889
2890 })(this.ShadowDOMPolyfill);
2891
2892 // Copyright 2013 The Polymer Authors. All rights reserved.
2893 // Use of this source code is goverened by a BSD-style
2894 // license that can be found in the LICENSE file.
2895
2896 (function(scope) {
2897 'use strict';
2898
2899 var EventTarget = scope.wrappers.EventTarget;
2900 var mixin = scope.mixin;
2901 var registerWrapper = scope.registerWrapper;
2902 var unwrap = scope.unwrap;
2903 var unwrapIfNeeded = scope.unwrapIfNeeded;
2904 var wrap = scope.wrap;
2905
2906 var OriginalWindow = window.Window;
2907
2908 function Window(impl) {
2909 EventTarget.call(this, impl);
2910 }
2911 Window.prototype = Object.create(EventTarget.prototype);
2912
2913 var originalGetComputedStyle = window.getComputedStyle;
2914 OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {
2915 return originalGetComputedStyle.call(this || window, unwrapIfNeeded(el),
2916 pseudo);
2917 };
2918
2919 ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(
2920 function(name) {
2921 OriginalWindow.prototype[name] = function() {
2922 var w = wrap(this || window);
2923 return w[name].apply(w, arguments);
2924 };
2925 });
2926
2927 mixin(Window.prototype, {
2928 getComputedStyle: function(el, pseudo) {
2929 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el),
2930 pseudo);
2931 }
2932 });
2933
2934 registerWrapper(OriginalWindow, Window);
2935
2936 scope.wrappers.Window = Window;
2937
2938 })(this.ShadowDOMPolyfill);
2939
2940 // Copyright 2013 The Polymer Authors. All rights reserved.
2941 // Use of this source code is goverened by a BSD-style
2942 // license that can be found in the LICENSE file.
2943
2944 (function(scope) {
2945 'use strict';
2946
2947 var defineGetter = scope.defineGetter;
2948 var defineWrapGetter = scope.defineWrapGetter;
2949 var registerWrapper = scope.registerWrapper;
2950 var unwrapIfNeeded = scope.unwrapIfNeeded;
2951 var wrapNodeList = scope.wrapNodeList;
2952 var wrappers = scope.wrappers;
2953
2954 var OriginalMutationObserver = window.MutationObserver ||
2955 window.WebKitMutationObserver;
2956
2957 if (!OriginalMutationObserver)
2958 return;
2959
2960 var OriginalMutationRecord = window.MutationRecord;
2961
2962 function MutationRecord(impl) {
2963 this.impl = impl;
2964 }
2965
2966 MutationRecord.prototype = {
2967 get addedNodes() {
2968 return wrapNodeList(this.impl.addedNodes);
2969 },
2970 get removedNodes() {
2971 return wrapNodeList(this.impl.removedNodes);
2972 }
2973 };
2974
2975 ['target', 'previousSibling', 'nextSibling'].forEach(function(name) {
2976 defineWrapGetter(MutationRecord, name);
2977 });
2978
2979 // WebKit/Blink treats these as instance properties so we override
2980 [
2981 'type',
2982 'attributeName',
2983 'attributeNamespace',
2984 'oldValue'
2985 ].forEach(function(name) {
2986 defineGetter(MutationRecord, name, function() {
2987 return this.impl[name];
2988 });
2989 });
2990
2991 if (OriginalMutationRecord)
2992 registerWrapper(OriginalMutationRecord, MutationRecord);
2993
2994 function wrapRecord(record) {
2995 return new MutationRecord(record);
2996 }
2997
2998 function wrapRecords(records) {
2999 return records.map(wrapRecord);
3000 }
3001
3002 function MutationObserver(callback) {
3003 var self = this;
3004 this.impl = new OriginalMutationObserver(function(mutations, observer) {
3005 callback.call(self, wrapRecords(mutations), self);
3006 });
3007 }
3008
3009 var OriginalNode = window.Node;
3010
3011 MutationObserver.prototype = {
3012 observe: function(target, options) {
3013 this.impl.observe(unwrapIfNeeded(target), options);
3014 },
3015 disconnect: function() {
3016 this.impl.disconnect();
3017 },
3018 takeRecords: function() {
3019 return wrapRecords(this.impl.takeRecords());
3020 }
3021 };
3022
3023 scope.wrappers.MutationObserver = MutationObserver;
3024 scope.wrappers.MutationRecord = MutationRecord;
3025
3026 })(this.ShadowDOMPolyfill);
3027
3028 // Copyright 2013 The Polymer Authors. All rights reserved.
3029 // Use of this source code is goverened by a BSD-style
3030 // license that can be found in the LICENSE file.
3031
3032 (function(scope) {
3033 'use strict';
3034
3035 var isWrapperFor = scope.isWrapperFor;
3036
3037 // This is a list of the elements we currently override the global constructor
3038 // for.
3039 var elements = {
3040 'a': 'HTMLAnchorElement',
3041 'applet': 'HTMLAppletElement',
3042 'area': 'HTMLAreaElement',
3043 'audio': 'HTMLAudioElement',
3044 'br': 'HTMLBRElement',
3045 'base': 'HTMLBaseElement',
3046 'body': 'HTMLBodyElement',
3047 'button': 'HTMLButtonElement',
3048 'canvas': 'HTMLCanvasElement',
3049 // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko.
3050 'dl': 'HTMLDListElement',
3051 'datalist': 'HTMLDataListElement',
3052 'dir': 'HTMLDirectoryElement',
3053 'div': 'HTMLDivElement',
3054 'embed': 'HTMLEmbedElement',
3055 'fieldset': 'HTMLFieldSetElement',
3056 'font': 'HTMLFontElement',
3057 'form': 'HTMLFormElement',
3058 'frame': 'HTMLFrameElement',
3059 'frameset': 'HTMLFrameSetElement',
3060 'hr': 'HTMLHRElement',
3061 'head': 'HTMLHeadElement',
3062 'h1': 'HTMLHeadingElement',
3063 'html': 'HTMLHtmlElement',
3064 'iframe': 'HTMLIFrameElement',
3065
3066 // Uses HTMLSpanElement in Firefox.
3067 // https://bugzilla.mozilla.org/show_bug.cgi?id=843881
3068 // 'image',
3069
3070 'input': 'HTMLInputElement',
3071 'li': 'HTMLLIElement',
3072 'label': 'HTMLLabelElement',
3073 'legend': 'HTMLLegendElement',
3074 'link': 'HTMLLinkElement',
3075 'map': 'HTMLMapElement',
3076 // 'media', Covered by audio and video
3077 'menu': 'HTMLMenuElement',
3078 'menuitem': 'HTMLMenuItemElement',
3079 'meta': 'HTMLMetaElement',
3080 'meter': 'HTMLMeterElement',
3081 'del': 'HTMLModElement',
3082 'ol': 'HTMLOListElement',
3083 'object': 'HTMLObjectElement',
3084 'optgroup': 'HTMLOptGroupElement',
3085 'option': 'HTMLOptionElement',
3086 'output': 'HTMLOutputElement',
3087 'p': 'HTMLParagraphElement',
3088 'param': 'HTMLParamElement',
3089 'pre': 'HTMLPreElement',
3090 'progress': 'HTMLProgressElement',
3091 'q': 'HTMLQuoteElement',
3092 'script': 'HTMLScriptElement',
3093 'select': 'HTMLSelectElement',
3094 'source': 'HTMLSourceElement',
3095 'span': 'HTMLSpanElement',
3096 'style': 'HTMLStyleElement',
3097 'caption': 'HTMLTableCaptionElement',
3098 // WebKit and Moz are wrong:
3099 // https://bugs.webkit.org/show_bug.cgi?id=111469
3100 // https://bugzilla.mozilla.org/show_bug.cgi?id=848096
3101 // 'td': 'HTMLTableCellElement',
3102 'col': 'HTMLTableColElement',
3103 'table': 'HTMLTableElement',
3104 'tr': 'HTMLTableRowElement',
3105 'thead': 'HTMLTableSectionElement',
3106 'tbody': 'HTMLTableSectionElement',
3107 'textarea': 'HTMLTextAreaElement',
3108 'title': 'HTMLTitleElement',
3109 'ul': 'HTMLUListElement',
3110 'video': 'HTMLVideoElement',
3111 };
3112
3113 function overrideConstructor(tagName) {
3114 var nativeConstructorName = elements[tagName];
3115 var nativeConstructor = window[nativeConstructorName];
3116 if (!nativeConstructor)
3117 return;
3118 var element = document.createElement(tagName);
3119 var wrapperConstructor = element.constructor;
3120 window[nativeConstructorName] = wrapperConstructor;
3121 }
3122
3123 Object.keys(elements).forEach(overrideConstructor);
3124
3125 Object.getOwnPropertyNames(scope.wrappers).forEach(function(name) {
3126 window[name] = scope.wrappers[name]
3127 });
3128
3129 // Export for testing.
3130 scope.knownElements = elements;
3131
3132 })(this.ShadowDOMPolyfill);
3133 /*
3134 * Copyright 2013 The Polymer Authors. All rights reserved.
3135 * Use of this source code is governed by a BSD-style
3136 * license that can be found in the LICENSE file.
3137 */
3138 (function() {
3139 var ShadowDOMPolyfill = window.ShadowDOMPolyfill;
3140 var wrap = ShadowDOMPolyfill.wrap;
3141
3142 // patch in prefixed name
3143 Object.defineProperties(HTMLElement.prototype, {
3144 //TODO(sjmiles): review accessor alias with Arv
3145 webkitShadowRoot: {
3146 get: function() {
3147 return this.shadowRoot;
3148 }
3149 }
3150 });
3151
3152 //TODO(sjmiles): review method alias with Arv
3153 HTMLElement.prototype.webkitCreateShadowRoot =
3154 HTMLElement.prototype.createShadowRoot;
3155
3156 // TODO(jmesserly): figure out what to do about these Dart-specific patches
3157 // Right now it depends on some dart2js impl details to patch getTypeNameOf
3158 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?)
3159 window.dartMainRunner = function(main) {
3160 var NodeList = ShadowDOMPolyfill.wrappers.NodeList;
3161 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot;
3162 var isWrapper = ShadowDOMPolyfill.isWrapper;
3163 var unwrap = ShadowDOMPolyfill.unwrap;
3164 var innerTypeNameOf = window.$.getFunctionForTypeNameOf();
3165
3166 function typeNameOfShadowDOM(obj) {
3167 var result;
3168 if (obj instanceof NodeList) {
3169 result = 'NodeList';
3170 } else if (obj instanceof ShadowRoot) {
3171 result = 'ShadowRoot';
3172 } else if (obj instanceof MutationRecord) {
3173 result = 'MutationRecord';
3174 } else if (obj instanceof MutationObserver) {
3175 result = 'MutationObserver';
3176 } else {
3177 if (isWrapper(obj)) {
3178 obj = unwrap(obj);
3179
3180 // Fix up class names for Firefox. For some of them like
3181 // HTMLFormElement and HTMLInputElement, the "constructor" property of
3182 // the unwrapped nodes points at the wrapper for some reason.
3183 // TODO(jmesserly): figure out why this is happening.
3184 var ctor = obj.constructor;
3185 if (ctor && !ctor.builtin$cls && ctor.name == 'GeneratedWrapper') {
3186 var name = Object.prototype.toString.call(obj);
3187 name = name.substring(8, name.length - 1);
3188 ctor.builtin$cls = name;
3189 }
3190 }
3191
3192 result = innerTypeNameOf.call$1(obj);
3193 }
3194
3195 return result;
3196 }
3197
3198 function constructorNameShadowDOM(object) {
3199 var $constructor, $name, string;
3200 if (object == null)
3201 return "Null";
3202 $constructor = object.constructor;
3203 if (typeof $constructor === "function") {
3204 $name = $constructor.builtin$cls;
3205 if ($name != null)
3206 return $name;
3207 }
3208
3209 }
3210
3211 window.$.constructorNameFallback = constructorNameShadowDOM;
3212 window.$._getTypeNameOf = { call$1: typeNameOfShadowDOM };
3213 window.Isolate.$isolateProperties._getTypeNameOf = window.$._getTypeNameOf;
3214
3215 // Invoke the real main
3216 main();
3217 };
3218
3219 })();
3220
3221 }
OLDNEW
« no previous file with comments | « lib/scoped_css.dart ('k') | lib/shadowdom.min.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698