Index: lib/shadowdom.debug.js |
diff --git a/lib/shadowdom.debug.js b/lib/shadowdom.debug.js |
deleted file mode 100644 |
index dc87a193258414d10a8c251a575cc418c40f7f0f..0000000000000000000000000000000000000000 |
--- a/lib/shadowdom.debug.js |
+++ /dev/null |
@@ -1,3221 +0,0 @@ |
-if ((!HTMLElement.prototype.createShadowRoot && |
- !HTMLElement.prototype.webkitCreateShadowRoot) || |
- window.__forceShadowDomPolyfill) { |
- |
-/* |
- * Copyright 2013 The Polymer Authors. All rights reserved. |
- * Use of this source code is governed by a BSD-style |
- * license that can be found in the LICENSE file. |
- */ |
-(function() { |
- // TODO(jmesserly): fix dart:html to use unprefixed name |
- if (Element.prototype.webkitCreateShadowRoot) { |
- Element.prototype.webkitCreateShadowRoot = function() { |
- return window.ShadowDOMPolyfill.wrapIfNeeded(this).createShadowRoot(); |
- }; |
- } |
-})(); |
- |
-/* |
- * Copyright 2012 The Polymer Authors. All rights reserved. |
- * Use of this source code is goverened by a BSD-style |
- * license that can be found in the LICENSE file. |
- */ |
- |
-// SideTable is a weak map where possible. If WeakMap is not available the |
-// association is stored as an expando property. |
-var SideTable; |
-// TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox |
-if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) { |
- SideTable = WeakMap; |
-} else { |
- (function() { |
- var defineProperty = Object.defineProperty; |
- var hasOwnProperty = Object.hasOwnProperty; |
- var counter = new Date().getTime() % 1e9; |
- |
- SideTable = function() { |
- this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__'); |
- }; |
- |
- SideTable.prototype = { |
- set: function(key, value) { |
- defineProperty(key, this.name, {value: value, writable: true}); |
- }, |
- get: function(key) { |
- return hasOwnProperty.call(key, this.name) ? key[this.name] : undefined; |
- }, |
- delete: function(key) { |
- this.set(key, undefined); |
- } |
- } |
- })(); |
-} |
- |
-// Copyright 2012 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-var ShadowDOMPolyfill = {}; |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var wrapperTable = new SideTable(); |
- var constructorTable = new SideTable(); |
- var wrappers = Object.create(null); |
- |
- function assert(b) { |
- if (!b) |
- throw new Error('Assertion failed'); |
- }; |
- |
- function mixin(to, from) { |
- Object.getOwnPropertyNames(from).forEach(function(name) { |
- Object.defineProperty(to, name, |
- Object.getOwnPropertyDescriptor(from, name)); |
- }); |
- return to; |
- }; |
- |
- function mixinStatics(to, from) { |
- Object.getOwnPropertyNames(from).forEach(function(name) { |
- switch (name) { |
- case 'arguments': |
- case 'caller': |
- case 'length': |
- case 'name': |
- case 'prototype': |
- case 'toString': |
- return; |
- } |
- Object.defineProperty(to, name, |
- Object.getOwnPropertyDescriptor(from, name)); |
- }); |
- return to; |
- }; |
- |
- // Mozilla's old DOM bindings are bretty busted: |
- // https://bugzilla.mozilla.org/show_bug.cgi?id=855844 |
- // Make sure they are create before we start modifying things. |
- Object.getOwnPropertyNames(window); |
- |
- function getWrapperConstructor(node) { |
- var nativePrototype = node.__proto__ || Object.getPrototypeOf(node); |
- var wrapperConstructor = constructorTable.get(nativePrototype); |
- if (wrapperConstructor) |
- return wrapperConstructor; |
- |
- var parentWrapperConstructor = getWrapperConstructor(nativePrototype); |
- |
- var GeneratedWrapper = createWrapperConstructor(parentWrapperConstructor); |
- registerInternal(nativePrototype, GeneratedWrapper, node); |
- |
- return GeneratedWrapper; |
- } |
- |
- function addForwardingProperties(nativePrototype, wrapperPrototype) { |
- installProperty(nativePrototype, wrapperPrototype, true); |
- } |
- |
- function registerInstanceProperties(wrapperPrototype, instanceObject) { |
- installProperty(instanceObject, wrapperPrototype, false); |
- } |
- |
- var isFirefox = /Firefox/.test(navigator.userAgent); |
- |
- // This is used as a fallback when getting the descriptor fails in |
- // installProperty. |
- var dummyDescriptor = { |
- get: function() {}, |
- set: function(v) {}, |
- configurable: true, |
- enumerable: true |
- }; |
- |
- function installProperty(source, target, allowMethod) { |
- Object.getOwnPropertyNames(source).forEach(function(name) { |
- if (name in target) |
- return; |
- |
- if (isFirefox) { |
- // Tickle Firefox's old bindings. |
- source.__lookupGetter__(name); |
- } |
- var descriptor; |
- try { |
- descriptor = Object.getOwnPropertyDescriptor(source, name); |
- } catch (ex) { |
- // JSC and V8 both use data properties instead accessors which can cause |
- // getting the property desciptor throw an exception. |
- // https://bugs.webkit.org/show_bug.cgi?id=49739 |
- descriptor = dummyDescriptor; |
- } |
- var getter, setter; |
- if (allowMethod && typeof descriptor.value === 'function') { |
- target[name] = function() { |
- return this.impl[name].apply(this.impl, arguments); |
- }; |
- return; |
- } |
- |
- getter = function() { |
- return this.impl[name]; |
- }; |
- |
- if (descriptor.writable || descriptor.set) { |
- setter = function(value) { |
- this.impl[name] = value; |
- }; |
- } |
- |
- Object.defineProperty(target, name, { |
- get: getter, |
- set: setter, |
- configurable: descriptor.configurable, |
- enumerable: descriptor.enumerable |
- }); |
- }); |
- } |
- |
- /** |
- * @param {Function} nativeConstructor |
- * @param {Function} wrapperConstructor |
- * @param {string|Object=} opt_instance If present, this is used to extract |
- * properties from an instance object. If this is a string |
- * |document.createElement| is used to create an instance. |
- */ |
- function register(nativeConstructor, wrapperConstructor, opt_instance) { |
- var nativePrototype = nativeConstructor.prototype; |
- registerInternal(nativePrototype, wrapperConstructor, opt_instance); |
- mixinStatics(wrapperConstructor, nativeConstructor); |
- } |
- |
- function registerInternal(nativePrototype, wrapperConstructor, opt_instance) { |
- var wrapperPrototype = wrapperConstructor.prototype; |
- assert(constructorTable.get(nativePrototype) === undefined); |
- constructorTable.set(nativePrototype, wrapperConstructor); |
- addForwardingProperties(nativePrototype, wrapperPrototype); |
- if (opt_instance) |
- registerInstanceProperties(wrapperPrototype, opt_instance); |
- } |
- |
- function isWrapperFor(wrapperConstructor, nativeConstructor) { |
- return constructorTable.get(nativeConstructor.prototype) === |
- wrapperConstructor; |
- } |
- |
- /** |
- * Creates a generic wrapper constructor based on |object| and its |
- * constructor. |
- * Sometimes the constructor does not have an associated instance |
- * (CharacterData for example). In that case you can pass the constructor that |
- * you want to map the object to using |opt_nativeConstructor|. |
- * @param {Node} object |
- * @param {Function=} opt_nativeConstructor |
- * @return {Function} The generated constructor. |
- */ |
- function registerObject(object) { |
- var nativePrototype = Object.getPrototypeOf(object); |
- |
- var superWrapperConstructor = getWrapperConstructor(nativePrototype); |
- var GeneratedWrapper = createWrapperConstructor(superWrapperConstructor); |
- registerInternal(nativePrototype, GeneratedWrapper, object); |
- |
- return GeneratedWrapper; |
- } |
- |
- function createWrapperConstructor(superWrapperConstructor) { |
- function GeneratedWrapper(node) { |
- superWrapperConstructor.call(this, node); |
- } |
- GeneratedWrapper.prototype = |
- Object.create(superWrapperConstructor.prototype); |
- GeneratedWrapper.prototype.constructor = GeneratedWrapper; |
- |
- return GeneratedWrapper; |
- } |
- |
- var OriginalDOMImplementation = DOMImplementation; |
- var OriginalEvent = Event; |
- var OriginalNode = Node; |
- var OriginalWindow = Window; |
- |
- function isWrapper(object) { |
- return object instanceof wrappers.EventTarget || |
- object instanceof wrappers.Event || |
- object instanceof wrappers.DOMImplementation; |
- } |
- |
- function isNative(object) { |
- return object instanceof OriginalNode || |
- object instanceof OriginalEvent || |
- object instanceof OriginalWindow || |
- object instanceof OriginalDOMImplementation; |
- } |
- |
- /** |
- * Wraps a node in a WrapperNode. If there already exists a wrapper for the |
- * |node| that wrapper is returned instead. |
- * @param {Node} node |
- * @return {WrapperNode} |
- */ |
- function wrap(impl) { |
- if (impl === null) |
- return null; |
- |
- assert(isNative(impl)); |
- var wrapper = wrapperTable.get(impl); |
- if (!wrapper) { |
- var wrapperConstructor = getWrapperConstructor(impl); |
- wrapper = new wrapperConstructor(impl); |
- wrapperTable.set(impl, wrapper); |
- } |
- return wrapper; |
- } |
- |
- /** |
- * Unwraps a wrapper and returns the node it is wrapping. |
- * @param {WrapperNode} wrapper |
- * @return {Node} |
- */ |
- function unwrap(wrapper) { |
- if (wrapper === null) |
- return null; |
- assert(isWrapper(wrapper)); |
- return wrapper.impl; |
- } |
- |
- /** |
- * Unwraps object if it is a wrapper. |
- * @param {Object} object |
- * @return {Object} The native implementation object. |
- */ |
- function unwrapIfNeeded(object) { |
- return object && isWrapper(object) ? unwrap(object) : object; |
- } |
- |
- /** |
- * Wraps object if it is not a wrapper. |
- * @param {Object} object |
- * @return {Object} The wrapper for object. |
- */ |
- function wrapIfNeeded(object) { |
- return object && !isWrapper(object) ? wrap(object) : object; |
- } |
- |
- /** |
- * Overrides the current wrapper (if any) for node. |
- * @param {Node} node |
- * @param {WrapperNode=} wrapper If left out the wrapper will be created as |
- * needed next time someone wraps the node. |
- */ |
- function rewrap(node, wrapper) { |
- if (wrapper === null) |
- return; |
- assert(isNative(node)); |
- assert(wrapper === undefined || isWrapper(wrapper)); |
- wrapperTable.set(node, wrapper); |
- } |
- |
- function defineGetter(constructor, name, getter) { |
- Object.defineProperty(constructor.prototype, name, { |
- get: getter, |
- configurable: true, |
- enumerable: true |
- }); |
- } |
- |
- function defineWrapGetter(constructor, name) { |
- defineGetter(constructor, name, function() { |
- return wrap(this.impl[name]); |
- }); |
- } |
- |
- /** |
- * Forwards existing methods on the native object to the wrapper methods. |
- * This does not wrap any of the arguments or the return value since the |
- * wrapper implementation already takes care of that. |
- * @param {Array.<Function>} constructors |
- * @parem {Array.<string>} names |
- */ |
- function forwardMethodsToWrapper(constructors, names) { |
- constructors.forEach(function(constructor) { |
- names.forEach(function(name) { |
- constructor.prototype[name] = function() { |
- var w = wrap(this); |
- return w[name].apply(w, arguments); |
- }; |
- }); |
- }); |
- } |
- |
- scope.assert = assert; |
- scope.defineGetter = defineGetter; |
- scope.defineWrapGetter = defineWrapGetter; |
- scope.forwardMethodsToWrapper = forwardMethodsToWrapper; |
- scope.isWrapper = isWrapper; |
- scope.isWrapperFor = isWrapperFor; |
- scope.mixin = mixin; |
- scope.registerObject = registerObject; |
- scope.registerWrapper = register; |
- scope.rewrap = rewrap; |
- scope.unwrap = unwrap; |
- scope.unwrapIfNeeded = unwrapIfNeeded; |
- scope.wrap = wrap; |
- scope.wrapIfNeeded = wrapIfNeeded; |
- scope.wrappers = wrappers; |
- |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- var unwrap = scope.unwrap; |
- var wrap = scope.wrap; |
- var wrappers = scope.wrappers; |
- |
- var wrappedFuns = new SideTable(); |
- var listenersTable = new SideTable(); |
- var handledEventsTable = new SideTable(); |
- var targetTable = new SideTable(); |
- var currentTargetTable = new SideTable(); |
- var relatedTargetTable = new SideTable(); |
- var eventPhaseTable = new SideTable(); |
- var stopPropagationTable = new SideTable(); |
- var stopImmediatePropagationTable = new SideTable(); |
- |
- function isShadowRoot(node) { |
- return node instanceof wrappers.ShadowRoot; |
- } |
- |
- function isInsertionPoint(node) { |
- var localName = node.localName; |
- return localName === 'content' || localName === 'shadow'; |
- } |
- |
- function isShadowHost(node) { |
- return !!node.shadowRoot; |
- } |
- |
- function getEventParent(node) { |
- var dv; |
- return node.parentNode || (dv = node.defaultView) && wrap(dv) || null; |
- } |
- |
- // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn-adjusted-parent |
- function calculateParents(node, context, ancestors) { |
- if (ancestors.length) |
- return ancestors.shift(); |
- |
- // 1. |
- if (isShadowRoot(node)) |
- return node.insertionParent || scope.getHostForShadowRoot(node); |
- |
- // 2. |
- var eventParents = scope.eventParentsTable.get(node); |
- if (eventParents) { |
- // Copy over the remaining event parents for next iteration. |
- for (var i = 1; i < eventParents.length; i++) { |
- ancestors[i - 1] = eventParents[i]; |
- } |
- return eventParents[0]; |
- } |
- |
- // 3. |
- if (context && isInsertionPoint(node)) { |
- var parentNode = node.parentNode; |
- if (parentNode && isShadowHost(parentNode)) { |
- var trees = scope.getShadowTrees(parentNode); |
- var p = context.insertionParent; |
- for (var i = 0; i < trees.length; i++) { |
- if (trees[i].contains(p)) |
- return p; |
- } |
- } |
- } |
- |
- return getEventParent(node); |
- } |
- |
- // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#event-retargeting |
- function retarget(node) { |
- var stack = []; // 1. |
- var ancestor = node; // 2. |
- var targets = []; |
- var ancestors = []; |
- while (ancestor) { // 3. |
- var context = null; // 3.2. |
- // TODO(arv): Change order of these. If the stack is empty we always end |
- // up pushing ancestor, no matter what. |
- if (isInsertionPoint(ancestor)) { // 3.1. |
- context = topMostNotInsertionPoint(stack); // 3.1.1. |
- var top = stack[stack.length - 1] || ancestor; // 3.1.2. |
- stack.push(top); |
- } else if (!stack.length) { |
- stack.push(ancestor); // 3.3. |
- } |
- var target = stack[stack.length - 1]; // 3.4. |
- targets.push({target: target, currentTarget: ancestor}); // 3.5. |
- if (isShadowRoot(ancestor)) // 3.6. |
- stack.pop(); // 3.6.1. |
- |
- ancestor = calculateParents(ancestor, context, ancestors); // 3.7. |
- } |
- return targets; |
- } |
- |
- function topMostNotInsertionPoint(stack) { |
- for (var i = stack.length - 1; i >= 0; i--) { |
- if (!isInsertionPoint(stack[i])) |
- return stack[i]; |
- } |
- return null; |
- } |
- |
- // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn-adjusted-related-target |
- function adjustRelatedTarget(target, related) { |
- var ancestors = []; |
- while (target) { // 3. |
- var stack = []; // 3.1. |
- var ancestor = related; // 3.2. |
- var last = undefined; // 3.3. Needs to be reset every iteration. |
- while (ancestor) { |
- var context = null; |
- if (!stack.length) { |
- stack.push(ancestor); |
- } else { |
- if (isInsertionPoint(ancestor)) { // 3.4.3. |
- context = topMostNotInsertionPoint(stack); |
- // isDistributed is more general than checking whether last is |
- // assigned into ancestor. |
- if (isDistributed(last)) { // 3.4.3.2. |
- var head = stack[stack.length - 1]; |
- stack.push(head); |
- } |
- } |
- } |
- |
- if (inSameTree(ancestor, target)) // 3.4.4. |
- return stack[stack.length - 1]; |
- |
- if (isShadowRoot(ancestor)) // 3.4.5. |
- stack.pop(); |
- |
- last = ancestor; // 3.4.6. |
- ancestor = calculateParents(ancestor, context, ancestors); // 3.4.7. |
- } |
- if (isShadowRoot(target)) // 3.5. |
- target = scope.getHostForShadowRoot(target); |
- else |
- target = target.parentNode; // 3.6. |
- } |
- } |
- |
- function isDistributed(node) { |
- return node.insertionParent; |
- } |
- |
- function rootOfNode(node) { |
- var p; |
- while (p = node.parentNode) { |
- node = p; |
- } |
- return node; |
- } |
- |
- function inSameTree(a, b) { |
- return rootOfNode(a) === rootOfNode(b); |
- } |
- |
- function isMutationEvent(type) { |
- switch (type) { |
- case 'DOMAttrModified': |
- case 'DOMAttributeNameChanged': |
- case 'DOMCharacterDataModified': |
- case 'DOMElementNameChanged': |
- case 'DOMNodeInserted': |
- case 'DOMNodeInsertedIntoDocument': |
- case 'DOMNodeRemoved': |
- case 'DOMNodeRemovedFromDocument': |
- case 'DOMSubtreeModified': |
- return true; |
- } |
- return false; |
- } |
- |
- function dispatchOriginalEvent(originalEvent) { |
- // Make sure this event is only dispatched once. |
- if (handledEventsTable.get(originalEvent)) |
- return; |
- handledEventsTable.set(originalEvent, true); |
- |
- // Don't do rendering if this is a mutation event since rendering might |
- // mutate the DOM which would fire more events and we would most likely |
- // just iloop. |
- if (!isMutationEvent(originalEvent.type)) |
- scope.renderAllPending(); |
- |
- var target = wrap(originalEvent.target); |
- var event = wrap(originalEvent); |
- return dispatchEvent(event, target); |
- } |
- |
- function dispatchEvent(event, originalWrapperTarget) { |
- var eventPath = retarget(originalWrapperTarget); |
- |
- // For window load events the load event is dispatched at the window but |
- // the target is set to the document. |
- // |
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end |
- // |
- // TODO(arv): Find a loess hacky way to do this. |
- if (event.type === 'load' && |
- eventPath.length === 2 && |
- eventPath[0].target instanceof wrappers.Document) { |
- eventPath.shift(); |
- } |
- |
- if (dispatchCapturing(event, eventPath)) { |
- if (dispatchAtTarget(event, eventPath)) { |
- dispatchBubbling(event, eventPath); |
- } |
- } |
- |
- eventPhaseTable.set(event, Event.NONE); |
- currentTargetTable.set(event, null); |
- |
- return event.defaultPrevented; |
- } |
- |
- function dispatchCapturing(event, eventPath) { |
- var phase; |
- |
- for (var i = eventPath.length - 1; i > 0; i--) { |
- var target = eventPath[i].target; |
- var currentTarget = eventPath[i].currentTarget; |
- if (target === currentTarget) |
- continue; |
- |
- phase = Event.CAPTURING_PHASE; |
- if (!invoke(eventPath[i], event, phase)) |
- return false; |
- } |
- |
- return true; |
- } |
- |
- function dispatchAtTarget(event, eventPath) { |
- var phase = Event.AT_TARGET; |
- return invoke(eventPath[0], event, phase); |
- } |
- |
- function dispatchBubbling(event, eventPath) { |
- var bubbles = event.bubbles; |
- var phase; |
- |
- for (var i = 1; i < eventPath.length; i++) { |
- var target = eventPath[i].target; |
- var currentTarget = eventPath[i].currentTarget; |
- if (target === currentTarget) |
- phase = Event.AT_TARGET; |
- else if (bubbles && !stopImmediatePropagationTable.get(event)) |
- phase = Event.BUBBLING_PHASE; |
- else |
- continue; |
- |
- if (!invoke(eventPath[i], event, phase)) |
- return; |
- } |
- } |
- |
- function invoke(tuple, event, phase) { |
- var target = tuple.target; |
- var currentTarget = tuple.currentTarget; |
- |
- var listeners = listenersTable.get(currentTarget); |
- if (!listeners) |
- return true; |
- |
- if ('relatedTarget' in event) { |
- var originalEvent = unwrap(event); |
- var relatedTarget = wrap(originalEvent.relatedTarget); |
- |
- var adjusted = adjustRelatedTarget(currentTarget, relatedTarget); |
- if (adjusted === target) |
- return true; |
- |
- relatedTargetTable.set(event, adjusted); |
- } |
- |
- eventPhaseTable.set(event, phase); |
- var type = event.type; |
- |
- var anyRemoved = false; |
- targetTable.set(event, target); |
- currentTargetTable.set(event, currentTarget); |
- |
- for (var i = 0; i < listeners.length; i++) { |
- var listener = listeners[i]; |
- if (listener.removed) { |
- anyRemoved = true; |
- continue; |
- } |
- |
- if (listener.type !== type || |
- !listener.capture && phase === Event.CAPTURING_PHASE || |
- listener.capture && phase === Event.BUBBLING_PHASE) { |
- continue; |
- } |
- |
- try { |
- if (typeof listener.handler === 'function') |
- listener.handler.call(currentTarget, event); |
- else |
- listener.handler.handleEvent(event); |
- |
- if (stopImmediatePropagationTable.get(event)) |
- return false; |
- |
- } catch (ex) { |
- if (window.onerror) |
- window.onerror(ex.message); |
- else |
- console.error(ex); |
- } |
- } |
- |
- if (anyRemoved) { |
- var copy = listeners.slice(); |
- listeners.length = 0; |
- for (var i = 0; i < copy.length; i++) { |
- if (!copy[i].removed) |
- listeners.push(copy[i]); |
- } |
- } |
- |
- return !stopPropagationTable.get(event); |
- } |
- |
- function Listener(type, handler, capture) { |
- this.type = type; |
- this.handler = handler; |
- this.capture = Boolean(capture); |
- } |
- Listener.prototype = { |
- equals: function(that) { |
- return this.handler === that.handler && this.type === that.type && |
- this.capture === that.capture; |
- }, |
- get removed() { |
- return this.handler === null; |
- }, |
- remove: function() { |
- this.handler = null; |
- } |
- }; |
- |
- var OriginalEvent = window.Event; |
- |
- /** |
- * Creates a new Event wrapper or wraps an existin native Event object. |
- * @param {string|Event} type |
- * @param {Object=} options |
- * @constructor |
- */ |
- function Event(type, options) { |
- if (type instanceof OriginalEvent) |
- this.impl = type; |
- else |
- return wrap(constructEvent(OriginalEvent, 'Event', type, options)); |
- } |
- Event.prototype = { |
- get target() { |
- return targetTable.get(this); |
- }, |
- get currentTarget() { |
- return currentTargetTable.get(this); |
- }, |
- get eventPhase() { |
- return eventPhaseTable.get(this); |
- }, |
- stopPropagation: function() { |
- stopPropagationTable.set(this, true); |
- }, |
- stopImmediatePropagation: function() { |
- stopPropagationTable.set(this, true); |
- stopImmediatePropagationTable.set(this, true); |
- } |
- }; |
- registerWrapper(OriginalEvent, Event, document.createEvent('Event')); |
- |
- function unwrapOptions(options) { |
- if (!options || !options.relatedTarget) |
- return options; |
- return Object.create(options, { |
- relatedTarget: {value: unwrap(options.relatedTarget)} |
- }); |
- } |
- |
- function registerGenericEvent(name, SuperEvent, prototype) { |
- var OriginalEvent = window[name]; |
- var GenericEvent = function(type, options) { |
- if (type instanceof OriginalEvent) |
- this.impl = type; |
- else |
- return wrap(constructEvent(OriginalEvent, name, type, options)); |
- }; |
- GenericEvent.prototype = Object.create(SuperEvent.prototype); |
- if (prototype) |
- mixin(GenericEvent.prototype, prototype); |
- // Firefox does not support FocusEvent |
- // https://bugzilla.mozilla.org/show_bug.cgi?id=855741 |
- if (OriginalEvent) |
- registerWrapper(OriginalEvent, GenericEvent, document.createEvent(name)); |
- return GenericEvent; |
- } |
- |
- var UIEvent = registerGenericEvent('UIEvent', Event); |
- var CustomEvent = registerGenericEvent('CustomEvent', Event); |
- |
- var relatedTargetProto = { |
- get relatedTarget() { |
- return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget); |
- } |
- }; |
- |
- function getInitFunction(name, relatedTargetIndex) { |
- return function() { |
- arguments[relatedTargetIndex] = unwrap(arguments[relatedTargetIndex]); |
- var impl = unwrap(this); |
- impl[name].apply(impl, arguments); |
- }; |
- } |
- |
- var mouseEventProto = mixin({ |
- initMouseEvent: getInitFunction('initMouseEvent', 14) |
- }, relatedTargetProto); |
- |
- var focusEventProto = mixin({ |
- initFocusEvent: getInitFunction('initFocusEvent', 5) |
- }, relatedTargetProto); |
- |
- var MouseEvent = registerGenericEvent('MouseEvent', UIEvent, mouseEventProto); |
- var FocusEvent = registerGenericEvent('FocusEvent', UIEvent, focusEventProto); |
- |
- var MutationEvent = registerGenericEvent('MutationEvent', Event, { |
- initMutationEvent: getInitFunction('initMutationEvent', 3), |
- get relatedNode() { |
- return wrap(this.impl.relatedNode); |
- }, |
- }); |
- |
- // In case the browser does not support event constructors we polyfill that |
- // by calling `createEvent('Foo')` and `initFooEvent` where the arguments to |
- // `initFooEvent` are derived from the registered default event init dict. |
- var defaultInitDicts = Object.create(null); |
- |
- var supportsEventConstructors = (function() { |
- try { |
- new window.MouseEvent('click'); |
- } catch (ex) { |
- return false; |
- } |
- return true; |
- })(); |
- |
- /** |
- * Constructs a new native event. |
- */ |
- function constructEvent(OriginalEvent, name, type, options) { |
- if (supportsEventConstructors) |
- return new OriginalEvent(type, unwrapOptions(options)); |
- |
- // Create the arguments from the default dictionary. |
- var event = unwrap(document.createEvent(name)); |
- var defaultDict = defaultInitDicts[name]; |
- var args = [type]; |
- Object.keys(defaultDict).forEach(function(key) { |
- var v = options != null && key in options ? |
- options[key] : defaultDict[key]; |
- if (key === 'relatedTarget') |
- v = unwrap(v); |
- args.push(v); |
- }); |
- event['init' + name].apply(event, args); |
- return event; |
- } |
- |
- if (!supportsEventConstructors) { |
- var configureEventConstructor = function(name, initDict, superName) { |
- if (superName) { |
- var superDict = defaultInitDicts[superName]; |
- initDict = mixin(mixin({}, superDict), initDict); |
- } |
- |
- defaultInitDicts[name] = initDict; |
- }; |
- |
- // The order of the default event init dictionary keys is important, the |
- // arguments to initFooEvent is derived from that. |
- configureEventConstructor('Event', {bubbles: false, cancelable: false}); |
- configureEventConstructor('CustomEvent', {detail: null}, 'Event'); |
- configureEventConstructor('UIEvent', {view: null, detail: 0}, 'Event'); |
- configureEventConstructor('MouseEvent', { |
- screenX: 0, |
- screenY: 0, |
- clientX: 0, |
- clientY: 0, |
- ctrlKey: false, |
- altKey: false, |
- shiftKey: false, |
- metaKey: false, |
- button: 0, |
- relatedTarget: null |
- }, 'UIEvent'); |
- configureEventConstructor('FocusEvent', {relatedTarget: null}, 'UIEvent'); |
- } |
- |
- function isValidListener(fun) { |
- if (typeof fun === 'function') |
- return true; |
- return fun && fun.handleEvent; |
- } |
- |
- var OriginalEventTarget = window.EventTarget; |
- |
- /** |
- * This represents a wrapper for an EventTarget. |
- * @param {!EventTarget} impl The original event target. |
- * @constructor |
- */ |
- function EventTarget(impl) { |
- this.impl = impl; |
- } |
- |
- // Node and Window have different internal type checks in WebKit so we cannot |
- // use the same method as the original function. |
- var methodNames = [ |
- 'addEventListener', |
- 'removeEventListener', |
- 'dispatchEvent' |
- ]; |
- |
- [Element, Window, Document].forEach(function(constructor) { |
- var p = constructor.prototype; |
- methodNames.forEach(function(name) { |
- Object.defineProperty(p, name + '_', {value: p[name]}); |
- }); |
- }); |
- |
- function getTargetToListenAt(wrapper) { |
- if (wrapper instanceof wrappers.ShadowRoot) |
- wrapper = scope.getHostForShadowRoot(wrapper); |
- return unwrap(wrapper); |
- } |
- |
- EventTarget.prototype = { |
- addEventListener: function(type, fun, capture) { |
- if (!isValidListener(fun)) |
- return; |
- |
- var listener = new Listener(type, fun, capture); |
- var listeners = listenersTable.get(this); |
- if (!listeners) { |
- listeners = []; |
- listenersTable.set(this, listeners); |
- } else { |
- // Might have a duplicate. |
- for (var i = 0; i < listeners.length; i++) { |
- if (listener.equals(listeners[i])) |
- return; |
- } |
- } |
- |
- listeners.push(listener); |
- |
- var target = getTargetToListenAt(this); |
- target.addEventListener_(type, dispatchOriginalEvent, true); |
- }, |
- removeEventListener: function(type, fun, capture) { |
- capture = Boolean(capture); |
- var listeners = listenersTable.get(this); |
- if (!listeners) |
- return; |
- var count = 0, found = false; |
- for (var i = 0; i < listeners.length; i++) { |
- if (listeners[i].type === type && listeners[i].capture === capture) { |
- count++; |
- if (listeners[i].handler === fun) { |
- found = true; |
- listeners[i].remove(); |
- } |
- } |
- } |
- |
- if (found && count === 1) { |
- var target = getTargetToListenAt(this); |
- target.removeEventListener_(type, dispatchOriginalEvent, true); |
- } |
- }, |
- dispatchEvent: function(event) { |
- scope.renderAllPending(); |
- var target = getTargetToListenAt(this); |
- return target.dispatchEvent_(unwrap(event)); |
- } |
- }; |
- |
- if (OriginalEventTarget) |
- registerWrapper(OriginalEventTarget, EventTarget); |
- |
- function wrapEventTargetMethods(constructors) { |
- forwardMethodsToWrapper(constructors, methodNames); |
- } |
- |
- |
- var originalElementFromPoint = document.elementFromPoint; |
- |
- function elementFromPoint(self, document, x, y) { |
- scope.renderAllPending(); |
- |
- var element = wrap(originalElementFromPoint.call(document.impl, x, y)); |
- var targets = retarget(element, this) |
- for (var i = 0; i < targets.length; i++) { |
- var target = targets[i]; |
- if (target.currentTarget === self) |
- return target.target; |
- } |
- return null; |
- } |
- |
- scope.adjustRelatedTarget = adjustRelatedTarget; |
- scope.elementFromPoint = elementFromPoint; |
- scope.wrapEventTargetMethods = wrapEventTargetMethods; |
- scope.wrappers.CustomEvent = CustomEvent; |
- scope.wrappers.Event = Event; |
- scope.wrappers.EventTarget = EventTarget; |
- scope.wrappers.FocusEvent = FocusEvent; |
- scope.wrappers.MouseEvent = MouseEvent; |
- scope.wrappers.MutationEvent = MutationEvent; |
- scope.wrappers.UIEvent = UIEvent; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2012 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var wrap = scope.wrap; |
- |
- function nonEnum(obj, prop) { |
- Object.defineProperty(obj, prop, {enumerable: false}); |
- } |
- |
- function NodeList() { |
- this.length = 0; |
- nonEnum(this, 'length'); |
- } |
- NodeList.prototype = { |
- item: function(index) { |
- return this[index]; |
- } |
- }; |
- nonEnum(NodeList.prototype, 'item'); |
- |
- function wrapNodeList(list) { |
- if (list == null) |
- return list; |
- var wrapperList = new NodeList(); |
- for (var i = 0, length = list.length; i < length; i++) { |
- wrapperList[i] = wrap(list[i]); |
- } |
- wrapperList.length = length; |
- return wrapperList; |
- } |
- |
- function addWrapNodeListMethod(wrapperConstructor, name) { |
- wrapperConstructor.prototype[name] = function() { |
- return wrapNodeList(this.impl[name].apply(this.impl, arguments)); |
- }; |
- } |
- |
- scope.wrappers.NodeList = NodeList; |
- scope.addWrapNodeListMethod = addWrapNodeListMethod; |
- scope.wrapNodeList = wrapNodeList; |
- |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2012 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var EventTarget = scope.wrappers.EventTarget; |
- var NodeList = scope.wrappers.NodeList; |
- var defineWrapGetter = scope.defineWrapGetter; |
- var assert = scope.assert; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- var unwrap = scope.unwrap; |
- var wrap = scope.wrap; |
- |
- function assertIsNodeWrapper(node) { |
- assert(node instanceof Node); |
- } |
- |
- /** |
- * Collects nodes from a DocumentFragment or a Node for removal followed |
- * by an insertion. |
- * |
- * This updates the internal pointers for node, previousNode and nextNode. |
- */ |
- function collectNodes(node, parentNode, previousNode, nextNode) { |
- if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) { |
- if (node.parentNode) |
- node.parentNode.removeChild(node); |
- node.parentNode_ = parentNode; |
- node.previousSibling_ = previousNode; |
- node.nextSibling_ = nextNode; |
- if (previousNode) |
- previousNode.nextSibling_ = node; |
- if (nextNode) |
- nextNode.previousSibling_ = node; |
- return [node]; |
- } |
- |
- var nodes = []; |
- var firstChild; |
- while (firstChild = node.firstChild) { |
- node.removeChild(firstChild); |
- nodes.push(firstChild); |
- firstChild.parentNode_ = parentNode; |
- } |
- |
- for (var i = 0; i < nodes.length; i++) { |
- nodes[i].previousSibling_ = nodes[i - 1] || previousNode; |
- nodes[i].nextSibling_ = nodes[i + 1] || nextNode; |
- } |
- |
- if (previousNode) |
- previousNode.nextSibling_ = nodes[0]; |
- if (nextNode) |
- nextNode.previousSibling_ = nodes[nodes.length - 1]; |
- |
- return nodes; |
- } |
- |
- function unwrapNodesForInsertion(nodes) { |
- if (nodes.length === 1) |
- return unwrap(nodes[0]); |
- |
- var df = unwrap(document.createDocumentFragment()); |
- for (var i = 0; i < nodes.length; i++) { |
- df.appendChild(unwrap(nodes[i])); |
- } |
- return df; |
- } |
- |
- function removeAllChildNodes(wrapper) { |
- var childWrapper = wrapper.firstChild; |
- while (childWrapper) { |
- assert(childWrapper.parentNode === wrapper); |
- var nextSibling = childWrapper.nextSibling; |
- var childNode = unwrap(childWrapper); |
- var parentNode = childNode.parentNode; |
- if (parentNode) |
- originalRemoveChild.call(parentNode, childNode); |
- childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.parentNode_ = null; |
- childWrapper = nextSibling; |
- } |
- wrapper.firstChild_ = wrapper.lastChild_ = null; |
- } |
- |
- var OriginalNode = window.Node; |
- |
- /** |
- * This represents a wrapper of a native DOM node. |
- * @param {!Node} original The original DOM node, aka, the visual DOM node. |
- * @constructor |
- * @extends {EventTarget} |
- */ |
- function Node(original) { |
- assert(original instanceof OriginalNode); |
- |
- EventTarget.call(this, original); |
- |
- // These properties are used to override the visual references with the |
- // logical ones. If the value is undefined it means that the logical is the |
- // same as the visual. |
- |
- /** |
- * @type {Node|undefined} |
- * @private |
- */ |
- this.parentNode_ = undefined; |
- |
- /** |
- * @type {Node|undefined} |
- * @private |
- */ |
- this.firstChild_ = undefined; |
- |
- /** |
- * @type {Node|undefined} |
- * @private |
- */ |
- this.lastChild_ = undefined; |
- |
- /** |
- * @type {Node|undefined} |
- * @private |
- */ |
- this.nextSibling_ = undefined; |
- |
- /** |
- * @type {Node|undefined} |
- * @private |
- */ |
- this.previousSibling_ = undefined; |
- }; |
- |
- var originalAppendChild = OriginalNode.prototype.appendChild; |
- var originalInsertBefore = OriginalNode.prototype.insertBefore; |
- var originalReplaceChild = OriginalNode.prototype.replaceChild; |
- var originalRemoveChild = OriginalNode.prototype.removeChild; |
- var originalCompareDocumentPosition = |
- OriginalNode.prototype.compareDocumentPosition; |
- |
- Node.prototype = Object.create(EventTarget.prototype); |
- mixin(Node.prototype, { |
- appendChild: function(childWrapper) { |
- assertIsNodeWrapper(childWrapper); |
- |
- this.invalidateShadowRenderer(); |
- |
- var previousNode = this.lastChild; |
- var nextNode = null; |
- var nodes = collectNodes(childWrapper, this, |
- previousNode, nextNode); |
- |
- this.lastChild_ = nodes[nodes.length - 1]; |
- if (!previousNode) |
- this.firstChild_ = nodes[0]; |
- |
- // TODO(arv): It is unclear if we need to update the visual DOM here. |
- // A better aproach might be to make sure we only get here for nodes that |
- // are related to a shadow host and then invalidate that and re-render |
- // the host (on reflow?). |
- originalAppendChild.call(this.impl, unwrapNodesForInsertion(nodes)); |
- |
- return childWrapper; |
- }, |
- |
- insertBefore: function(childWrapper, refWrapper) { |
- // TODO(arv): Unify with appendChild |
- if (!refWrapper) |
- return this.appendChild(childWrapper); |
- |
- assertIsNodeWrapper(childWrapper); |
- assertIsNodeWrapper(refWrapper); |
- assert(refWrapper.parentNode === this); |
- |
- this.invalidateShadowRenderer(); |
- |
- var previousNode = refWrapper.previousSibling; |
- var nextNode = refWrapper; |
- var nodes = collectNodes(childWrapper, this, |
- previousNode, nextNode); |
- |
- |
- if (this.firstChild === refWrapper) |
- this.firstChild_ = nodes[0]; |
- |
- // insertBefore refWrapper no matter what the parent is? |
- var refNode = unwrap(refWrapper); |
- var parentNode = refNode.parentNode; |
- if (parentNode) { |
- originalInsertBefore.call( |
- parentNode, |
- unwrapNodesForInsertion(nodes), |
- refNode); |
- } |
- |
- return childWrapper; |
- }, |
- |
- removeChild: function(childWrapper) { |
- assertIsNodeWrapper(childWrapper); |
- if (childWrapper.parentNode !== this) { |
- // TODO(arv): DOMException |
- throw new Error('NotFoundError'); |
- } |
- |
- this.invalidateShadowRenderer(); |
- |
- // We need to remove the real node from the DOM before updating the |
- // pointers. This is so that that mutation event is dispatched before |
- // the pointers have changed. |
- var thisFirstChild = this.firstChild; |
- var thisLastChild = this.lastChild; |
- var childWrapperNextSibling = childWrapper.nextSibling; |
- var childWrapperPreviousSibling = childWrapper.previousSibling; |
- |
- var childNode = unwrap(childWrapper); |
- var parentNode = childNode.parentNode; |
- if (parentNode) |
- originalRemoveChild.call(parentNode, childNode); |
- |
- if (thisFirstChild === childWrapper) |
- this.firstChild_ = childWrapperNextSibling; |
- if (thisLastChild === childWrapper) |
- this.lastChild_ = childWrapperPreviousSibling; |
- if (childWrapperPreviousSibling) |
- childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling; |
- if (childWrapperNextSibling) |
- childWrapperNextSibling.previousSibling_ = childWrapperPreviousSibling; |
- |
- childWrapper.previousSibling_ = childWrapper.nextSibling_ = childWrapper.parentNode_ = null; |
- |
- return childWrapper; |
- }, |
- |
- replaceChild: function(newChildWrapper, oldChildWrapper) { |
- assertIsNodeWrapper(newChildWrapper); |
- assertIsNodeWrapper(oldChildWrapper); |
- |
- if (oldChildWrapper.parentNode !== this) { |
- // TODO(arv): DOMException |
- throw new Error('NotFoundError'); |
- } |
- |
- this.invalidateShadowRenderer(); |
- |
- var previousNode = oldChildWrapper.previousSibling; |
- var nextNode = oldChildWrapper.nextSibling; |
- if (nextNode === newChildWrapper) |
- nextNode = newChildWrapper.nextSibling; |
- var nodes = collectNodes(newChildWrapper, this, |
- previousNode, nextNode); |
- |
- if (this.firstChild === oldChildWrapper) |
- this.firstChild_ = nodes[0]; |
- if (this.lastChild === oldChildWrapper) |
- this.lastChild_ = nodes[nodes.length - 1]; |
- |
- oldChildWrapper.previousSibling_ = null; |
- oldChildWrapper.nextSibling_ = null; |
- oldChildWrapper.parentNode_ = null; |
- |
- // replaceChild no matter what the parent is? |
- var oldChildNode = unwrap(oldChildWrapper); |
- if (oldChildNode.parentNode) { |
- originalReplaceChild.call( |
- oldChildNode.parentNode, |
- unwrapNodesForInsertion(nodes), |
- oldChildNode); |
- } |
- |
- return oldChildWrapper; |
- }, |
- |
- hasChildNodes: function() { |
- return this.firstChild === null; |
- }, |
- |
- /** @type {Node} */ |
- get parentNode() { |
- // If the parentNode has not been overridden, use the original parentNode. |
- return this.parentNode_ !== undefined ? |
- this.parentNode_ : wrap(this.impl.parentNode); |
- }, |
- |
- /** @type {Node} */ |
- get firstChild() { |
- return this.firstChild_ !== undefined ? |
- this.firstChild_ : wrap(this.impl.firstChild); |
- }, |
- |
- /** @type {Node} */ |
- get lastChild() { |
- return this.lastChild_ !== undefined ? |
- this.lastChild_ : wrap(this.impl.lastChild); |
- }, |
- |
- /** @type {Node} */ |
- get nextSibling() { |
- return this.nextSibling_ !== undefined ? |
- this.nextSibling_ : wrap(this.impl.nextSibling); |
- }, |
- |
- /** @type {Node} */ |
- get previousSibling() { |
- return this.previousSibling_ !== undefined ? |
- this.previousSibling_ : wrap(this.impl.previousSibling); |
- }, |
- |
- get parentElement() { |
- var p = this.parentNode; |
- while (p && p.nodeType !== Node.ELEMENT_NODE) { |
- p = p.parentNode; |
- } |
- return p; |
- }, |
- |
- get textContent() { |
- // TODO(arv): This should fallback to this.impl.textContent if there |
- // are no shadow trees below or above the context node. |
- var s = ''; |
- for (var child = this.firstChild; child; child = child.nextSibling) { |
- s += child.textContent; |
- } |
- return s; |
- }, |
- set textContent(textContent) { |
- removeAllChildNodes(this); |
- this.invalidateShadowRenderer(); |
- if (textContent !== '') { |
- var textNode = this.impl.ownerDocument.createTextNode(textContent); |
- this.appendChild(textNode); |
- } |
- }, |
- |
- get childNodes() { |
- var wrapperList = new NodeList(); |
- var i = 0; |
- for (var child = this.firstChild; child; child = child.nextSibling) { |
- wrapperList[i++] = child; |
- } |
- wrapperList.length = i; |
- return wrapperList; |
- }, |
- |
- cloneNode: function(deep) { |
- if (!this.invalidateShadowRenderer()) |
- return wrap(this.impl.cloneNode(deep)); |
- |
- var clone = wrap(this.impl.cloneNode(false)); |
- if (deep) { |
- for (var child = this.firstChild; child; child = child.nextSibling) { |
- clone.appendChild(child.cloneNode(true)); |
- } |
- } |
- // TODO(arv): Some HTML elements also clone other data like value. |
- return clone; |
- }, |
- |
- // insertionParent is added in ShadowRender.js |
- |
- contains: function(child) { |
- if (!child) |
- return false; |
- |
- // TODO(arv): Optimize using ownerDocument etc. |
- if (child === this) |
- return true; |
- var parentNode = child.parentNode; |
- if (!parentNode) |
- return false; |
- return this.contains(parentNode); |
- }, |
- |
- compareDocumentPosition: function(otherNode) { |
- // This only wraps, it therefore only operates on the composed DOM and not |
- // the logical DOM. |
- return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode)); |
- } |
- }); |
- |
- defineWrapGetter(Node, 'ownerDocument'); |
- |
- // We use a DocumentFragment as a base and then delete the properties of |
- // DocumentFragment.prototype from the wrapper Node. Since delete makes |
- // objects slow in some JS engines we recreate the prototype object. |
- registerWrapper(OriginalNode, Node, document.createDocumentFragment()); |
- delete Node.prototype.querySelector; |
- delete Node.prototype.querySelectorAll; |
- Node.prototype = mixin(Object.create(EventTarget.prototype), Node.prototype); |
- |
- scope.wrappers.Node = Node; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- function findOne(node, selector) { |
- var m, el = node.firstElementChild; |
- while (el) { |
- if (el.matches(selector)) |
- return el; |
- m = findOne(el, selector); |
- if (m) |
- return m; |
- el = el.nextElementSibling; |
- } |
- return null; |
- } |
- |
- function findAll(node, selector, results) { |
- var el = node.firstElementChild; |
- while (el) { |
- if (el.matches(selector)) |
- results[results.length++] = el; |
- findAll(el, selector, results); |
- el = el.nextElementSibling; |
- } |
- return results; |
- } |
- |
- // find and findAll will only match Simple Selectors, |
- // Structural Pseudo Classes are not guarenteed to be correct |
- // http://www.w3.org/TR/css3-selectors/#simple-selectors |
- |
- var SelectorsInterface = { |
- querySelector: function(selector) { |
- return findOne(this, selector); |
- }, |
- querySelectorAll: function(selector) { |
- return findAll(this, selector, new NodeList()) |
- } |
- }; |
- |
- var GetElementsByInterface = { |
- getElementsByTagName: function(tagName) { |
- // TODO(arv): Check tagName? |
- return this.querySelectorAll(tagName); |
- }, |
- getElementsByClassName: function(className) { |
- // TODO(arv): Check className? |
- return this.querySelectorAll('.' + className); |
- }, |
- getElementsByTagNameNS: function(ns, tagName) { |
- if (ns === '*') |
- return this.getElementsByTagName(tagName); |
- |
- // TODO(arv): Check tagName? |
- var result = new NodeList; |
- var els = this.getElementsByTagName(tagName); |
- for (var i = 0, j = 0; i < els.length; i++) { |
- if (els[i].namespaceURI === ns) |
- result[j++] = els[i]; |
- } |
- result.length = j; |
- return result; |
- } |
- }; |
- |
- scope.GetElementsByInterface = GetElementsByInterface; |
- scope.SelectorsInterface = SelectorsInterface; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var NodeList = scope.wrappers.NodeList; |
- |
- function forwardElement(node) { |
- while (node && node.nodeType !== Node.ELEMENT_NODE) { |
- node = node.nextSibling; |
- } |
- return node; |
- } |
- |
- function backwardsElement(node) { |
- while (node && node.nodeType !== Node.ELEMENT_NODE) { |
- node = node.previousSibling; |
- } |
- return node; |
- } |
- |
- var ParentNodeInterface = { |
- get firstElementChild() { |
- return forwardElement(this.firstChild); |
- }, |
- |
- get lastElementChild() { |
- return backwardsElement(this.lastChild); |
- }, |
- |
- get childElementCount() { |
- var count = 0; |
- for (var child = this.firstElementChild; |
- child; |
- child = child.nextElementSibling) { |
- count++; |
- } |
- return count; |
- }, |
- |
- get children() { |
- var wrapperList = new NodeList(); |
- var i = 0; |
- for (var child = this.firstElementChild; |
- child; |
- child = child.nextElementSibling) { |
- wrapperList[i++] = child; |
- } |
- wrapperList.length = i; |
- return wrapperList; |
- } |
- }; |
- |
- var ChildNodeInterface = { |
- get nextElementSibling() { |
- return forwardElement(this.nextSibling); |
- }, |
- |
- get previousElementSibling() { |
- return backwardsElement(this.nextSibling); |
- } |
- }; |
- |
- scope.ChildNodeInterface = ChildNodeInterface; |
- scope.ParentNodeInterface = ParentNodeInterface; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var ChildNodeInterface = scope.ChildNodeInterface; |
- var Node = scope.wrappers.Node; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- |
- var OriginalCharacterData = window.CharacterData; |
- |
- function CharacterData(node) { |
- Node.call(this, node); |
- } |
- CharacterData.prototype = Object.create(Node.prototype); |
- mixin(CharacterData.prototype, { |
- get textContent() { |
- return this.data; |
- }, |
- set textContent(value) { |
- this.data = value; |
- } |
- }); |
- |
- mixin(CharacterData.prototype, ChildNodeInterface); |
- |
- registerWrapper(OriginalCharacterData, CharacterData, |
- document.createTextNode('')); |
- |
- scope.wrappers.CharacterData = CharacterData; |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var ChildNodeInterface = scope.ChildNodeInterface; |
- var GetElementsByInterface = scope.GetElementsByInterface; |
- var Node = scope.wrappers.Node; |
- var ParentNodeInterface = scope.ParentNodeInterface; |
- var SelectorsInterface = scope.SelectorsInterface; |
- var addWrapNodeListMethod = scope.addWrapNodeListMethod; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- var wrappers = scope.wrappers; |
- |
- var shadowRootTable = new SideTable(); |
- var OriginalElement = window.Element; |
- |
- var originalMatches = |
- OriginalElement.prototype.matches || |
- OriginalElement.prototype.mozMatchesSelector || |
- OriginalElement.prototype.msMatchesSelector || |
- OriginalElement.prototype.webkitMatchesSelector; |
- |
- function Element(node) { |
- Node.call(this, node); |
- } |
- Element.prototype = Object.create(Node.prototype); |
- mixin(Element.prototype, { |
- createShadowRoot: function() { |
- var newShadowRoot = new wrappers.ShadowRoot(this); |
- shadowRootTable.set(this, newShadowRoot); |
- |
- scope.getRendererForHost(this); |
- |
- this.invalidateShadowRenderer(true); |
- |
- return newShadowRoot; |
- }, |
- |
- get shadowRoot() { |
- return shadowRootTable.get(this) || null; |
- }, |
- |
- setAttribute: function(name, value) { |
- this.impl.setAttribute(name, value); |
- // This is a bit agressive. We need to invalidate if it affects |
- // the rendering content[select] or if it effects the value of a content |
- // select. |
- this.invalidateShadowRenderer(); |
- }, |
- |
- matches: function(selector) { |
- return originalMatches.call(this.impl, selector); |
- } |
- }); |
- |
- mixin(Element.prototype, ChildNodeInterface); |
- mixin(Element.prototype, GetElementsByInterface); |
- mixin(Element.prototype, ParentNodeInterface); |
- mixin(Element.prototype, SelectorsInterface); |
- |
- registerWrapper(OriginalElement, Element); |
- |
- scope.wrappers.Element = Element; |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var Element = scope.wrappers.Element; |
- var defineGetter = scope.defineGetter; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- var unwrap = scope.unwrap; |
- var wrap = scope.wrap; |
- |
- ///////////////////////////////////////////////////////////////////////////// |
- // innerHTML and outerHTML |
- |
- var escapeRegExp = /&|<|"/g; |
- |
- function escapeReplace(c) { |
- switch (c) { |
- case '&': |
- return '&'; |
- case '<': |
- return '<'; |
- case '"': |
- return '"' |
- } |
- } |
- |
- function escape(s) { |
- return s.replace(escapeRegExp, escapeReplace); |
- } |
- |
- // http://www.whatwg.org/specs/web-apps/current-work/#void-elements |
- var voidElements = { |
- 'area': true, |
- 'base': true, |
- 'br': true, |
- 'col': true, |
- 'command': true, |
- 'embed': true, |
- 'hr': true, |
- 'img': true, |
- 'input': true, |
- 'keygen': true, |
- 'link': true, |
- 'meta': true, |
- 'param': true, |
- 'source': true, |
- 'track': true, |
- 'wbr': true |
- }; |
- |
- function getOuterHTML(node) { |
- switch (node.nodeType) { |
- case Node.ELEMENT_NODE: |
- var tagName = node.tagName.toLowerCase(); |
- var s = '<' + tagName; |
- var attrs = node.attributes; |
- for (var i = 0, attr; attr = attrs[i]; i++) { |
- s += ' ' + attr.name + '="' + escape(attr.value) + '"'; |
- } |
- s += '>'; |
- if (voidElements[tagName]) |
- return s; |
- |
- return s + getInnerHTML(node) + '</' + tagName + '>'; |
- |
- case Node.TEXT_NODE: |
- return escape(node.nodeValue); |
- |
- case Node.COMMENT_NODE: |
- return '<!--' + escape(node.nodeValue) + '-->'; |
- default: |
- console.error(node); |
- throw new Error('not implemented'); |
- } |
- } |
- |
- function getInnerHTML(node) { |
- var s = ''; |
- for (var child = node.firstChild; child; child = child.nextSibling) { |
- s += getOuterHTML(child); |
- } |
- return s; |
- } |
- |
- function setInnerHTML(node, value, opt_tagName) { |
- var tagName = opt_tagName || 'div'; |
- node.textContent = ''; |
- var tempElement =unwrap(node.ownerDocument.createElement(tagName)); |
- tempElement.innerHTML = value; |
- var firstChild; |
- while (firstChild = tempElement.firstChild) { |
- node.appendChild(wrap(firstChild)); |
- } |
- } |
- |
- var OriginalHTMLElement = window.HTMLElement; |
- |
- function HTMLElement(node) { |
- Element.call(this, node); |
- } |
- HTMLElement.prototype = Object.create(Element.prototype); |
- mixin(HTMLElement.prototype, { |
- get innerHTML() { |
- // TODO(arv): This should fallback to this.impl.innerHTML if there |
- // are no shadow trees below or above the context node. |
- return getInnerHTML(this); |
- }, |
- set innerHTML(value) { |
- setInnerHTML(this, value, this.tagName); |
- }, |
- |
- get outerHTML() { |
- // TODO(arv): This should fallback to HTMLElement_prototype.outerHTML if there |
- // are no shadow trees below or above the context node. |
- return getOuterHTML(this); |
- }, |
- set outerHTML(value) { |
- if (!this.invalidateShadowRenderer()) { |
- this.impl.outerHTML = value; |
- } else { |
- throw new Error('not implemented'); |
- } |
- } |
- }); |
- |
- function getterRequiresRendering(name) { |
- defineGetter(HTMLElement, name, function() { |
- scope.renderAllPending(); |
- return this.impl[name]; |
- }); |
- } |
- |
- [ |
- 'clientHeight', |
- 'clientLeft', |
- 'clientTop', |
- 'clientWidth', |
- 'offsetHeight', |
- 'offsetLeft', |
- 'offsetTop', |
- 'offsetWidth', |
- 'scrollHeight', |
- 'scrollLeft', |
- 'scrollTop', |
- 'scrollWidth', |
- ].forEach(getterRequiresRendering); |
- |
- function methodRequiresRendering(name) { |
- Object.defineProperty(HTMLElement.prototype, name, { |
- value: function() { |
- scope.renderAllPending(); |
- return this.impl[name].apply(this.impl, arguments); |
- }, |
- configurable: true, |
- enumerable: true |
- }); |
- } |
- |
- [ |
- 'getBoundingClientRect', |
- 'getClientRects', |
- 'scrollIntoView' |
- ].forEach(methodRequiresRendering); |
- |
- // HTMLElement is abstract so we use a subclass that has no members. |
- registerWrapper(OriginalHTMLElement, HTMLElement, |
- document.createElement('b')); |
- |
- scope.wrappers.HTMLElement = HTMLElement; |
- |
- // TODO: Find a better way to share these two with WrapperShadowRoot. |
- scope.getInnerHTML = getInnerHTML; |
- scope.setInnerHTML = setInnerHTML |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var HTMLElement = scope.wrappers.HTMLElement; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- |
- var OriginalHTMLContentElement = window.HTMLContentElement; |
- |
- function HTMLContentElement(node) { |
- HTMLElement.call(this, node); |
- } |
- HTMLContentElement.prototype = Object.create(HTMLElement.prototype); |
- mixin(HTMLContentElement.prototype, { |
- get select() { |
- return this.getAttribute('select'); |
- }, |
- set select(value) { |
- this.setAttribute('select', value); |
- }, |
- |
- setAttribute: function(n, v) { |
- HTMLElement.prototype.setAttribute.call(this, n, v); |
- if (String(n).toLowerCase() === 'select') |
- this.invalidateShadowRenderer(true); |
- } |
- |
- // getDistributedNodes is added in ShadowRenderer |
- |
- // TODO: attribute boolean resetStyleInheritance; |
- }); |
- |
- if (OriginalHTMLContentElement) |
- registerWrapper(OriginalHTMLContentElement, HTMLContentElement); |
- |
- scope.wrappers.HTMLContentElement = HTMLContentElement; |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var HTMLElement = scope.wrappers.HTMLElement; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- |
- var OriginalHTMLShadowElement = window.HTMLShadowElement; |
- |
- function HTMLShadowElement(node) { |
- HTMLElement.call(this, node); |
- this.olderShadowRoot_ = null; |
- } |
- HTMLShadowElement.prototype = Object.create(HTMLElement.prototype); |
- mixin(HTMLShadowElement.prototype, { |
- get olderShadowRoot() { |
- return this.olderShadowRoot_; |
- }, |
- |
- invalidateShadowRenderer: function() { |
- HTMLElement.prototype.invalidateShadowRenderer.call(this, true); |
- }, |
- |
- // TODO: attribute boolean resetStyleInheritance; |
- }); |
- |
- if (OriginalHTMLShadowElement) |
- registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement); |
- |
- scope.wrappers.HTMLShadowElement = HTMLShadowElement; |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var HTMLElement = scope.wrappers.HTMLElement; |
- var getInnerHTML = scope.getInnerHTML; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- var setInnerHTML = scope.setInnerHTML; |
- var wrap = scope.wrap; |
- |
- var contentTable = new SideTable(); |
- var templateContentsOwnerTable = new SideTable(); |
- |
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner |
- function getTemplateContentsOwner(doc) { |
- if (!doc.defaultView) |
- return doc; |
- var d = templateContentsOwnerTable.get(doc); |
- if (!d) { |
- // TODO(arv): This should either be a Document or HTMLDocument depending |
- // on doc. |
- d = doc.implementation.createHTMLDocument(''); |
- while (d.lastChild) { |
- d.removeChild(d.lastChild); |
- } |
- templateContentsOwnerTable.set(doc, d); |
- } |
- return d; |
- } |
- |
- function extractContent(templateElement) { |
- var doc = getTemplateContentsOwner(templateElement.ownerDocument); |
- var df = doc.createDocumentFragment(); |
- var nextSibling; |
- var child; |
- while (child = templateElement.firstChild) { |
- df.appendChild(child); |
- } |
- return df; |
- } |
- |
- var OriginalHTMLTemplateElement = window.HTMLTemplateElement; |
- |
- function HTMLTemplateElement(node) { |
- HTMLElement.call(this, node); |
- } |
- HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype); |
- |
- mixin(HTMLTemplateElement.prototype, { |
- get content() { |
- if (OriginalHTMLTemplateElement) |
- return wrap(this.impl.content); |
- |
- // TODO(arv): This should be done in createCallback. I initially tried to |
- // do this in the constructor but the wrapper is not yet created at that |
- // point in time so we hit an iloop. |
- var content = contentTable.get(this); |
- if (!content) { |
- content = extractContent(this); |
- contentTable.set(this, content); |
- } |
- return content; |
- }, |
- |
- get innerHTML() { |
- return getInnerHTML(this.content); |
- }, |
- set innerHTML(value) { |
- setInnerHTML(this.content, value); |
- this.invalidateShadowRenderer(); |
- } |
- |
- // TODO(arv): cloneNode needs to clone content. |
- |
- }); |
- |
- if (OriginalHTMLTemplateElement) |
- registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement); |
- |
- scope.wrappers.HTMLTemplateElement = HTMLTemplateElement; |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var HTMLContentElement = scope.wrappers.HTMLContentElement; |
- var HTMLElement = scope.wrappers.HTMLElement; |
- var HTMLShadowElement = scope.wrappers.HTMLShadowElement; |
- var HTMLTemplateElement = scope.wrappers.HTMLTemplateElement; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- |
- var OriginalHTMLUnknownElement = window.HTMLUnknownElement; |
- |
- function HTMLUnknownElement(node) { |
- switch (node.localName) { |
- case 'content': |
- return new HTMLContentElement(node); |
- case 'shadow': |
- return new HTMLShadowElement(node); |
- case 'template': |
- return new HTMLTemplateElement(node); |
- } |
- HTMLElement.call(this, node); |
- } |
- HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype); |
- registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement); |
- scope.wrappers.HTMLUnknownElement = HTMLUnknownElement; |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var GetElementsByInterface = scope.GetElementsByInterface; |
- var ParentNodeInterface = scope.ParentNodeInterface; |
- var SelectorsInterface = scope.SelectorsInterface; |
- var mixin = scope.mixin; |
- var registerObject = scope.registerObject; |
- |
- var DocumentFragment = registerObject(document.createDocumentFragment()); |
- mixin(DocumentFragment.prototype, ParentNodeInterface); |
- mixin(DocumentFragment.prototype, SelectorsInterface); |
- mixin(DocumentFragment.prototype, GetElementsByInterface); |
- |
- var Text = registerObject(document.createTextNode('')); |
- var Comment = registerObject(document.createComment('')); |
- |
- scope.wrappers.Comment = Comment; |
- scope.wrappers.DocumentFragment = DocumentFragment; |
- scope.wrappers.Text = Text; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var DocumentFragment = scope.wrappers.DocumentFragment; |
- var elementFromPoint = scope.elementFromPoint; |
- var getInnerHTML = scope.getInnerHTML; |
- var mixin = scope.mixin; |
- var rewrap = scope.rewrap; |
- var setInnerHTML = scope.setInnerHTML; |
- var unwrap = scope.unwrap; |
- |
- var shadowHostTable = new SideTable(); |
- |
- function ShadowRoot(hostWrapper) { |
- var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment()); |
- DocumentFragment.call(this, node); |
- |
- // createDocumentFragment associates the node with a wrapper |
- // DocumentFragment instance. Override that. |
- rewrap(node, this); |
- |
- var oldShadowRoot = hostWrapper.shadowRoot; |
- scope.nextOlderShadowTreeTable.set(this, oldShadowRoot); |
- |
- shadowHostTable.set(this, hostWrapper); |
- } |
- ShadowRoot.prototype = Object.create(DocumentFragment.prototype); |
- mixin(ShadowRoot.prototype, { |
- get innerHTML() { |
- return getInnerHTML(this); |
- }, |
- set innerHTML(value) { |
- setInnerHTML(this, value); |
- this.invalidateShadowRenderer(); |
- }, |
- |
- invalidateShadowRenderer: function() { |
- return shadowHostTable.get(this).invalidateShadowRenderer(); |
- }, |
- |
- elementFromPoint: function(x, y) { |
- return elementFromPoint(this, this.ownerDocument, x, y); |
- }, |
- |
- getElementById: function(id) { |
- return this.querySelector('#' + id); |
- } |
- }); |
- |
- scope.wrappers.ShadowRoot = ShadowRoot; |
- scope.getHostForShadowRoot = function(node) { |
- return shadowHostTable.get(node); |
- }; |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var HTMLContentElement = scope.wrappers.HTMLContentElement; |
- var Node = scope.wrappers.Node; |
- var assert = scope.assert; |
- var mixin = scope.mixin; |
- var unwrap = scope.unwrap; |
- var wrap = scope.wrap; |
- |
- /** |
- * Updates the fields of a wrapper to a snapshot of the logical DOM as needed. |
- * Up means parentNode |
- * Sideways means previous and next sibling. |
- * @param {!Node} wrapper |
- */ |
- function updateWrapperUpAndSideways(wrapper) { |
- wrapper.previousSibling_ = wrapper.previousSibling; |
- wrapper.nextSibling_ = wrapper.nextSibling; |
- wrapper.parentNode_ = wrapper.parentNode; |
- } |
- |
- /** |
- * Updates the fields of a wrapper to a snapshot of the logical DOM as needed. |
- * Down means first and last child |
- * @param {!Node} wrapper |
- */ |
- function updateWrapperDown(wrapper) { |
- wrapper.firstChild_ = wrapper.firstChild; |
- wrapper.lastChild_ = wrapper.lastChild; |
- } |
- |
- function updateAllChildNodes(parentNodeWrapper) { |
- assert(parentNodeWrapper instanceof Node); |
- for (var childWrapper = parentNodeWrapper.firstChild; |
- childWrapper; |
- childWrapper = childWrapper.nextSibling) { |
- updateWrapperUpAndSideways(childWrapper); |
- } |
- updateWrapperDown(parentNodeWrapper); |
- } |
- |
- // This object groups DOM operations. This is supposed to be the DOM as the |
- // browser/render tree sees it. |
- // When changes are done to the visual DOM the logical DOM needs to be updated |
- // to reflect the correct tree. |
- function removeAllChildNodes(parentNodeWrapper) { |
- var parentNode = unwrap(parentNodeWrapper); |
- updateAllChildNodes(parentNodeWrapper); |
- parentNode.textContent = ''; |
- } |
- |
- function appendChild(parentNodeWrapper, childWrapper) { |
- var parentNode = unwrap(parentNodeWrapper); |
- var child = unwrap(childWrapper); |
- if (child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { |
- updateAllChildNodes(childWrapper); |
- |
- } else { |
- remove(childWrapper); |
- updateWrapperUpAndSideways(childWrapper); |
- } |
- |
- parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild; |
- if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild) |
- parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild; |
- |
- var lastChildWrapper = wrap(parentNode.lastChild); |
- if (lastChildWrapper) { |
- lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling; |
- } |
- |
- parentNode.appendChild(child); |
- } |
- |
- function removeChild(parentNodeWrapper, childWrapper) { |
- var parentNode = unwrap(parentNodeWrapper); |
- var child = unwrap(childWrapper); |
- |
- updateWrapperUpAndSideways(childWrapper); |
- |
- if (childWrapper.previousSibling) |
- childWrapper.previousSibling.nextSibling_ = childWrapper; |
- if (childWrapper.nextSibling) |
- childWrapper.nextSibling.previousSibling_ = childWrapper; |
- |
- if (parentNodeWrapper.lastChild === childWrapper) |
- parentNodeWrapper.lastChild_ = childWrapper; |
- if (parentNodeWrapper.firstChild === childWrapper) |
- parentNodeWrapper.firstChild_ = childWrapper; |
- |
- parentNode.removeChild(child); |
- } |
- |
- function remove(nodeWrapper) { |
- var node = unwrap(nodeWrapper) |
- var parentNode = node.parentNode; |
- if (parentNode) |
- removeChild(wrap(parentNode), nodeWrapper); |
- } |
- |
- var distributedChildNodesTable = new SideTable(); |
- var eventParentsTable = new SideTable(); |
- var insertionParentTable = new SideTable(); |
- var nextOlderShadowTreeTable = new SideTable(); |
- var rendererForHostTable = new SideTable(); |
- var shadowDOMRendererTable = new SideTable(); |
- |
- var reprCounter = 0; |
- |
- function repr(node) { |
- if (!node.displayName) |
- node.displayName = node.nodeName + '-' + ++reprCounter; |
- return node.displayName; |
- } |
- |
- function distributeChildToInsertionPoint(child, insertionPoint) { |
- getDistributedChildNodes(insertionPoint).push(child); |
- insertionParentTable.set(child, insertionPoint); |
- |
- var eventParents = eventParentsTable.get(child); |
- if (!eventParents) |
- eventParentsTable.set(child, eventParents = []); |
- eventParents.push(insertionPoint); |
- } |
- |
- function resetDistributedChildNodes(insertionPoint) { |
- distributedChildNodesTable.set(insertionPoint, []); |
- } |
- |
- function getDistributedChildNodes(insertionPoint) { |
- return distributedChildNodesTable.get(insertionPoint); |
- } |
- |
- function getChildNodesSnapshot(node) { |
- var result = [], i = 0; |
- for (var child = node.firstChild; child; child = child.nextSibling) { |
- result[i++] = child; |
- } |
- return result; |
- } |
- |
- /** |
- * Visits all nodes in the tree that fulfils the |predicate|. If the |visitor| |
- * function returns |false| the traversal is aborted. |
- * @param {!Node} tree |
- * @param {function(!Node) : boolean} predicate |
- * @param {function(!Node) : *} visitor |
- */ |
- function visit(tree, predicate, visitor) { |
- // This operates on logical DOM. |
- var nodes = getChildNodesSnapshot(tree); |
- for (var i = 0; i < nodes.length; i++) { |
- var node = nodes[i]; |
- if (predicate(node)) { |
- if (visitor(node) === false) |
- return; |
- } else { |
- visit(node, predicate, visitor); |
- } |
- } |
- } |
- |
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn-distribution-algorithm |
- function distribute(tree, pool) { |
- var anyRemoved = false; |
- |
- visit(tree, isActiveInsertionPoint, |
- function(insertionPoint) { |
- resetDistributedChildNodes(insertionPoint); |
- for (var i = 0; i < pool.length; i++) { // 1.2 |
- var node = pool[i]; // 1.2.1 |
- if (node === undefined) // removed |
- continue; |
- if (matchesCriteria(node, insertionPoint)) { // 1.2.2 |
- distributeChildToInsertionPoint(node, insertionPoint); // 1.2.2.1 |
- pool[i] = undefined; // 1.2.2.2 |
- anyRemoved = true; |
- } |
- } |
- }); |
- |
- if (!anyRemoved) |
- return pool; |
- |
- return pool.filter(function(item) { |
- return item !== undefined; |
- }); |
- } |
- |
- // Matching Insertion Points |
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#matching-insertion-points |
- |
- // TODO(arv): Verify this... I don't remember why I picked this regexp. |
- var selectorMatchRegExp = /^[*.:#[a-zA-Z_|]/; |
- |
- var allowedPseudoRegExp = new RegExp('^:(' + [ |
- 'link', |
- 'visited', |
- 'target', |
- 'enabled', |
- 'disabled', |
- 'checked', |
- 'indeterminate', |
- 'nth-child', |
- 'nth-last-child', |
- 'nth-of-type', |
- 'nth-last-of-type', |
- 'first-child', |
- 'last-child', |
- 'first-of-type', |
- 'last-of-type', |
- 'only-of-type', |
- ].join('|') + ')'); |
- |
- |
- function oneOf(object, propertyNames) { |
- for (var i = 0; i < propertyNames.length; i++) { |
- if (propertyNames[i] in object) |
- return propertyNames[i]; |
- } |
- } |
- |
- /** |
- * @param {Element} node |
- * @oaram {Element} point The insertion point element. |
- * @return {boolean} Whether the node matches the insertion point. |
- */ |
- function matchesCriteria(node, point) { |
- var select = point.getAttribute('select'); |
- if (!select) |
- return true; |
- |
- // Here we know the select attribute is a non empty string. |
- select = select.trim(); |
- if (!select) |
- return true; |
- |
- if (node.nodeType !== Node.ELEMENT_NODE) |
- return false; |
- |
- // TODO(arv): This does not seem right. Need to check for a simple selector. |
- if (!selectorMatchRegExp.test(select)) |
- return false; |
- |
- if (select[0] === ':' &&!allowedPseudoRegExp.test(select)) |
- return false; |
- |
- try { |
- return node.matches(select); |
- } catch (ex) { |
- // Invalid selector. |
- return false; |
- } |
- } |
- |
- var request = oneOf(window, [ |
- 'requestAnimationFrame', |
- 'mozRequestAnimationFrame', |
- 'webkitRequestAnimationFrame', |
- 'setTimeout' |
- ]); |
- |
- var pendingDirtyRenderers = []; |
- var renderTimer; |
- |
- function renderAllPending() { |
- renderTimer = null; |
- pendingDirtyRenderers.forEach(function(owner) { |
- owner.render(); |
- }); |
- pendingDirtyRenderers = []; |
- } |
- |
- function ShadowRenderer(host) { |
- this.host = host; |
- this.dirty = false; |
- this.associateNode(host); |
- } |
- |
- function getRendererForHost(host) { |
- var renderer = rendererForHostTable.get(host); |
- if (!renderer) { |
- renderer = new ShadowRenderer(host); |
- rendererForHostTable.set(host, renderer); |
- } |
- return renderer; |
- } |
- |
- ShadowRenderer.prototype = { |
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#rendering-shadow-trees |
- render: function() { |
- if (!this.dirty) |
- return; |
- |
- var host = this.host; |
- this.treeComposition(); |
- var shadowDOM = host.shadowRoot; |
- if (!shadowDOM) |
- return; |
- |
- this.removeAllChildNodes(this.host); |
- |
- var shadowDOMChildNodes = getChildNodesSnapshot(shadowDOM); |
- shadowDOMChildNodes.forEach(function(node) { |
- this.renderNode(host, shadowDOM, node, false); |
- }, this); |
- |
- this.dirty = false; |
- }, |
- |
- invalidate: function() { |
- if (!this.dirty) { |
- this.dirty = true; |
- pendingDirtyRenderers.push(this); |
- if (renderTimer) |
- return; |
- renderTimer = window[request](renderAllPending, 0); |
- } |
- }, |
- |
- renderNode: function(visualParent, tree, node, isNested) { |
- if (isShadowHost(node)) { |
- this.appendChild(visualParent, node); |
- var renderer = getRendererForHost(node); |
- renderer.dirty = true; // Need to rerender due to reprojection. |
- renderer.render(); |
- } else if (isInsertionPoint(node)) { |
- this.renderInsertionPoint(visualParent, tree, node, isNested); |
- } else if (isShadowInsertionPoint(node)) { |
- this.renderShadowInsertionPoint(visualParent, tree, node); |
- } else { |
- this.renderAsAnyDomTree(visualParent, tree, node, isNested); |
- } |
- }, |
- |
- renderAsAnyDomTree: function(visualParent, tree, child, isNested) { |
- this.appendChild(visualParent, child); |
- |
- if (isShadowHost(child)) { |
- render(child); |
- } else { |
- var parent = child; |
- var logicalChildNodes = getChildNodesSnapshot(parent); |
- logicalChildNodes.forEach(function(node) { |
- this.renderNode(parent, tree, node, isNested); |
- }, this); |
- } |
- }, |
- |
- renderInsertionPoint: function(visualParent, tree, insertionPoint, isNested) { |
- var distributedChildNodes = getDistributedChildNodes(insertionPoint); |
- if (distributedChildNodes.length) { |
- this.removeAllChildNodes(insertionPoint); |
- |
- distributedChildNodes.forEach(function(child) { |
- if (isInsertionPoint(child) && isNested) |
- this.renderInsertionPoint(visualParent, tree, child, isNested); |
- else |
- this.renderAsAnyDomTree(visualParent, tree, child, isNested); |
- }, this); |
- } else { |
- this.renderFallbackContent(visualParent, insertionPoint); |
- } |
- this.remove(insertionPoint); |
- }, |
- |
- renderShadowInsertionPoint: function(visualParent, tree, shadowInsertionPoint) { |
- var nextOlderTree = getNextOlderTree(tree); |
- if (nextOlderTree) { |
- // This makes ShadowRoot have its insertionParent be the <shadow>. |
- insertionParentTable.set(nextOlderTree, shadowInsertionPoint); |
- shadowInsertionPoint.olderShadowRoot_ = nextOlderTree; |
- this.remove(shadowInsertionPoint); |
- var shadowDOMChildNodes = getChildNodesSnapshot(nextOlderTree); |
- shadowDOMChildNodes.forEach(function(node) { |
- this.renderNode(visualParent, nextOlderTree, node, true); |
- }, this); |
- } else { |
- this.renderFallbackContent(visualParent, shadowInsertionPoint); |
- } |
- }, |
- |
- renderFallbackContent: function (visualParent, fallbackHost) { |
- var logicalChildNodes = getChildNodesSnapshot(fallbackHost); |
- logicalChildNodes.forEach(function(node) { |
- this.appendChild(visualParent, node); |
- }, this); |
- }, |
- |
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn-tree-composition |
- treeComposition: function () { |
- var shadowHost = this.host; |
- var tree = shadowHost.shadowRoot; // 1. |
- var pool = []; // 2. |
- var shadowHostChildNodes = getChildNodesSnapshot(shadowHost); |
- shadowHostChildNodes.forEach(function(child) { // 3. |
- if (isInsertionPoint(child)) { // 3.2. |
- var reprojected = getDistributedChildNodes(child); // 3.2.1. |
- // if reprojected is undef... reset it? |
- if (!reprojected || !reprojected.length) // 3.2.2. |
- reprojected = getChildNodesSnapshot(child); |
- pool.push.apply(pool, reprojected); // 3.2.3. |
- } else { |
- pool.push(child); // 3.3. |
- } |
- }); |
- |
- var shadowInsertionPoint, point; |
- while (tree) { // 4. |
- // 4.1. |
- shadowInsertionPoint = undefined; // Reset every iteration. |
- visit(tree, isActiveShadowInsertionPoint, function(point) { |
- shadowInsertionPoint = point; |
- return false; |
- }); |
- point = shadowInsertionPoint; |
- |
- pool = distribute(tree, pool); // 4.2. |
- if (point) { // 4.3. |
- var nextOlderTree = getNextOlderTree(tree); // 4.3.1. |
- if (!nextOlderTree) { |
- break; // 4.3.1.1. |
- } else { |
- tree = nextOlderTree; // 4.3.2.2. |
- assignShadowTreeToShadowInsertionPoint(tree, point); // 4.3.2.2. |
- continue; // 4.3.2.3. |
- } |
- } else { |
- break; // 4.4. |
- } |
- } |
- }, |
- |
- // Visual DOM mutation. |
- appendChild: function(parent, child) { |
- appendChild(parent, child); |
- this.associateNode(child); |
- }, |
- |
- remove: function(node) { |
- remove(node); |
- this.associateNode(node); |
- }, |
- |
- removeAllChildNodes: function(parent) { |
- removeAllChildNodes(parent); |
- // TODO(arv): Does this need to associate all the nodes with this renderer? |
- }, |
- |
- associateNode: function(node) { |
- // TODO: Clear when moved out of shadow tree. |
- shadowDOMRendererTable.set(node, this); |
- } |
- }; |
- |
- function isInsertionPoint(node) { |
- // Should this include <shadow>? |
- return node.localName === 'content'; |
- } |
- |
- function isActiveInsertionPoint(node) { |
- // <content> inside another <content> or <shadow> is considered inactive. |
- return node.localName === 'content'; |
- } |
- |
- function isShadowInsertionPoint(node) { |
- return node.localName === 'shadow'; |
- } |
- |
- function isActiveShadowInsertionPoint(node) { |
- // <shadow> inside another <content> or <shadow> is considered inactive. |
- return node.localName === 'shadow'; |
- } |
- |
- function isShadowHost(shadowHost) { |
- return !!shadowHost.shadowRoot; |
- } |
- |
- /** |
- * @param {WrapperShadowRoot} tree |
- */ |
- function getNextOlderTree(tree) { |
- return nextOlderShadowTreeTable.get(tree); |
- } |
- |
- function getShadowTrees(host) { |
- var trees = []; |
- |
- for (var tree = host.shadowRoot; |
- tree; |
- tree = nextOlderShadowTreeTable.get(tree)) { |
- trees.push(tree); |
- } |
- return trees; |
- } |
- |
- function assignShadowTreeToShadowInsertionPoint(tree, point) { |
- insertionParentTable.set(tree, point); |
- } |
- |
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#rendering-shadow-trees |
- function render(host) { |
- new ShadowRenderer(host).render(); |
- }; |
- |
- Node.prototype.invalidateShadowRenderer = function(force) { |
- // TODO: If this is in light DOM we only need to invalidate renderer if this |
- // is a direct child of a ShadowRoot. |
- // Maybe we should only associate renderers with direct child nodes of a |
- // shadow root (and all nodes in the shadow dom). |
- var renderer = shadowDOMRendererTable.get(this); |
- if (!renderer) |
- return false; |
- |
- var p; |
- if (force || this.shadowRoot || |
- (p = this.parentNode) && (p.shadowRoot || p instanceof ShadowRoot)) { |
- renderer.invalidate(); |
- } |
- |
- return true; |
- }; |
- |
- HTMLContentElement.prototype.getDistributedNodes = function() { |
- // TODO(arv): We should associate the element with the shadow root so we |
- // only have to rerender this ShadowRenderer. |
- renderAllPending(); |
- return getDistributedChildNodes(this); |
- }; |
- |
- mixin(Node.prototype, { |
- get insertionParent() { |
- return insertionParentTable.get(this) || null; |
- } |
- }); |
- |
- scope.eventParentsTable = eventParentsTable; |
- scope.getRendererForHost = getRendererForHost; |
- scope.getShadowTrees = getShadowTrees; |
- scope.nextOlderShadowTreeTable = nextOlderShadowTreeTable; |
- scope.renderAllPending = renderAllPending; |
- |
- // Exposed for testing |
- scope.visual = { |
- removeAllChildNodes: removeAllChildNodes, |
- appendChild: appendChild, |
- removeChild: removeChild |
- }; |
- |
-})(this.ShadowDOMPolyfill); |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var GetElementsByInterface = scope.GetElementsByInterface; |
- var Node = scope.wrappers.Node; |
- var ParentNodeInterface = scope.ParentNodeInterface; |
- var SelectorsInterface = scope.SelectorsInterface; |
- var defineWrapGetter = scope.defineWrapGetter; |
- var elementFromPoint = scope.elementFromPoint; |
- var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- var unwrap = scope.unwrap; |
- var wrap = scope.wrap; |
- var wrapEventTargetMethods = scope.wrapEventTargetMethods; |
- var wrapNodeList = scope.wrapNodeList; |
- |
- var implementationTable = new SideTable(); |
- |
- function Document(node) { |
- Node.call(this, node); |
- } |
- Document.prototype = Object.create(Node.prototype); |
- |
- defineWrapGetter(Document, 'documentElement'); |
- |
- // Conceptually both body and head can be in a shadow but suporting that seems |
- // overkill at this point. |
- defineWrapGetter(Document, 'body'); |
- defineWrapGetter(Document, 'head'); |
- |
- // document cannot be overridden so we override a bunch of its methods |
- // directly on the instance. |
- |
- function wrapMethod(name) { |
- var original = document[name]; |
- Document.prototype[name] = function() { |
- return wrap(original.apply(this.impl, arguments)); |
- }; |
- } |
- |
- [ |
- 'getElementById', |
- 'createElement', |
- 'createElementNS', |
- 'createTextNode', |
- 'createDocumentFragment', |
- 'createEvent', |
- 'createEventNS', |
- ].forEach(wrapMethod); |
- |
- var originalAdoptNode = document.adoptNode; |
- var originalWrite = document.write; |
- |
- mixin(Document.prototype, { |
- adoptNode: function(node) { |
- originalAdoptNode.call(this.impl, unwrap(node)); |
- return node; |
- }, |
- elementFromPoint: function(x, y) { |
- return elementFromPoint(this, this, x, y); |
- }, |
- write: function(s) { |
- var all = this.querySelectorAll('*'); |
- var last = all[all.length - 1]; |
- while (last.nextSibling) { |
- last = last.nextSibling; |
- } |
- var p = last.parentNode; |
- p.lastChild_ = undefined; |
- last.nextSibling_ = undefined; |
- originalWrite.call(this.impl, s); |
- } |
- }); |
- |
- // We also override some of the methods on document.body and document.head |
- // for convenience. |
- forwardMethodsToWrapper([ |
- window.HTMLBodyElement, |
- window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument |
- window.HTMLHeadElement, |
- ], [ |
- 'appendChild', |
- 'compareDocumentPosition', |
- 'getElementsByClassName', |
- 'getElementsByTagName', |
- 'getElementsByTagNameNS', |
- 'insertBefore', |
- 'querySelector', |
- 'querySelectorAll', |
- 'removeChild', |
- 'replaceChild', |
- ]); |
- |
- forwardMethodsToWrapper([ |
- window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument |
- ], [ |
- 'adoptNode', |
- 'createDocumentFragment', |
- 'createElement', |
- 'createElementNS', |
- 'createEvent', |
- 'createEventNS', |
- 'createTextNode', |
- 'elementFromPoint', |
- 'getElementById', |
- 'write', |
- ]); |
- |
- mixin(Document.prototype, GetElementsByInterface); |
- mixin(Document.prototype, ParentNodeInterface); |
- mixin(Document.prototype, SelectorsInterface); |
- |
- mixin(Document.prototype, { |
- get implementation() { |
- var implementation = implementationTable.get(this); |
- if (implementation) |
- return implementation; |
- implementation = |
- new DOMImplementation(unwrap(this).implementation); |
- implementationTable.set(this, implementation); |
- return implementation; |
- } |
- }); |
- |
- registerWrapper(window.Document, Document, |
- document.implementation.createHTMLDocument('')); |
- |
- // Both WebKit and Gecko uses HTMLDocument for document. HTML5/DOM only has |
- // one Document interface and IE implements the standard correctly. |
- if (window.HTMLDocument) |
- registerWrapper(window.HTMLDocument, Document); |
- |
- wrapEventTargetMethods([ |
- window.HTMLBodyElement, |
- window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument |
- window.HTMLHeadElement, |
- ]); |
- |
- function DOMImplementation(impl) { |
- this.impl = impl; |
- } |
- |
- function wrapImplMethod(constructor, name) { |
- var original = document.implementation[name]; |
- constructor.prototype[name] = function() { |
- return wrap(original.apply(this.impl, arguments)); |
- }; |
- } |
- |
- function forwardImplMethod(constructor, name) { |
- var original = document.implementation[name]; |
- constructor.prototype[name] = function() { |
- return original.apply(this.impl, arguments); |
- }; |
- } |
- |
- wrapImplMethod(DOMImplementation, 'createDocumentType'); |
- wrapImplMethod(DOMImplementation, 'createDocument'); |
- wrapImplMethod(DOMImplementation, 'createHTMLDocument'); |
- forwardImplMethod(DOMImplementation, 'hasFeature'); |
- |
- registerWrapper(window.DOMImplementation, DOMImplementation); |
- |
- forwardMethodsToWrapper([ |
- window.DOMImplementation, |
- ], [ |
- 'createDocumentType', |
- 'createDocument', |
- 'createHTMLDocument', |
- 'hasFeature', |
- ]); |
- |
- scope.wrappers.Document = Document; |
- scope.wrappers.DOMImplementation = DOMImplementation; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var EventTarget = scope.wrappers.EventTarget; |
- var mixin = scope.mixin; |
- var registerWrapper = scope.registerWrapper; |
- var unwrap = scope.unwrap; |
- var unwrapIfNeeded = scope.unwrapIfNeeded; |
- var wrap = scope.wrap; |
- |
- var OriginalWindow = window.Window; |
- |
- function Window(impl) { |
- EventTarget.call(this, impl); |
- } |
- Window.prototype = Object.create(EventTarget.prototype); |
- |
- var originalGetComputedStyle = window.getComputedStyle; |
- OriginalWindow.prototype.getComputedStyle = function(el, pseudo) { |
- return originalGetComputedStyle.call(this || window, unwrapIfNeeded(el), |
- pseudo); |
- }; |
- |
- ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach( |
- function(name) { |
- OriginalWindow.prototype[name] = function() { |
- var w = wrap(this || window); |
- return w[name].apply(w, arguments); |
- }; |
- }); |
- |
- mixin(Window.prototype, { |
- getComputedStyle: function(el, pseudo) { |
- return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el), |
- pseudo); |
- } |
- }); |
- |
- registerWrapper(OriginalWindow, Window); |
- |
- scope.wrappers.Window = Window; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var defineGetter = scope.defineGetter; |
- var defineWrapGetter = scope.defineWrapGetter; |
- var registerWrapper = scope.registerWrapper; |
- var unwrapIfNeeded = scope.unwrapIfNeeded; |
- var wrapNodeList = scope.wrapNodeList; |
- var wrappers = scope.wrappers; |
- |
- var OriginalMutationObserver = window.MutationObserver || |
- window.WebKitMutationObserver; |
- |
- if (!OriginalMutationObserver) |
- return; |
- |
- var OriginalMutationRecord = window.MutationRecord; |
- |
- function MutationRecord(impl) { |
- this.impl = impl; |
- } |
- |
- MutationRecord.prototype = { |
- get addedNodes() { |
- return wrapNodeList(this.impl.addedNodes); |
- }, |
- get removedNodes() { |
- return wrapNodeList(this.impl.removedNodes); |
- } |
- }; |
- |
- ['target', 'previousSibling', 'nextSibling'].forEach(function(name) { |
- defineWrapGetter(MutationRecord, name); |
- }); |
- |
- // WebKit/Blink treats these as instance properties so we override |
- [ |
- 'type', |
- 'attributeName', |
- 'attributeNamespace', |
- 'oldValue' |
- ].forEach(function(name) { |
- defineGetter(MutationRecord, name, function() { |
- return this.impl[name]; |
- }); |
- }); |
- |
- if (OriginalMutationRecord) |
- registerWrapper(OriginalMutationRecord, MutationRecord); |
- |
- function wrapRecord(record) { |
- return new MutationRecord(record); |
- } |
- |
- function wrapRecords(records) { |
- return records.map(wrapRecord); |
- } |
- |
- function MutationObserver(callback) { |
- var self = this; |
- this.impl = new OriginalMutationObserver(function(mutations, observer) { |
- callback.call(self, wrapRecords(mutations), self); |
- }); |
- } |
- |
- var OriginalNode = window.Node; |
- |
- MutationObserver.prototype = { |
- observe: function(target, options) { |
- this.impl.observe(unwrapIfNeeded(target), options); |
- }, |
- disconnect: function() { |
- this.impl.disconnect(); |
- }, |
- takeRecords: function() { |
- return wrapRecords(this.impl.takeRecords()); |
- } |
- }; |
- |
- scope.wrappers.MutationObserver = MutationObserver; |
- scope.wrappers.MutationRecord = MutationRecord; |
- |
-})(this.ShadowDOMPolyfill); |
- |
-// Copyright 2013 The Polymer Authors. All rights reserved. |
-// Use of this source code is goverened by a BSD-style |
-// license that can be found in the LICENSE file. |
- |
-(function(scope) { |
- 'use strict'; |
- |
- var isWrapperFor = scope.isWrapperFor; |
- |
- // This is a list of the elements we currently override the global constructor |
- // for. |
- var elements = { |
- 'a': 'HTMLAnchorElement', |
- 'applet': 'HTMLAppletElement', |
- 'area': 'HTMLAreaElement', |
- 'audio': 'HTMLAudioElement', |
- 'br': 'HTMLBRElement', |
- 'base': 'HTMLBaseElement', |
- 'body': 'HTMLBodyElement', |
- 'button': 'HTMLButtonElement', |
- 'canvas': 'HTMLCanvasElement', |
- // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko. |
- 'dl': 'HTMLDListElement', |
- 'datalist': 'HTMLDataListElement', |
- 'dir': 'HTMLDirectoryElement', |
- 'div': 'HTMLDivElement', |
- 'embed': 'HTMLEmbedElement', |
- 'fieldset': 'HTMLFieldSetElement', |
- 'font': 'HTMLFontElement', |
- 'form': 'HTMLFormElement', |
- 'frame': 'HTMLFrameElement', |
- 'frameset': 'HTMLFrameSetElement', |
- 'hr': 'HTMLHRElement', |
- 'head': 'HTMLHeadElement', |
- 'h1': 'HTMLHeadingElement', |
- 'html': 'HTMLHtmlElement', |
- 'iframe': 'HTMLIFrameElement', |
- |
- // Uses HTMLSpanElement in Firefox. |
- // https://bugzilla.mozilla.org/show_bug.cgi?id=843881 |
- // 'image', |
- |
- 'input': 'HTMLInputElement', |
- 'li': 'HTMLLIElement', |
- 'label': 'HTMLLabelElement', |
- 'legend': 'HTMLLegendElement', |
- 'link': 'HTMLLinkElement', |
- 'map': 'HTMLMapElement', |
- // 'media', Covered by audio and video |
- 'menu': 'HTMLMenuElement', |
- 'menuitem': 'HTMLMenuItemElement', |
- 'meta': 'HTMLMetaElement', |
- 'meter': 'HTMLMeterElement', |
- 'del': 'HTMLModElement', |
- 'ol': 'HTMLOListElement', |
- 'object': 'HTMLObjectElement', |
- 'optgroup': 'HTMLOptGroupElement', |
- 'option': 'HTMLOptionElement', |
- 'output': 'HTMLOutputElement', |
- 'p': 'HTMLParagraphElement', |
- 'param': 'HTMLParamElement', |
- 'pre': 'HTMLPreElement', |
- 'progress': 'HTMLProgressElement', |
- 'q': 'HTMLQuoteElement', |
- 'script': 'HTMLScriptElement', |
- 'select': 'HTMLSelectElement', |
- 'source': 'HTMLSourceElement', |
- 'span': 'HTMLSpanElement', |
- 'style': 'HTMLStyleElement', |
- 'caption': 'HTMLTableCaptionElement', |
- // WebKit and Moz are wrong: |
- // https://bugs.webkit.org/show_bug.cgi?id=111469 |
- // https://bugzilla.mozilla.org/show_bug.cgi?id=848096 |
- // 'td': 'HTMLTableCellElement', |
- 'col': 'HTMLTableColElement', |
- 'table': 'HTMLTableElement', |
- 'tr': 'HTMLTableRowElement', |
- 'thead': 'HTMLTableSectionElement', |
- 'tbody': 'HTMLTableSectionElement', |
- 'textarea': 'HTMLTextAreaElement', |
- 'title': 'HTMLTitleElement', |
- 'ul': 'HTMLUListElement', |
- 'video': 'HTMLVideoElement', |
- }; |
- |
- function overrideConstructor(tagName) { |
- var nativeConstructorName = elements[tagName]; |
- var nativeConstructor = window[nativeConstructorName]; |
- if (!nativeConstructor) |
- return; |
- var element = document.createElement(tagName); |
- var wrapperConstructor = element.constructor; |
- window[nativeConstructorName] = wrapperConstructor; |
- } |
- |
- Object.keys(elements).forEach(overrideConstructor); |
- |
- Object.getOwnPropertyNames(scope.wrappers).forEach(function(name) { |
- window[name] = scope.wrappers[name] |
- }); |
- |
- // Export for testing. |
- scope.knownElements = elements; |
- |
-})(this.ShadowDOMPolyfill); |
-/* |
- * Copyright 2013 The Polymer Authors. All rights reserved. |
- * Use of this source code is governed by a BSD-style |
- * license that can be found in the LICENSE file. |
- */ |
-(function() { |
- var ShadowDOMPolyfill = window.ShadowDOMPolyfill; |
- var wrap = ShadowDOMPolyfill.wrap; |
- |
- // patch in prefixed name |
- Object.defineProperties(HTMLElement.prototype, { |
- //TODO(sjmiles): review accessor alias with Arv |
- webkitShadowRoot: { |
- get: function() { |
- return this.shadowRoot; |
- } |
- } |
- }); |
- |
- //TODO(sjmiles): review method alias with Arv |
- HTMLElement.prototype.webkitCreateShadowRoot = |
- HTMLElement.prototype.createShadowRoot; |
- |
- // TODO(jmesserly): figure out what to do about these Dart-specific patches |
- // Right now it depends on some dart2js impl details to patch getTypeNameOf |
- // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?) |
- window.dartMainRunner = function(main) { |
- var NodeList = ShadowDOMPolyfill.wrappers.NodeList; |
- var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot; |
- var isWrapper = ShadowDOMPolyfill.isWrapper; |
- var unwrap = ShadowDOMPolyfill.unwrap; |
- var innerTypeNameOf = window.$.getFunctionForTypeNameOf(); |
- |
- function typeNameOfShadowDOM(obj) { |
- var result; |
- if (obj instanceof NodeList) { |
- result = 'NodeList'; |
- } else if (obj instanceof ShadowRoot) { |
- result = 'ShadowRoot'; |
- } else if (obj instanceof MutationRecord) { |
- result = 'MutationRecord'; |
- } else if (obj instanceof MutationObserver) { |
- result = 'MutationObserver'; |
- } else { |
- if (isWrapper(obj)) { |
- obj = unwrap(obj); |
- |
- // Fix up class names for Firefox. For some of them like |
- // HTMLFormElement and HTMLInputElement, the "constructor" property of |
- // the unwrapped nodes points at the wrapper for some reason. |
- // TODO(jmesserly): figure out why this is happening. |
- var ctor = obj.constructor; |
- if (ctor && !ctor.builtin$cls && ctor.name == 'GeneratedWrapper') { |
- var name = Object.prototype.toString.call(obj); |
- name = name.substring(8, name.length - 1); |
- ctor.builtin$cls = name; |
- } |
- } |
- |
- result = innerTypeNameOf.call$1(obj); |
- } |
- |
- return result; |
- } |
- |
- function constructorNameShadowDOM(object) { |
- var $constructor, $name, string; |
- if (object == null) |
- return "Null"; |
- $constructor = object.constructor; |
- if (typeof $constructor === "function") { |
- $name = $constructor.builtin$cls; |
- if ($name != null) |
- return $name; |
- } |
- |
- } |
- |
- window.$.constructorNameFallback = constructorNameShadowDOM; |
- window.$._getTypeNameOf = { call$1: typeNameOfShadowDOM }; |
- window.Isolate.$isolateProperties._getTypeNameOf = window.$._getTypeNameOf; |
- |
- // Invoke the real main |
- main(); |
- }; |
- |
-})(); |
- |
-} |