| Index: pkg/shadow_dom/lib/shadow_dom.debug.js
|
| diff --git a/pkg/shadow_dom/lib/shadow_dom.debug.js b/pkg/shadow_dom/lib/shadow_dom.debug.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dc87a193258414d10a8c251a575cc418c40f7f0f
|
| --- /dev/null
|
| +++ b/pkg/shadow_dom/lib/shadow_dom.debug.js
|
| @@ -0,0 +1,3221 @@
|
| +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();
|
| + };
|
| +
|
| +})();
|
| +
|
| +}
|
|
|