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

Unified Diff: runtime/bin/vmservice/client/deployed/web/packages/web_components/platform.concat.js

Issue 342513004: Visual refresh of allocation profile page (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/bin/vmservice/client/deployed/web/packages/web_components/platform.concat.js
diff --git a/runtime/bin/vmservice/client/deployed/web/packages/web_components/platform.concat.js b/runtime/bin/vmservice/client/deployed/web/packages/web_components/platform.concat.js
deleted file mode 100644
index 9fa19b5c3d0c77a98d5e5a12c59c39c79628b508..0000000000000000000000000000000000000000
--- a/runtime/bin/vmservice/client/deployed/web/packages/web_components/platform.concat.js
+++ /dev/null
@@ -1,17703 +0,0 @@
-/*
- * Copyright 2012 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.
- */
-
-if (typeof WeakMap === 'undefined') {
- (function() {
- var defineProperty = Object.defineProperty;
- var counter = Date.now() % 1e9;
-
- var WeakMap = function() {
- this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
- };
-
- WeakMap.prototype = {
- set: function(key, value) {
- var entry = key[this.name];
- if (entry && entry[0] === key)
- entry[1] = value;
- else
- defineProperty(key, this.name, {value: [key, value], writable: true});
- },
- get: function(key) {
- var entry;
- return (entry = key[this.name]) && entry[0] === key ?
- entry[1] : undefined;
- },
- delete: function(key) {
- this.set(key, undefined);
- }
- };
-
- window.WeakMap = WeakMap;
- })();
-}
-
-// Copyright 2012 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-(function(global) {
- 'use strict';
-
- // Detect and do basic sanity checking on Object/Array.observe.
- function detectObjectObserve() {
- if (typeof Object.observe !== 'function' ||
- typeof Array.observe !== 'function') {
- return false;
- }
-
- var records = [];
-
- function callback(recs) {
- records = recs;
- }
-
- var test = {};
- var arr = [];
- Object.observe(test, callback);
- Array.observe(arr, callback);
- test.id = 1;
- test.id = 2;
- delete test.id;
- arr.push(1, 2);
- arr.length = 0;
-
- Object.deliverChangeRecords(callback);
- if (records.length !== 5)
- return false;
-
- if (records[0].type != 'add' ||
- records[1].type != 'update' ||
- records[2].type != 'delete' ||
- records[3].type != 'splice' ||
- records[4].type != 'splice') {
- return false;
- }
-
- Object.unobserve(test, callback);
- Array.unobserve(arr, callback);
-
- return true;
- }
-
- var hasObserve = detectObjectObserve();
-
- function detectEval() {
- // don't test for eval if document has CSP securityPolicy object and we can see that
- // eval is not supported. This avoids an error message in console even when the exception
- // is caught
- if (global.document &&
- 'securityPolicy' in global.document &&
- !global.document.securityPolicy.allowsEval) {
- return false;
- }
-
- try {
- var f = new Function('', 'return true;');
- return f();
- } catch (ex) {
- return false;
- }
- }
-
- var hasEval = detectEval();
-
- function isIndex(s) {
- return +s === s >>> 0;
- }
-
- function toNumber(s) {
- return +s;
- }
-
- function isObject(obj) {
- return obj === Object(obj);
- }
-
- var numberIsNaN = global.Number.isNaN || function isNaN(value) {
- return typeof value === 'number' && global.isNaN(value);
- }
-
- function areSameValue(left, right) {
- if (left === right)
- return left !== 0 || 1 / left === 1 / right;
- if (numberIsNaN(left) && numberIsNaN(right))
- return true;
-
- return left !== left && right !== right;
- }
-
- var createObject = ('__proto__' in {}) ?
- function(obj) { return obj; } :
- function(obj) {
- var proto = obj.__proto__;
- if (!proto)
- return obj;
- var newObject = Object.create(proto);
- Object.getOwnPropertyNames(obj).forEach(function(name) {
- Object.defineProperty(newObject, name,
- Object.getOwnPropertyDescriptor(obj, name));
- });
- return newObject;
- };
-
- var identStart = '[\$_a-zA-Z]';
- var identPart = '[\$_a-zA-Z0-9]';
- var ident = identStart + '+' + identPart + '*';
- var elementIndex = '(?:[0-9]|[1-9]+[0-9]+)';
- var identOrElementIndex = '(?:' + ident + '|' + elementIndex + ')';
- var path = '(?:' + identOrElementIndex + ')(?:\\s*\\.\\s*' + identOrElementIndex + ')*';
- var pathRegExp = new RegExp('^' + path + '$');
-
- function isPathValid(s) {
- if (typeof s != 'string')
- return false;
- s = s.trim();
-
- if (s == '')
- return true;
-
- if (s[0] == '.')
- return false;
-
- return pathRegExp.test(s);
- }
-
- var constructorIsPrivate = {};
-
- function Path(s, privateToken) {
- if (privateToken !== constructorIsPrivate)
- throw Error('Use Path.get to retrieve path objects');
-
- if (s.trim() == '')
- return this;
-
- if (isIndex(s)) {
- this.push(s);
- return this;
- }
-
- s.split(/\s*\.\s*/).filter(function(part) {
- return part;
- }).forEach(function(part) {
- this.push(part);
- }, this);
-
- if (hasEval && this.length) {
- this.getValueFrom = this.compiledGetValueFromFn();
- }
- }
-
- // TODO(rafaelw): Make simple LRU cache
- var pathCache = {};
-
- function getPath(pathString) {
- if (pathString instanceof Path)
- return pathString;
-
- if (pathString == null)
- pathString = '';
-
- if (typeof pathString !== 'string')
- pathString = String(pathString);
-
- var path = pathCache[pathString];
- if (path)
- return path;
- if (!isPathValid(pathString))
- return invalidPath;
- var path = new Path(pathString, constructorIsPrivate);
- pathCache[pathString] = path;
- return path;
- }
-
- Path.get = getPath;
-
- Path.prototype = createObject({
- __proto__: [],
- valid: true,
-
- toString: function() {
- return this.join('.');
- },
-
- getValueFrom: function(obj, directObserver) {
- for (var i = 0; i < this.length; i++) {
- if (obj == null)
- return;
- obj = obj[this[i]];
- }
- return obj;
- },
-
- iterateObjects: function(obj, observe) {
- for (var i = 0; i < this.length; i++) {
- if (i)
- obj = obj[this[i - 1]];
- if (!isObject(obj))
- return;
- observe(obj);
- }
- },
-
- compiledGetValueFromFn: function() {
- var accessors = this.map(function(ident) {
- return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
- });
-
- var str = '';
- var pathString = 'obj';
- str += 'if (obj != null';
- var i = 0;
- for (; i < (this.length - 1); i++) {
- var ident = this[i];
- pathString += accessors[i];
- str += ' &&\n ' + pathString + ' != null';
- }
- str += ')\n';
-
- pathString += accessors[i];
-
- str += ' return ' + pathString + ';\nelse\n return undefined;';
- return new Function('obj', str);
- },
-
- setValueFrom: function(obj, value) {
- if (!this.length)
- return false;
-
- for (var i = 0; i < this.length - 1; i++) {
- if (!isObject(obj))
- return false;
- obj = obj[this[i]];
- }
-
- if (!isObject(obj))
- return false;
-
- obj[this[i]] = value;
- return true;
- }
- });
-
- var invalidPath = new Path('', constructorIsPrivate);
- invalidPath.valid = false;
- invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
-
- var MAX_DIRTY_CHECK_CYCLES = 1000;
-
- function dirtyCheck(observer) {
- var cycles = 0;
- while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
- cycles++;
- }
- if (global.testingExposeCycleCount)
- global.dirtyCheckCycleCount = cycles;
-
- return cycles > 0;
- }
-
- function objectIsEmpty(object) {
- for (var prop in object)
- return false;
- return true;
- }
-
- function diffIsEmpty(diff) {
- return objectIsEmpty(diff.added) &&
- objectIsEmpty(diff.removed) &&
- objectIsEmpty(diff.changed);
- }
-
- function diffObjectFromOldObject(object, oldObject) {
- var added = {};
- var removed = {};
- var changed = {};
-
- for (var prop in oldObject) {
- var newValue = object[prop];
-
- if (newValue !== undefined && newValue === oldObject[prop])
- continue;
-
- if (!(prop in object)) {
- removed[prop] = undefined;
- continue;
- }
-
- if (newValue !== oldObject[prop])
- changed[prop] = newValue;
- }
-
- for (var prop in object) {
- if (prop in oldObject)
- continue;
-
- added[prop] = object[prop];
- }
-
- if (Array.isArray(object) && object.length !== oldObject.length)
- changed.length = object.length;
-
- return {
- added: added,
- removed: removed,
- changed: changed
- };
- }
-
- var eomTasks = [];
- function runEOMTasks() {
- if (!eomTasks.length)
- return false;
-
- for (var i = 0; i < eomTasks.length; i++) {
- eomTasks[i]();
- }
- eomTasks.length = 0;
- return true;
- }
-
- var runEOM = hasObserve ? (function(){
- var eomObj = { pingPong: true };
- var eomRunScheduled = false;
-
- Object.observe(eomObj, function() {
- runEOMTasks();
- eomRunScheduled = false;
- });
-
- return function(fn) {
- eomTasks.push(fn);
- if (!eomRunScheduled) {
- eomRunScheduled = true;
- eomObj.pingPong = !eomObj.pingPong;
- }
- };
- })() :
- (function() {
- return function(fn) {
- eomTasks.push(fn);
- };
- })();
-
- var observedObjectCache = [];
-
- function newObservedObject() {
- var observer;
- var object;
- var discardRecords = false;
- var first = true;
-
- function callback(records) {
- if (observer && observer.state_ === OPENED && !discardRecords)
- observer.check_(records);
- }
-
- return {
- open: function(obs) {
- if (observer)
- throw Error('ObservedObject in use');
-
- if (!first)
- Object.deliverChangeRecords(callback);
-
- observer = obs;
- first = false;
- },
- observe: function(obj, arrayObserve) {
- object = obj;
- if (arrayObserve)
- Array.observe(object, callback);
- else
- Object.observe(object, callback);
- },
- deliver: function(discard) {
- discardRecords = discard;
- Object.deliverChangeRecords(callback);
- discardRecords = false;
- },
- close: function() {
- observer = undefined;
- Object.unobserve(object, callback);
- observedObjectCache.push(this);
- }
- };
- }
-
- function getObservedObject(observer, object, arrayObserve) {
- var dir = observedObjectCache.pop() || newObservedObject();
- dir.open(observer);
- dir.observe(object, arrayObserve);
- return dir;
- }
-
- var emptyArray = [];
- var observedSetCache = [];
-
- function newObservedSet() {
- var observers = [];
- var observerCount = 0;
- var objects = [];
- var toRemove = emptyArray;
- var resetNeeded = false;
- var resetScheduled = false;
-
- function observe(obj) {
- if (!obj)
- return;
-
- var index = toRemove.indexOf(obj);
- if (index >= 0) {
- toRemove[index] = undefined;
- objects.push(obj);
- } else if (objects.indexOf(obj) < 0) {
- objects.push(obj);
- Object.observe(obj, callback);
- }
-
- observe(Object.getPrototypeOf(obj));
- }
-
- function reset() {
- var objs = toRemove === emptyArray ? [] : toRemove;
- toRemove = objects;
- objects = objs;
-
- var observer;
- for (var id in observers) {
- observer = observers[id];
- if (!observer || observer.state_ != OPENED)
- continue;
-
- observer.iterateObjects_(observe);
- }
-
- for (var i = 0; i < toRemove.length; i++) {
- var obj = toRemove[i];
- if (obj)
- Object.unobserve(obj, callback);
- }
-
- toRemove.length = 0;
- }
-
- function scheduledReset() {
- resetScheduled = false;
- if (!resetNeeded)
- return;
-
- reset();
- }
-
- function scheduleReset() {
- if (resetScheduled)
- return;
-
- resetNeeded = true;
- resetScheduled = true;
- runEOM(scheduledReset);
- }
-
- function callback() {
- reset();
-
- var observer;
-
- for (var id in observers) {
- observer = observers[id];
- if (!observer || observer.state_ != OPENED)
- continue;
-
- observer.check_();
- }
- }
-
- var record = {
- object: undefined,
- objects: objects,
- open: function(obs) {
- observers[obs.id_] = obs;
- observerCount++;
- obs.iterateObjects_(observe);
- },
- close: function(obs) {
- var anyLeft = false;
-
- observers[obs.id_] = undefined;
- observerCount--;
-
- if (observerCount) {
- scheduleReset();
- return;
- }
- resetNeeded = false;
-
- for (var i = 0; i < objects.length; i++) {
- Object.unobserve(objects[i], callback);
- Observer.unobservedCount++;
- }
-
- observers.length = 0;
- objects.length = 0;
- observedSetCache.push(this);
- },
- reset: scheduleReset
- };
-
- return record;
- }
-
- var lastObservedSet;
-
- function getObservedSet(observer, obj) {
- if (!lastObservedSet || lastObservedSet.object !== obj) {
- lastObservedSet = observedSetCache.pop() || newObservedSet();
- lastObservedSet.object = obj;
- }
- lastObservedSet.open(observer);
- return lastObservedSet;
- }
-
- var UNOPENED = 0;
- var OPENED = 1;
- var CLOSED = 2;
- var RESETTING = 3;
-
- var nextObserverId = 1;
-
- function Observer() {
- this.state_ = UNOPENED;
- this.callback_ = undefined;
- this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
- this.directObserver_ = undefined;
- this.value_ = undefined;
- this.id_ = nextObserverId++;
- }
-
- Observer.prototype = {
- open: function(callback, target) {
- if (this.state_ != UNOPENED)
- throw Error('Observer has already been opened.');
-
- addToAll(this);
- this.callback_ = callback;
- this.target_ = target;
- this.state_ = OPENED;
- this.connect_();
- return this.value_;
- },
-
- close: function() {
- if (this.state_ != OPENED)
- return;
-
- removeFromAll(this);
- this.state_ = CLOSED;
- this.disconnect_();
- this.value_ = undefined;
- this.callback_ = undefined;
- this.target_ = undefined;
- },
-
- deliver: function() {
- if (this.state_ != OPENED)
- return;
-
- dirtyCheck(this);
- },
-
- report_: function(changes) {
- try {
- this.callback_.apply(this.target_, changes);
- } catch (ex) {
- Observer._errorThrownDuringCallback = true;
- console.error('Exception caught during observer callback: ' +
- (ex.stack || ex));
- }
- },
-
- discardChanges: function() {
- this.check_(undefined, true);
- return this.value_;
- }
- }
-
- var collectObservers = !hasObserve;
- var allObservers;
- Observer._allObserversCount = 0;
-
- if (collectObservers) {
- allObservers = [];
- }
-
- function addToAll(observer) {
- Observer._allObserversCount++;
- if (!collectObservers)
- return;
-
- allObservers.push(observer);
- }
-
- function removeFromAll(observer) {
- Observer._allObserversCount--;
- }
-
- var runningMicrotaskCheckpoint = false;
-
- var hasDebugForceFullDelivery = hasObserve && (function() {
- try {
- eval('%RunMicrotasks()');
- return true;
- } catch (ex) {
- return false;
- }
- })();
-
- global.Platform = global.Platform || {};
-
- global.Platform.performMicrotaskCheckpoint = function() {
- if (runningMicrotaskCheckpoint)
- return;
-
- if (hasDebugForceFullDelivery) {
- eval('%RunMicrotasks()');
- return;
- }
-
- if (!collectObservers)
- return;
-
- runningMicrotaskCheckpoint = true;
-
- var cycles = 0;
- var anyChanged, toCheck;
-
- do {
- cycles++;
- toCheck = allObservers;
- allObservers = [];
- anyChanged = false;
-
- for (var i = 0; i < toCheck.length; i++) {
- var observer = toCheck[i];
- if (observer.state_ != OPENED)
- continue;
-
- if (observer.check_())
- anyChanged = true;
-
- allObservers.push(observer);
- }
- if (runEOMTasks())
- anyChanged = true;
- } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
-
- if (global.testingExposeCycleCount)
- global.dirtyCheckCycleCount = cycles;
-
- runningMicrotaskCheckpoint = false;
- };
-
- if (collectObservers) {
- global.Platform.clearObservers = function() {
- allObservers = [];
- };
- }
-
- function ObjectObserver(object) {
- Observer.call(this);
- this.value_ = object;
- this.oldObject_ = undefined;
- }
-
- ObjectObserver.prototype = createObject({
- __proto__: Observer.prototype,
-
- arrayObserve: false,
-
- connect_: function(callback, target) {
- if (hasObserve) {
- this.directObserver_ = getObservedObject(this, this.value_,
- this.arrayObserve);
- } else {
- this.oldObject_ = this.copyObject(this.value_);
- }
-
- },
-
- copyObject: function(object) {
- var copy = Array.isArray(object) ? [] : {};
- for (var prop in object) {
- copy[prop] = object[prop];
- };
- if (Array.isArray(object))
- copy.length = object.length;
- return copy;
- },
-
- check_: function(changeRecords, skipChanges) {
- var diff;
- var oldValues;
- if (hasObserve) {
- if (!changeRecords)
- return false;
-
- oldValues = {};
- diff = diffObjectFromChangeRecords(this.value_, changeRecords,
- oldValues);
- } else {
- oldValues = this.oldObject_;
- diff = diffObjectFromOldObject(this.value_, this.oldObject_);
- }
-
- if (diffIsEmpty(diff))
- return false;
-
- if (!hasObserve)
- this.oldObject_ = this.copyObject(this.value_);
-
- this.report_([
- diff.added || {},
- diff.removed || {},
- diff.changed || {},
- function(property) {
- return oldValues[property];
- }
- ]);
-
- return true;
- },
-
- disconnect_: function() {
- if (hasObserve) {
- this.directObserver_.close();
- this.directObserver_ = undefined;
- } else {
- this.oldObject_ = undefined;
- }
- },
-
- deliver: function() {
- if (this.state_ != OPENED)
- return;
-
- if (hasObserve)
- this.directObserver_.deliver(false);
- else
- dirtyCheck(this);
- },
-
- discardChanges: function() {
- if (this.directObserver_)
- this.directObserver_.deliver(true);
- else
- this.oldObject_ = this.copyObject(this.value_);
-
- return this.value_;
- }
- });
-
- function ArrayObserver(array) {
- if (!Array.isArray(array))
- throw Error('Provided object is not an Array');
- ObjectObserver.call(this, array);
- }
-
- ArrayObserver.prototype = createObject({
-
- __proto__: ObjectObserver.prototype,
-
- arrayObserve: true,
-
- copyObject: function(arr) {
- return arr.slice();
- },
-
- check_: function(changeRecords) {
- var splices;
- if (hasObserve) {
- if (!changeRecords)
- return false;
- splices = projectArraySplices(this.value_, changeRecords);
- } else {
- splices = calcSplices(this.value_, 0, this.value_.length,
- this.oldObject_, 0, this.oldObject_.length);
- }
-
- if (!splices || !splices.length)
- return false;
-
- if (!hasObserve)
- this.oldObject_ = this.copyObject(this.value_);
-
- this.report_([splices]);
- return true;
- }
- });
-
- ArrayObserver.applySplices = function(previous, current, splices) {
- splices.forEach(function(splice) {
- var spliceArgs = [splice.index, splice.removed.length];
- var addIndex = splice.index;
- while (addIndex < splice.index + splice.addedCount) {
- spliceArgs.push(current[addIndex]);
- addIndex++;
- }
-
- Array.prototype.splice.apply(previous, spliceArgs);
- });
- };
-
- function PathObserver(object, path) {
- Observer.call(this);
-
- this.object_ = object;
- this.path_ = path instanceof Path ? path : getPath(path);
- this.directObserver_ = undefined;
- }
-
- PathObserver.prototype = createObject({
- __proto__: Observer.prototype,
-
- connect_: function() {
- if (hasObserve)
- this.directObserver_ = getObservedSet(this, this.object_);
-
- this.check_(undefined, true);
- },
-
- disconnect_: function() {
- this.value_ = undefined;
-
- if (this.directObserver_) {
- this.directObserver_.close(this);
- this.directObserver_ = undefined;
- }
- },
-
- iterateObjects_: function(observe) {
- this.path_.iterateObjects(this.object_, observe);
- },
-
- check_: function(changeRecords, skipChanges) {
- var oldValue = this.value_;
- this.value_ = this.path_.getValueFrom(this.object_);
- if (skipChanges || areSameValue(this.value_, oldValue))
- return false;
-
- this.report_([this.value_, oldValue]);
- return true;
- },
-
- setValue: function(newValue) {
- if (this.path_)
- this.path_.setValueFrom(this.object_, newValue);
- }
- });
-
- function CompoundObserver() {
- Observer.call(this);
-
- this.value_ = [];
- this.directObserver_ = undefined;
- this.observed_ = [];
- }
-
- var observerSentinel = {};
-
- CompoundObserver.prototype = createObject({
- __proto__: Observer.prototype,
-
- connect_: function() {
- this.check_(undefined, true);
-
- if (!hasObserve)
- return;
-
- var object;
- var needsDirectObserver = false;
- for (var i = 0; i < this.observed_.length; i += 2) {
- object = this.observed_[i]
- if (object !== observerSentinel) {
- needsDirectObserver = true;
- break;
- }
- }
-
- if (this.directObserver_) {
- if (needsDirectObserver) {
- this.directObserver_.reset();
- return;
- }
- this.directObserver_.close();
- this.directObserver_ = undefined;
- return;
- }
-
- if (needsDirectObserver)
- this.directObserver_ = getObservedSet(this, object);
- },
-
- closeObservers_: function() {
- for (var i = 0; i < this.observed_.length; i += 2) {
- if (this.observed_[i] === observerSentinel)
- this.observed_[i + 1].close();
- }
- this.observed_.length = 0;
- },
-
- disconnect_: function() {
- this.value_ = undefined;
-
- if (this.directObserver_) {
- this.directObserver_.close(this);
- this.directObserver_ = undefined;
- }
-
- this.closeObservers_();
- },
-
- addPath: function(object, path) {
- if (this.state_ != UNOPENED && this.state_ != RESETTING)
- throw Error('Cannot add paths once started.');
-
- this.observed_.push(object, path instanceof Path ? path : getPath(path));
- },
-
- addObserver: function(observer) {
- if (this.state_ != UNOPENED && this.state_ != RESETTING)
- throw Error('Cannot add observers once started.');
-
- observer.open(this.deliver, this);
- this.observed_.push(observerSentinel, observer);
- },
-
- startReset: function() {
- if (this.state_ != OPENED)
- throw Error('Can only reset while open');
-
- this.state_ = RESETTING;
- this.closeObservers_();
- },
-
- finishReset: function() {
- if (this.state_ != RESETTING)
- throw Error('Can only finishReset after startReset');
- this.state_ = OPENED;
- this.connect_();
-
- return this.value_;
- },
-
- iterateObjects_: function(observe) {
- var object;
- for (var i = 0; i < this.observed_.length; i += 2) {
- object = this.observed_[i]
- if (object !== observerSentinel)
- this.observed_[i + 1].iterateObjects(object, observe)
- }
- },
-
- check_: function(changeRecords, skipChanges) {
- var oldValues;
- for (var i = 0; i < this.observed_.length; i += 2) {
- var pathOrObserver = this.observed_[i+1];
- var object = this.observed_[i];
- var value = object === observerSentinel ?
- pathOrObserver.discardChanges() :
- pathOrObserver.getValueFrom(object)
-
- if (skipChanges) {
- this.value_[i / 2] = value;
- continue;
- }
-
- if (areSameValue(value, this.value_[i / 2]))
- continue;
-
- oldValues = oldValues || [];
- oldValues[i / 2] = this.value_[i / 2];
- this.value_[i / 2] = value;
- }
-
- if (!oldValues)
- return false;
-
- // TODO(rafaelw): Having observed_ as the third callback arg here is
- // pretty lame API. Fix.
- this.report_([this.value_, oldValues, this.observed_]);
- return true;
- }
- });
-
- function identFn(value) { return value; }
-
- function ObserverTransform(observable, getValueFn, setValueFn,
- dontPassThroughSet) {
- this.callback_ = undefined;
- this.target_ = undefined;
- this.value_ = undefined;
- this.observable_ = observable;
- this.getValueFn_ = getValueFn || identFn;
- this.setValueFn_ = setValueFn || identFn;
- // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
- // at the moment because of a bug in it's dependency tracking.
- this.dontPassThroughSet_ = dontPassThroughSet;
- }
-
- ObserverTransform.prototype = {
- open: function(callback, target) {
- this.callback_ = callback;
- this.target_ = target;
- this.value_ =
- this.getValueFn_(this.observable_.open(this.observedCallback_, this));
- return this.value_;
- },
-
- observedCallback_: function(value) {
- value = this.getValueFn_(value);
- if (areSameValue(value, this.value_))
- return;
- var oldValue = this.value_;
- this.value_ = value;
- this.callback_.call(this.target_, this.value_, oldValue);
- },
-
- discardChanges: function() {
- this.value_ = this.getValueFn_(this.observable_.discardChanges());
- return this.value_;
- },
-
- deliver: function() {
- return this.observable_.deliver();
- },
-
- setValue: function(value) {
- value = this.setValueFn_(value);
- if (!this.dontPassThroughSet_ && this.observable_.setValue)
- return this.observable_.setValue(value);
- },
-
- close: function() {
- if (this.observable_)
- this.observable_.close();
- this.callback_ = undefined;
- this.target_ = undefined;
- this.observable_ = undefined;
- this.value_ = undefined;
- this.getValueFn_ = undefined;
- this.setValueFn_ = undefined;
- }
- }
-
- var expectedRecordTypes = {
- add: true,
- update: true,
- delete: true
- };
-
- function notifyFunction(object, name) {
- if (typeof Object.observe !== 'function')
- return;
-
- var notifier = Object.getNotifier(object);
- return function(type, oldValue) {
- var changeRecord = {
- object: object,
- type: type,
- name: name
- };
- if (arguments.length === 2)
- changeRecord.oldValue = oldValue;
- notifier.notify(changeRecord);
- }
- }
-
- Observer.defineComputedProperty = function(target, name, observable) {
- var notify = notifyFunction(target, name);
- var value = observable.open(function(newValue, oldValue) {
- value = newValue;
- if (notify)
- notify('update', oldValue);
- });
-
- Object.defineProperty(target, name, {
- get: function() {
- observable.deliver();
- return value;
- },
- set: function(newValue) {
- observable.setValue(newValue);
- return newValue;
- },
- configurable: true
- });
-
- return {
- close: function() {
- observable.close();
- Object.defineProperty(target, name, {
- value: value,
- writable: true,
- configurable: true
- });
- }
- };
- }
-
- function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
- var added = {};
- var removed = {};
-
- for (var i = 0; i < changeRecords.length; i++) {
- var record = changeRecords[i];
- if (!expectedRecordTypes[record.type]) {
- console.error('Unknown changeRecord type: ' + record.type);
- console.error(record);
- continue;
- }
-
- if (!(record.name in oldValues))
- oldValues[record.name] = record.oldValue;
-
- if (record.type == 'update')
- continue;
-
- if (record.type == 'add') {
- if (record.name in removed)
- delete removed[record.name];
- else
- added[record.name] = true;
-
- continue;
- }
-
- // type = 'delete'
- if (record.name in added) {
- delete added[record.name];
- delete oldValues[record.name];
- } else {
- removed[record.name] = true;
- }
- }
-
- for (var prop in added)
- added[prop] = object[prop];
-
- for (var prop in removed)
- removed[prop] = undefined;
-
- var changed = {};
- for (var prop in oldValues) {
- if (prop in added || prop in removed)
- continue;
-
- var newValue = object[prop];
- if (oldValues[prop] !== newValue)
- changed[prop] = newValue;
- }
-
- return {
- added: added,
- removed: removed,
- changed: changed
- };
- }
-
- function newSplice(index, removed, addedCount) {
- return {
- index: index,
- removed: removed,
- addedCount: addedCount
- };
- }
-
- var EDIT_LEAVE = 0;
- var EDIT_UPDATE = 1;
- var EDIT_ADD = 2;
- var EDIT_DELETE = 3;
-
- function ArraySplice() {}
-
- ArraySplice.prototype = {
-
- // Note: This function is *based* on the computation of the Levenshtein
- // "edit" distance. The one change is that "updates" are treated as two
- // edits - not one. With Array splices, an update is really a delete
- // followed by an add. By retaining this, we optimize for "keeping" the
- // maximum array items in the original array. For example:
- //
- // 'xxxx123' -> '123yyyy'
- //
- // With 1-edit updates, the shortest path would be just to update all seven
- // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
- // leaves the substring '123' intact.
- calcEditDistances: function(current, currentStart, currentEnd,
- old, oldStart, oldEnd) {
- // "Deletion" columns
- var rowCount = oldEnd - oldStart + 1;
- var columnCount = currentEnd - currentStart + 1;
- var distances = new Array(rowCount);
-
- // "Addition" rows. Initialize null column.
- for (var i = 0; i < rowCount; i++) {
- distances[i] = new Array(columnCount);
- distances[i][0] = i;
- }
-
- // Initialize null row
- for (var j = 0; j < columnCount; j++)
- distances[0][j] = j;
-
- for (var i = 1; i < rowCount; i++) {
- for (var j = 1; j < columnCount; j++) {
- if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
- distances[i][j] = distances[i - 1][j - 1];
- else {
- var north = distances[i - 1][j] + 1;
- var west = distances[i][j - 1] + 1;
- distances[i][j] = north < west ? north : west;
- }
- }
- }
-
- return distances;
- },
-
- // This starts at the final weight, and walks "backward" by finding
- // the minimum previous weight recursively until the origin of the weight
- // matrix.
- spliceOperationsFromEditDistances: function(distances) {
- var i = distances.length - 1;
- var j = distances[0].length - 1;
- var current = distances[i][j];
- var edits = [];
- while (i > 0 || j > 0) {
- if (i == 0) {
- edits.push(EDIT_ADD);
- j--;
- continue;
- }
- if (j == 0) {
- edits.push(EDIT_DELETE);
- i--;
- continue;
- }
- var northWest = distances[i - 1][j - 1];
- var west = distances[i - 1][j];
- var north = distances[i][j - 1];
-
- var min;
- if (west < north)
- min = west < northWest ? west : northWest;
- else
- min = north < northWest ? north : northWest;
-
- if (min == northWest) {
- if (northWest == current) {
- edits.push(EDIT_LEAVE);
- } else {
- edits.push(EDIT_UPDATE);
- current = northWest;
- }
- i--;
- j--;
- } else if (min == west) {
- edits.push(EDIT_DELETE);
- i--;
- current = west;
- } else {
- edits.push(EDIT_ADD);
- j--;
- current = north;
- }
- }
-
- edits.reverse();
- return edits;
- },
-
- /**
- * Splice Projection functions:
- *
- * A splice map is a representation of how a previous array of items
- * was transformed into a new array of items. Conceptually it is a list of
- * tuples of
- *
- * <index, removed, addedCount>
- *
- * which are kept in ascending index order of. The tuple represents that at
- * the |index|, |removed| sequence of items were removed, and counting forward
- * from |index|, |addedCount| items were added.
- */
-
- /**
- * Lacking individual splice mutation information, the minimal set of
- * splices can be synthesized given the previous state and final state of an
- * array. The basic approach is to calculate the edit distance matrix and
- * choose the shortest path through it.
- *
- * Complexity: O(l * p)
- * l: The length of the current array
- * p: The length of the old array
- */
- calcSplices: function(current, currentStart, currentEnd,
- old, oldStart, oldEnd) {
- var prefixCount = 0;
- var suffixCount = 0;
-
- var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
- if (currentStart == 0 && oldStart == 0)
- prefixCount = this.sharedPrefix(current, old, minLength);
-
- if (currentEnd == current.length && oldEnd == old.length)
- suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
-
- currentStart += prefixCount;
- oldStart += prefixCount;
- currentEnd -= suffixCount;
- oldEnd -= suffixCount;
-
- if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
- return [];
-
- if (currentStart == currentEnd) {
- var splice = newSplice(currentStart, [], 0);
- while (oldStart < oldEnd)
- splice.removed.push(old[oldStart++]);
-
- return [ splice ];
- } else if (oldStart == oldEnd)
- return [ newSplice(currentStart, [], currentEnd - currentStart) ];
-
- var ops = this.spliceOperationsFromEditDistances(
- this.calcEditDistances(current, currentStart, currentEnd,
- old, oldStart, oldEnd));
-
- var splice = undefined;
- var splices = [];
- var index = currentStart;
- var oldIndex = oldStart;
- for (var i = 0; i < ops.length; i++) {
- switch(ops[i]) {
- case EDIT_LEAVE:
- if (splice) {
- splices.push(splice);
- splice = undefined;
- }
-
- index++;
- oldIndex++;
- break;
- case EDIT_UPDATE:
- if (!splice)
- splice = newSplice(index, [], 0);
-
- splice.addedCount++;
- index++;
-
- splice.removed.push(old[oldIndex]);
- oldIndex++;
- break;
- case EDIT_ADD:
- if (!splice)
- splice = newSplice(index, [], 0);
-
- splice.addedCount++;
- index++;
- break;
- case EDIT_DELETE:
- if (!splice)
- splice = newSplice(index, [], 0);
-
- splice.removed.push(old[oldIndex]);
- oldIndex++;
- break;
- }
- }
-
- if (splice) {
- splices.push(splice);
- }
- return splices;
- },
-
- sharedPrefix: function(current, old, searchLength) {
- for (var i = 0; i < searchLength; i++)
- if (!this.equals(current[i], old[i]))
- return i;
- return searchLength;
- },
-
- sharedSuffix: function(current, old, searchLength) {
- var index1 = current.length;
- var index2 = old.length;
- var count = 0;
- while (count < searchLength && this.equals(current[--index1], old[--index2]))
- count++;
-
- return count;
- },
-
- calculateSplices: function(current, previous) {
- return this.calcSplices(current, 0, current.length, previous, 0,
- previous.length);
- },
-
- equals: function(currentValue, previousValue) {
- return currentValue === previousValue;
- }
- };
-
- var arraySplice = new ArraySplice();
-
- function calcSplices(current, currentStart, currentEnd,
- old, oldStart, oldEnd) {
- return arraySplice.calcSplices(current, currentStart, currentEnd,
- old, oldStart, oldEnd);
- }
-
- function intersect(start1, end1, start2, end2) {
- // Disjoint
- if (end1 < start2 || end2 < start1)
- return -1;
-
- // Adjacent
- if (end1 == start2 || end2 == start1)
- return 0;
-
- // Non-zero intersect, span1 first
- if (start1 < start2) {
- if (end1 < end2)
- return end1 - start2; // Overlap
- else
- return end2 - start2; // Contained
- } else {
- // Non-zero intersect, span2 first
- if (end2 < end1)
- return end2 - start1; // Overlap
- else
- return end1 - start1; // Contained
- }
- }
-
- function mergeSplice(splices, index, removed, addedCount) {
-
- var splice = newSplice(index, removed, addedCount);
-
- var inserted = false;
- var insertionOffset = 0;
-
- for (var i = 0; i < splices.length; i++) {
- var current = splices[i];
- current.index += insertionOffset;
-
- if (inserted)
- continue;
-
- var intersectCount = intersect(splice.index,
- splice.index + splice.removed.length,
- current.index,
- current.index + current.addedCount);
-
- if (intersectCount >= 0) {
- // Merge the two splices
-
- splices.splice(i, 1);
- i--;
-
- insertionOffset -= current.addedCount - current.removed.length;
-
- splice.addedCount += current.addedCount - intersectCount;
- var deleteCount = splice.removed.length +
- current.removed.length - intersectCount;
-
- if (!splice.addedCount && !deleteCount) {
- // merged splice is a noop. discard.
- inserted = true;
- } else {
- var removed = current.removed;
-
- if (splice.index < current.index) {
- // some prefix of splice.removed is prepended to current.removed.
- var prepend = splice.removed.slice(0, current.index - splice.index);
- Array.prototype.push.apply(prepend, removed);
- removed = prepend;
- }
-
- if (splice.index + splice.removed.length > current.index + current.addedCount) {
- // some suffix of splice.removed is appended to current.removed.
- var append = splice.removed.slice(current.index + current.addedCount - splice.index);
- Array.prototype.push.apply(removed, append);
- }
-
- splice.removed = removed;
- if (current.index < splice.index) {
- splice.index = current.index;
- }
- }
- } else if (splice.index < current.index) {
- // Insert splice here.
-
- inserted = true;
-
- splices.splice(i, 0, splice);
- i++;
-
- var offset = splice.addedCount - splice.removed.length
- current.index += offset;
- insertionOffset += offset;
- }
- }
-
- if (!inserted)
- splices.push(splice);
- }
-
- function createInitialSplices(array, changeRecords) {
- var splices = [];
-
- for (var i = 0; i < changeRecords.length; i++) {
- var record = changeRecords[i];
- switch(record.type) {
- case 'splice':
- mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
- break;
- case 'add':
- case 'update':
- case 'delete':
- if (!isIndex(record.name))
- continue;
- var index = toNumber(record.name);
- if (index < 0)
- continue;
- mergeSplice(splices, index, [record.oldValue], 1);
- break;
- default:
- console.error('Unexpected record type: ' + JSON.stringify(record));
- break;
- }
- }
-
- return splices;
- }
-
- function projectArraySplices(array, changeRecords) {
- var splices = [];
-
- createInitialSplices(array, changeRecords).forEach(function(splice) {
- if (splice.addedCount == 1 && splice.removed.length == 1) {
- if (splice.removed[0] !== array[splice.index])
- splices.push(splice);
-
- return
- };
-
- splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount,
- splice.removed, 0, splice.removed.length));
- });
-
- return splices;
- }
-
- global.Observer = Observer;
- global.Observer.runEOM_ = runEOM;
- global.Observer.hasObjectObserve = hasObserve;
- global.ArrayObserver = ArrayObserver;
- global.ArrayObserver.calculateSplices = function(current, previous) {
- return arraySplice.calculateSplices(current, previous);
- };
-
- global.ArraySplice = ArraySplice;
- global.ObjectObserver = ObjectObserver;
- global.PathObserver = PathObserver;
- global.CompoundObserver = CompoundObserver;
- global.Path = Path;
- global.ObserverTransform = ObserverTransform;
-})(typeof global !== 'undefined' && global && typeof module !== 'undefined' && module ? global : this || window);
-
-// prepoulate window.Platform.flags for default controls
-window.Platform = window.Platform || {};
-// prepopulate window.logFlags if necessary
-window.logFlags = window.logFlags || {};
-// process flags
-(function(scope){
- // import
- var flags = scope.flags || {};
- // populate flags from location
- location.search.slice(1).split('&').forEach(function(o) {
- o = o.split('=');
- o[0] && (flags[o[0]] = o[1] || true);
- });
- var entryPoint = document.currentScript ||
- document.querySelector('script[src*="platform.js"]');
- if (entryPoint) {
- var a = entryPoint.attributes;
- for (var i = 0, n; i < a.length; i++) {
- n = a[i];
- if (n.name !== 'src') {
- flags[n.name] = n.value || true;
- }
- }
- }
- if (flags.log) {
- flags.log.split(',').forEach(function(f) {
- window.logFlags[f] = true;
- });
- }
- // If any of these flags match 'native', then force native ShadowDOM; any
- // other truthy value, or failure to detect native
- // ShadowDOM, results in polyfill
- flags.shadow = flags.shadow || flags.shadowdom || flags.polyfill;
- if (flags.shadow === 'native') {
- flags.shadow = false;
- } else {
- flags.shadow = flags.shadow || !HTMLElement.prototype.createShadowRoot;
- }
-
- if (flags.shadow && document.querySelectorAll('script').length > 1) {
- console.warn('platform.js is not the first script on the page. ' +
- 'See http://www.polymer-project.org/docs/start/platform.html#setup ' +
- 'for details.');
- }
-
- // CustomElements polyfill flag
- if (flags.register) {
- window.CustomElements = window.CustomElements || {flags: {}};
- window.CustomElements.flags.register = flags.register;
- }
-
- if (flags.imports) {
- window.HTMLImports = window.HTMLImports || {flags: {}};
- window.HTMLImports.flags.imports = flags.imports;
- }
-
- // export
- scope.flags = flags;
-})(Platform);
-
-// select ShadowDOM impl
-if (Platform.flags.shadow) {
-
-// 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.
-
-window.ShadowDOMPolyfill = {};
-
-(function(scope) {
- 'use strict';
-
- var constructorTable = new WeakMap();
- var nativePrototypeTable = new WeakMap();
- var wrappers = Object.create(null);
-
- // Don't test for eval if document has CSP securityPolicy object and we can
- // see that eval is not supported. This avoids an error message in console
- // even when the exception is caught
- var hasEval = !('securityPolicy' in document) ||
- document.securityPolicy.allowsEval;
- if (hasEval) {
- try {
- var f = new Function('', 'return true;');
- hasEval = f();
- } catch (ex) {
- hasEval = false;
- }
- }
-
- function assert(b) {
- if (!b)
- throw new Error('Assertion failed');
- };
-
- var defineProperty = Object.defineProperty;
- var getOwnPropertyNames = Object.getOwnPropertyNames;
- var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
-
- function mixin(to, from) {
- getOwnPropertyNames(from).forEach(function(name) {
- defineProperty(to, name, getOwnPropertyDescriptor(from, name));
- });
- return to;
- };
-
- function mixinStatics(to, from) {
- getOwnPropertyNames(from).forEach(function(name) {
- switch (name) {
- case 'arguments':
- case 'caller':
- case 'length':
- case 'name':
- case 'prototype':
- case 'toString':
- return;
- }
- defineProperty(to, name, getOwnPropertyDescriptor(from, name));
- });
- return to;
- };
-
- function oneOf(object, propertyNames) {
- for (var i = 0; i < propertyNames.length; i++) {
- if (propertyNames[i] in object)
- return propertyNames[i];
- }
- }
-
- // 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.
- 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 isEventHandlerName(name) {
- return /^on[a-z]+$/.test(name);
- }
-
- function isIdentifierName(name) {
- return /^\w[a-zA-Z_0-9]*$/.test(name);
- }
-
- function getGetter(name) {
- return hasEval && isIdentifierName(name) ?
- new Function('return this.impl.' + name) :
- function() { return this.impl[name]; };
- }
-
- function getSetter(name) {
- return hasEval && isIdentifierName(name) ?
- new Function('v', 'this.impl.' + name + ' = v') :
- function(v) { this.impl[name] = v; };
- }
-
- function getMethod(name) {
- return hasEval && isIdentifierName(name) ?
- new Function('return this.impl.' + name +
- '.apply(this.impl, arguments)') :
- function() { return this.impl[name].apply(this.impl, arguments); };
- }
-
- function getDescriptor(source, name) {
- try {
- return Object.getOwnPropertyDescriptor(source, name);
- } catch (ex) {
- // JSC and V8 both use data properties instead of accessors which can
- // cause getting the property desciptor to throw an exception.
- // https://bugs.webkit.org/show_bug.cgi?id=49739
- return dummyDescriptor;
- }
- }
-
- function installProperty(source, target, allowMethod, opt_blacklist) {
- var names = getOwnPropertyNames(source);
- for (var i = 0; i < names.length; i++) {
- var name = names[i];
- if (name === 'polymerBlackList_')
- continue;
-
- if (name in target)
- continue;
-
- if (source.polymerBlackList_ && source.polymerBlackList_[name])
- continue;
-
- if (isFirefox) {
- // Tickle Firefox's old bindings.
- source.__lookupGetter__(name);
- }
- var descriptor = getDescriptor(source, name);
- var getter, setter;
- if (allowMethod && typeof descriptor.value === 'function') {
- target[name] = getMethod(name);
- continue;
- }
-
- var isEvent = isEventHandlerName(name);
- if (isEvent)
- getter = scope.getEventHandlerGetter(name);
- else
- getter = getGetter(name);
-
- if (descriptor.writable || descriptor.set) {
- if (isEvent)
- setter = scope.getEventHandlerSetter(name);
- else
- setter = getSetter(name);
- }
-
- defineProperty(target, name, {
- get: getter,
- set: setter,
- configurable: descriptor.configurable,
- enumerable: descriptor.enumerable
- });
- }
- }
-
- /**
- * @param {Function} nativeConstructor
- * @param {Function} wrapperConstructor
- * @param {Object=} opt_instance If present, this is used to extract
- * properties from an instance object.
- */
- 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);
- nativePrototypeTable.set(wrapperPrototype, nativePrototype);
-
- addForwardingProperties(nativePrototype, wrapperPrototype);
- if (opt_instance)
- registerInstanceProperties(wrapperPrototype, opt_instance);
- defineProperty(wrapperPrototype, 'constructor', {
- value: wrapperConstructor,
- configurable: true,
- enumerable: false,
- writable: true
- });
- // Set it again. Some VMs optimizes objects that are used as prototypes.
- wrapperConstructor.prototype = wrapperPrototype;
- }
-
- function isWrapperFor(wrapperConstructor, nativeConstructor) {
- return constructorTable.get(nativeConstructor.prototype) ===
- wrapperConstructor;
- }
-
- /**
- * Creates a generic wrapper constructor based on |object| and its
- * constructor.
- * @param {Node} object
- * @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);
- }
- var p = Object.create(superWrapperConstructor.prototype);
- p.constructor = GeneratedWrapper;
- GeneratedWrapper.prototype = p;
-
- return GeneratedWrapper;
- }
-
- var OriginalDOMImplementation = window.DOMImplementation;
- var OriginalEventTarget = window.EventTarget;
- var OriginalEvent = window.Event;
- var OriginalNode = window.Node;
- var OriginalWindow = window.Window;
- var OriginalRange = window.Range;
- var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D;
- var OriginalWebGLRenderingContext = window.WebGLRenderingContext;
- var OriginalSVGElementInstance = window.SVGElementInstance;
-
- function isWrapper(object) {
- return object instanceof wrappers.EventTarget ||
- object instanceof wrappers.Event ||
- object instanceof wrappers.Range ||
- object instanceof wrappers.DOMImplementation ||
- object instanceof wrappers.CanvasRenderingContext2D ||
- wrappers.WebGLRenderingContext &&
- object instanceof wrappers.WebGLRenderingContext;
- }
-
- function isNative(object) {
- return OriginalEventTarget && object instanceof OriginalEventTarget ||
- object instanceof OriginalNode ||
- object instanceof OriginalEvent ||
- object instanceof OriginalWindow ||
- object instanceof OriginalRange ||
- object instanceof OriginalDOMImplementation ||
- object instanceof OriginalCanvasRenderingContext2D ||
- OriginalWebGLRenderingContext &&
- object instanceof OriginalWebGLRenderingContext ||
- OriginalSVGElementInstance &&
- object instanceof OriginalSVGElementInstance;
- }
-
- /**
- * 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));
- return impl.polymerWrapper_ ||
- (impl.polymerWrapper_ = new (getWrapperConstructor(impl))(impl));
- }
-
- /**
- * 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));
- node.polymerWrapper_ = wrapper;
- }
-
- function defineGetter(constructor, name, getter) {
- 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 = wrapIfNeeded(this);
- return w[name].apply(w, arguments);
- };
- });
- });
- }
-
- scope.assert = assert;
- scope.constructorTable = constructorTable;
- scope.defineGetter = defineGetter;
- scope.defineWrapGetter = defineWrapGetter;
- scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
- scope.isWrapper = isWrapper;
- scope.isWrapperFor = isWrapperFor;
- scope.mixin = mixin;
- scope.nativePrototypeTable = nativePrototypeTable;
- scope.oneOf = oneOf;
- scope.registerObject = registerObject;
- scope.registerWrapper = register;
- scope.rewrap = rewrap;
- scope.unwrap = unwrap;
- scope.unwrapIfNeeded = unwrapIfNeeded;
- scope.wrap = wrap;
- scope.wrapIfNeeded = wrapIfNeeded;
- scope.wrappers = wrappers;
-
-})(window.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(context) {
- 'use strict';
-
- var OriginalMutationObserver = window.MutationObserver;
- var callbacks = [];
- var pending = false;
- var timerFunc;
-
- function handle() {
- pending = false;
- var copies = callbacks.slice(0);
- callbacks = [];
- for (var i = 0; i < copies.length; i++) {
- (0, copies[i])();
- }
- }
-
- if (OriginalMutationObserver) {
- var counter = 1;
- var observer = new OriginalMutationObserver(handle);
- var textNode = document.createTextNode(counter);
- observer.observe(textNode, {characterData: true});
-
- timerFunc = function() {
- counter = (counter + 1) % 2;
- textNode.data = counter;
- };
-
- } else {
- timerFunc = window.setImmediate || window.setTimeout;
- }
-
- function setEndOfMicrotask(func) {
- callbacks.push(func);
- if (pending)
- return;
- pending = true;
- timerFunc(handle, 0);
- }
-
- context.setEndOfMicrotask = setEndOfMicrotask;
-
-})(window.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 setEndOfMicrotask = scope.setEndOfMicrotask
- var wrapIfNeeded = scope.wrapIfNeeded
- var wrappers = scope.wrappers;
-
- var registrationsTable = new WeakMap();
- var globalMutationObservers = [];
- var isScheduled = false;
-
- function scheduleCallback(observer) {
- if (isScheduled)
- return;
- setEndOfMicrotask(notifyObservers);
- isScheduled = true;
- }
-
- // http://dom.spec.whatwg.org/#mutation-observers
- function notifyObservers() {
- isScheduled = false;
-
- do {
- var notifyList = globalMutationObservers.slice();
- var anyNonEmpty = false;
- for (var i = 0; i < notifyList.length; i++) {
- var mo = notifyList[i];
- var queue = mo.takeRecords();
- removeTransientObserversFor(mo);
- if (queue.length) {
- mo.callback_(queue, mo);
- anyNonEmpty = true;
- }
- }
- } while (anyNonEmpty);
- }
-
- /**
- * @param {string} type
- * @param {Node} target
- * @constructor
- */
- function MutationRecord(type, target) {
- this.type = type;
- this.target = target;
- this.addedNodes = new wrappers.NodeList();
- this.removedNodes = new wrappers.NodeList();
- this.previousSibling = null;
- this.nextSibling = null;
- this.attributeName = null;
- this.attributeNamespace = null;
- this.oldValue = null;
- }
-
- /**
- * Registers transient observers to ancestor and its ancesors for the node
- * which was removed.
- * @param {!Node} ancestor
- * @param {!Node} node
- */
- function registerTransientObservers(ancestor, node) {
- for (; ancestor; ancestor = ancestor.parentNode) {
- var registrations = registrationsTable.get(ancestor);
- if (!registrations)
- continue;
- for (var i = 0; i < registrations.length; i++) {
- var registration = registrations[i];
- if (registration.options.subtree)
- registration.addTransientObserver(node);
- }
- }
- }
-
- function removeTransientObserversFor(observer) {
- for (var i = 0; i < observer.nodes_.length; i++) {
- var node = observer.nodes_[i];
- var registrations = registrationsTable.get(node);
- if (!registrations)
- return;
- for (var j = 0; j < registrations.length; j++) {
- var registration = registrations[j];
- if (registration.observer === observer)
- registration.removeTransientObservers();
- }
- }
- }
-
- // http://dom.spec.whatwg.org/#queue-a-mutation-record
- function enqueueMutation(target, type, data) {
- // 1.
- var interestedObservers = Object.create(null);
- var associatedStrings = Object.create(null);
-
- // 2.
- for (var node = target; node; node = node.parentNode) {
- // 3.
- var registrations = registrationsTable.get(node);
- if (!registrations)
- continue;
- for (var j = 0; j < registrations.length; j++) {
- var registration = registrations[j];
- var options = registration.options;
- // 1.
- if (node !== target && !options.subtree)
- continue;
-
- // 2.
- if (type === 'attributes' && !options.attributes)
- continue;
-
- // 3. If type is "attributes", options's attributeFilter is present, and
- // either options's attributeFilter does not contain name or namespace
- // is non-null, continue.
- if (type === 'attributes' && options.attributeFilter &&
- (data.namespace !== null ||
- options.attributeFilter.indexOf(data.name) === -1)) {
- continue;
- }
-
- // 4.
- if (type === 'characterData' && !options.characterData)
- continue;
-
- // 5.
- if (type === 'childList' && !options.childList)
- continue;
-
- // 6.
- var observer = registration.observer;
- interestedObservers[observer.uid_] = observer;
-
- // 7. If either type is "attributes" and options's attributeOldValue is
- // true, or type is "characterData" and options's characterDataOldValue
- // is true, set the paired string of registered observer's observer in
- // interested observers to oldValue.
- if (type === 'attributes' && options.attributeOldValue ||
- type === 'characterData' && options.characterDataOldValue) {
- associatedStrings[observer.uid_] = data.oldValue;
- }
- }
- }
-
- var anyRecordsEnqueued = false;
-
- // 4.
- for (var uid in interestedObservers) {
- var observer = interestedObservers[uid];
- var record = new MutationRecord(type, target);
-
- // 2.
- if ('name' in data && 'namespace' in data) {
- record.attributeName = data.name;
- record.attributeNamespace = data.namespace;
- }
-
- // 3.
- if (data.addedNodes)
- record.addedNodes = data.addedNodes;
-
- // 4.
- if (data.removedNodes)
- record.removedNodes = data.removedNodes;
-
- // 5.
- if (data.previousSibling)
- record.previousSibling = data.previousSibling;
-
- // 6.
- if (data.nextSibling)
- record.nextSibling = data.nextSibling;
-
- // 7.
- if (associatedStrings[uid] !== undefined)
- record.oldValue = associatedStrings[uid];
-
- // 8.
- observer.records_.push(record);
-
- anyRecordsEnqueued = true;
- }
-
- if (anyRecordsEnqueued)
- scheduleCallback();
- }
-
- var slice = Array.prototype.slice;
-
- /**
- * @param {!Object} options
- * @constructor
- */
- function MutationObserverOptions(options) {
- this.childList = !!options.childList;
- this.subtree = !!options.subtree;
-
- // 1. If either options' attributeOldValue or attributeFilter is present
- // and options' attributes is omitted, set options' attributes to true.
- if (!('attributes' in options) &&
- ('attributeOldValue' in options || 'attributeFilter' in options)) {
- this.attributes = true;
- } else {
- this.attributes = !!options.attributes;
- }
-
- // 2. If options' characterDataOldValue is present and options'
- // characterData is omitted, set options' characterData to true.
- if ('characterDataOldValue' in options && !('characterData' in options))
- this.characterData = true;
- else
- this.characterData = !!options.characterData;
-
- // 3. & 4.
- if (!this.attributes &&
- (options.attributeOldValue || 'attributeFilter' in options) ||
- // 5.
- !this.characterData && options.characterDataOldValue) {
- throw new TypeError();
- }
-
- this.characterData = !!options.characterData;
- this.attributeOldValue = !!options.attributeOldValue;
- this.characterDataOldValue = !!options.characterDataOldValue;
- if ('attributeFilter' in options) {
- if (options.attributeFilter == null ||
- typeof options.attributeFilter !== 'object') {
- throw new TypeError();
- }
- this.attributeFilter = slice.call(options.attributeFilter);
- } else {
- this.attributeFilter = null;
- }
- }
-
- var uidCounter = 0;
-
- /**
- * The class that maps to the DOM MutationObserver interface.
- * @param {Function} callback.
- * @constructor
- */
- function MutationObserver(callback) {
- this.callback_ = callback;
- this.nodes_ = [];
- this.records_ = [];
- this.uid_ = ++uidCounter;
-
- // This will leak. There is no way to implement this without WeakRefs :'(
- globalMutationObservers.push(this);
- }
-
- MutationObserver.prototype = {
- // http://dom.spec.whatwg.org/#dom-mutationobserver-observe
- observe: function(target, options) {
- target = wrapIfNeeded(target);
-
- var newOptions = new MutationObserverOptions(options);
-
- // 6.
- var registration;
- var registrations = registrationsTable.get(target);
- if (!registrations)
- registrationsTable.set(target, registrations = []);
-
- for (var i = 0; i < registrations.length; i++) {
- if (registrations[i].observer === this) {
- registration = registrations[i];
- // 6.1.
- registration.removeTransientObservers();
- // 6.2.
- registration.options = newOptions;
- }
- }
-
- // 7.
- if (!registration) {
- registration = new Registration(this, target, newOptions);
- registrations.push(registration);
- this.nodes_.push(target);
- }
- },
-
- // http://dom.spec.whatwg.org/#dom-mutationobserver-disconnect
- disconnect: function() {
- this.nodes_.forEach(function(node) {
- var registrations = registrationsTable.get(node);
- for (var i = 0; i < registrations.length; i++) {
- var registration = registrations[i];
- if (registration.observer === this) {
- registrations.splice(i, 1);
- // Each node can only have one registered observer associated with
- // this observer.
- break;
- }
- }
- }, this);
- this.records_ = [];
- },
-
- takeRecords: function() {
- var copyOfRecords = this.records_;
- this.records_ = [];
- return copyOfRecords;
- }
- };
-
- /**
- * Class used to represent a registered observer.
- * @param {MutationObserver} observer
- * @param {Node} target
- * @param {MutationObserverOptions} options
- * @constructor
- */
- function Registration(observer, target, options) {
- this.observer = observer;
- this.target = target;
- this.options = options;
- this.transientObservedNodes = [];
- }
-
- Registration.prototype = {
- /**
- * Adds a transient observer on node. The transient observer gets removed
- * next time we deliver the change records.
- * @param {Node} node
- */
- addTransientObserver: function(node) {
- // Don't add transient observers on the target itself. We already have all
- // the required listeners set up on the target.
- if (node === this.target)
- return;
-
- this.transientObservedNodes.push(node);
- var registrations = registrationsTable.get(node);
- if (!registrations)
- registrationsTable.set(node, registrations = []);
-
- // We know that registrations does not contain this because we already
- // checked if node === this.target.
- registrations.push(this);
- },
-
- removeTransientObservers: function() {
- var transientObservedNodes = this.transientObservedNodes;
- this.transientObservedNodes = [];
-
- for (var i = 0; i < transientObservedNodes.length; i++) {
- var node = transientObservedNodes[i];
- var registrations = registrationsTable.get(node);
- for (var j = 0; j < registrations.length; j++) {
- if (registrations[j] === this) {
- registrations.splice(j, 1);
- // Each node can only have one registered observer associated with
- // this observer.
- break;
- }
- }
- }
- }
- };
-
- scope.enqueueMutation = enqueueMutation;
- scope.registerTransientObservers = registerTransientObservers;
- scope.wrappers.MutationObserver = MutationObserver;
- scope.wrappers.MutationRecord = MutationRecord;
-
-})(window.ShadowDOMPolyfill);
-
-/**
- * Copyright 2014 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';
-
- /**
- * A tree scope represents the root of a tree. All nodes in a tree point to
- * the same TreeScope object. The tree scope of a node get set the first time
- * it is accessed or when a node is added or remove to a tree.
- * @constructor
- */
- function TreeScope(root, parent) {
- this.root = root;
- this.parent = parent;
- }
-
- TreeScope.prototype = {
- get renderer() {
- if (this.root instanceof scope.wrappers.ShadowRoot) {
- return scope.getRendererForHost(this.root.host);
- }
- return null;
- },
-
- contains: function(treeScope) {
- for (; treeScope; treeScope = treeScope.parent) {
- if (treeScope === this)
- return true;
- }
- return false;
- }
- };
-
- function setTreeScope(node, treeScope) {
- if (node.treeScope_ !== treeScope) {
- node.treeScope_ = treeScope;
- for (var sr = node.shadowRoot; sr; sr = sr.olderShadowRoot) {
- sr.treeScope_.parent = treeScope;
- }
- for (var child = node.firstChild; child; child = child.nextSibling) {
- setTreeScope(child, treeScope);
- }
- }
- }
-
- function getTreeScope(node) {
- if (node.treeScope_)
- return node.treeScope_;
- var parent = node.parentNode;
- var treeScope;
- if (parent)
- treeScope = getTreeScope(parent);
- else
- treeScope = new TreeScope(node, null);
- return node.treeScope_ = treeScope;
- }
-
- scope.TreeScope = TreeScope;
- scope.getTreeScope = getTreeScope;
- scope.setTreeScope = setTreeScope;
-
-})(window.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 getTreeScope = scope.getTreeScope;
- var mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
- var wrappers = scope.wrappers;
-
- var wrappedFuns = new WeakMap();
- var listenersTable = new WeakMap();
- var handledEventsTable = new WeakMap();
- var currentlyDispatchingEvents = new WeakMap();
- var targetTable = new WeakMap();
- var currentTargetTable = new WeakMap();
- var relatedTargetTable = new WeakMap();
- var eventPhaseTable = new WeakMap();
- var stopPropagationTable = new WeakMap();
- var stopImmediatePropagationTable = new WeakMap();
- var eventHandlersTable = new WeakMap();
- var eventPathTable = new WeakMap();
-
- 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 getInsertionParent(node) || node.host;
-
- // 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 = getInsertionParent(context);
- 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 = target.host;
- else
- target = target.parentNode; // 3.6.
- }
- }
-
- function getInsertionParent(node) {
- return scope.insertionParentTable.get(node);
- }
-
- function isDistributed(node) {
- return getInsertionParent(node);
- }
-
- function inSameTree(a, b) {
- return getTreeScope(a) === getTreeScope(b);
- }
-
- function dispatchOriginalEvent(originalEvent) {
- // Make sure this event is only dispatched once.
- if (handledEventsTable.get(originalEvent))
- return;
- handledEventsTable.set(originalEvent, true);
- dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
- }
-
- function isLoadLikeEvent(event) {
- switch (event.type) {
- case 'beforeunload':
- case 'load':
- case 'unload':
- return true;
- }
- return false;
- }
-
- function dispatchEvent(event, originalWrapperTarget) {
- if (currentlyDispatchingEvents.get(event))
- throw new Error('InvalidStateError')
- currentlyDispatchingEvents.set(event, true);
-
- // Render to ensure that the event path is correct.
- scope.renderAllPending();
- 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 less hacky way to do this.
- if (eventPath.length === 2 &&
- eventPath[0].target instanceof wrappers.Document &&
- isLoadLikeEvent(event)) {
- eventPath.shift();
- }
-
- eventPathTable.set(event, eventPath);
-
- if (dispatchCapturing(event, eventPath)) {
- if (dispatchAtTarget(event, eventPath)) {
- dispatchBubbling(event, eventPath);
- }
- }
-
- eventPhaseTable.set(event, Event.NONE);
- currentTargetTable.delete(event, null);
- currentlyDispatchingEvents.delete(event);
-
- 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 unwrappedRelatedTarget = originalEvent.relatedTarget;
-
- // X-Tag sets relatedTarget on a CustomEvent. If they do that there is no
- // way to have relatedTarget return the adjusted target but worse is that
- // the originalEvent might not have a relatedTarget so we hit an assert
- // when we try to wrap it.
- if (unwrappedRelatedTarget) {
- // In IE we can get objects that are not EventTargets at this point.
- // Safari does not have an EventTarget interface so revert to checking
- // for addEventListener as an approximation.
- if (unwrappedRelatedTarget instanceof Object &&
- unwrappedRelatedTarget.addEventListener) {
- var relatedTarget = wrap(unwrappedRelatedTarget);
-
- var adjusted = adjustRelatedTarget(currentTarget, relatedTarget);
- if (adjusted === target)
- return true;
- } else {
- adjusted = null;
- }
- 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, ex.stack);
- }
- }
-
- 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;
- OriginalEvent.prototype.polymerBlackList_ = {
- returnValue: true,
- // TODO(arv): keyLocation is part of KeyboardEvent but Firefox does not
- // support constructable KeyboardEvent so we keep it here for now.
- keyLocation: true
- };
-
- /**
- * 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) {
- var impl = type;
- if (!OriginalBeforeUnloadEvent && impl.type === 'beforeunload')
- return new BeforeUnloadEvent(impl);
- this.impl = impl;
- } 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);
- },
- get path() {
- var nodeList = new wrappers.NodeList();
- var eventPath = eventPathTable.get(this);
- if (eventPath) {
- var index = 0;
- var lastIndex = eventPath.length - 1;
- var baseRoot = getTreeScope(currentTargetTable.get(this));
-
- for (var i = 0; i <= lastIndex; i++) {
- var currentTarget = eventPath[i].currentTarget;
- var currentRoot = getTreeScope(currentTarget);
- if (currentRoot.contains(baseRoot) &&
- // Make sure we do not add Window to the path.
- (i !== lastIndex || currentTarget instanceof wrappers.Node)) {
- nodeList[index++] = currentTarget;
- }
- }
- nodeList.length = index;
- }
- return nodeList;
- },
- 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);
- if (OriginalEvent) {
- // - Old versions of Safari fails on new FocusEvent (and others?).
- // - IE does not support event constructors.
- // - createEvent('FocusEvent') throws in Firefox.
- // => Try the best practice solution first and fallback to the old way
- // if needed.
- try {
- registerWrapper(OriginalEvent, GenericEvent, new OriginalEvent('temp'));
- } catch (ex) {
- registerWrapper(OriginalEvent, GenericEvent,
- document.createEvent(name));
- }
- }
- return GenericEvent;
- }
-
- var UIEvent = registerGenericEvent('UIEvent', Event);
- var CustomEvent = registerGenericEvent('CustomEvent', Event);
-
- var relatedTargetProto = {
- get relatedTarget() {
- var relatedTarget = relatedTargetTable.get(this);
- // relatedTarget can be null.
- if (relatedTarget !== undefined)
- return relatedTarget;
- return 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);
-
- // 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.FocusEvent('focus');
- } 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');
- }
-
- // Safari 7 does not yet have BeforeUnloadEvent.
- // https://bugs.webkit.org/show_bug.cgi?id=120849
- var OriginalBeforeUnloadEvent = window.BeforeUnloadEvent;
-
- function BeforeUnloadEvent(impl) {
- Event.call(this, impl);
- }
- BeforeUnloadEvent.prototype = Object.create(Event.prototype);
- mixin(BeforeUnloadEvent.prototype, {
- get returnValue() {
- return this.impl.returnValue;
- },
- set returnValue(v) {
- this.impl.returnValue = v;
- }
- });
-
- if (OriginalBeforeUnloadEvent)
- registerWrapper(OriginalBeforeUnloadEvent, BeforeUnloadEvent);
-
- function isValidListener(fun) {
- if (typeof fun === 'function')
- return true;
- return fun && fun.handleEvent;
- }
-
- 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;
- }
-
- 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'
- ];
-
- [Node, Window].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 = wrapper.host;
- return unwrap(wrapper);
- }
-
- EventTarget.prototype = {
- addEventListener: function(type, fun, capture) {
- if (!isValidListener(fun) || isMutationEvent(type))
- 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) {
- // We want to use the native dispatchEvent because it triggers the default
- // actions (like checking a checkbox). However, if there are no listeners
- // in the composed tree then there are no events that will trigger and
- // listeners in the non composed tree that are part of the event path are
- // not notified.
- //
- // If we find out that there are no listeners in the composed tree we add
- // a temporary listener to the target which makes us get called back even
- // in that case.
-
- var nativeEvent = unwrap(event);
- var eventType = nativeEvent.type;
-
- // Allow dispatching the same event again. This is safe because if user
- // code calls this during an existing dispatch of the same event the
- // native dispatchEvent throws (that is required by the spec).
- handledEventsTable.set(nativeEvent, false);
-
- // Force rendering since we prefer native dispatch and that works on the
- // composed tree.
- scope.renderAllPending();
-
- var tempListener;
- if (!hasListenerInAncestors(this, eventType)) {
- tempListener = function() {};
- this.addEventListener(eventType, tempListener, true);
- }
-
- try {
- return unwrap(this).dispatchEvent_(nativeEvent);
- } finally {
- if (tempListener)
- this.removeEventListener(eventType, tempListener, true);
- }
- }
- };
-
- function hasListener(node, type) {
- var listeners = listenersTable.get(node);
- if (listeners) {
- for (var i = 0; i < listeners.length; i++) {
- if (!listeners[i].removed && listeners[i].type === type)
- return true;
- }
- }
- return false;
- }
-
- function hasListenerInAncestors(target, type) {
- for (var node = unwrap(target); node; node = node.parentNode) {
- if (hasListener(wrap(node), type))
- return true;
- }
- return false;
- }
-
- 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;
- }
-
- /**
- * Returns a function that is to be used as a getter for `onfoo` properties.
- * @param {string} name
- * @return {Function}
- */
- function getEventHandlerGetter(name) {
- return function() {
- var inlineEventHandlers = eventHandlersTable.get(this);
- return inlineEventHandlers && inlineEventHandlers[name] &&
- inlineEventHandlers[name].value || null;
- };
- }
-
- /**
- * Returns a function that is to be used as a setter for `onfoo` properties.
- * @param {string} name
- * @return {Function}
- */
- function getEventHandlerSetter(name) {
- var eventType = name.slice(2);
- return function(value) {
- var inlineEventHandlers = eventHandlersTable.get(this);
- if (!inlineEventHandlers) {
- inlineEventHandlers = Object.create(null);
- eventHandlersTable.set(this, inlineEventHandlers);
- }
-
- var old = inlineEventHandlers[name];
- if (old)
- this.removeEventListener(eventType, old.wrapped, false);
-
- if (typeof value === 'function') {
- var wrapped = function(e) {
- var rv = value.call(this, e);
- if (rv === false)
- e.preventDefault();
- else if (name === 'onbeforeunload' && typeof rv === 'string')
- e.returnValue = rv;
- // mouseover uses true for preventDefault but preventDefault for
- // mouseover is ignored by browsers these day.
- };
-
- this.addEventListener(eventType, wrapped, false);
- inlineEventHandlers[name] = {
- value: value,
- wrapped: wrapped
- };
- }
- };
- }
-
- scope.adjustRelatedTarget = adjustRelatedTarget;
- scope.elementFromPoint = elementFromPoint;
- scope.getEventHandlerGetter = getEventHandlerGetter;
- scope.getEventHandlerSetter = getEventHandlerSetter;
- scope.wrapEventTargetMethods = wrapEventTargetMethods;
- scope.wrappers.BeforeUnloadEvent = BeforeUnloadEvent;
- scope.wrappers.CustomEvent = CustomEvent;
- scope.wrappers.Event = Event;
- scope.wrappers.EventTarget = EventTarget;
- scope.wrappers.FocusEvent = FocusEvent;
- scope.wrappers.MouseEvent = MouseEvent;
- scope.wrappers.UIEvent = UIEvent;
-
-})(window.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;
-
-})(window.ShadowDOMPolyfill);
-
-/*
- * Copyright 2014 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';
-
- // TODO(arv): Implement.
-
- scope.wrapHTMLCollection = scope.wrapNodeList;
- scope.wrappers.HTMLCollection = scope.wrappers.NodeList;
-
-})(window.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 TreeScope = scope.TreeScope;
- var assert = scope.assert;
- var defineWrapGetter = scope.defineWrapGetter;
- var enqueueMutation = scope.enqueueMutation;
- var getTreeScope = scope.getTreeScope;
- var isWrapper = scope.isWrapper;
- var mixin = scope.mixin;
- var registerTransientObservers = scope.registerTransientObservers;
- var registerWrapper = scope.registerWrapper;
- var setTreeScope = scope.setTreeScope;
- var unwrap = scope.unwrap;
- var unwrapIfNeeded = scope.unwrapIfNeeded;
- var wrap = scope.wrap;
- var wrapIfNeeded = scope.wrapIfNeeded;
- var wrappers = scope.wrappers;
-
- function assertIsNodeWrapper(node) {
- assert(node instanceof Node);
- }
-
- function createOneElementNodeList(node) {
- var nodes = new NodeList();
- nodes[0] = node;
- nodes.length = 1;
- return nodes;
- }
-
- var surpressMutations = false;
-
- /**
- * Called before node is inserted into a node to enqueue its removal from its
- * old parent.
- * @param {!Node} node The node that is about to be removed.
- * @param {!Node} parent The parent node that the node is being removed from.
- * @param {!NodeList} nodes The collected nodes.
- */
- function enqueueRemovalForInsertedNodes(node, parent, nodes) {
- enqueueMutation(parent, 'childList', {
- removedNodes: nodes,
- previousSibling: node.previousSibling,
- nextSibling: node.nextSibling
- });
- }
-
- function enqueueRemovalForInsertedDocumentFragment(df, nodes) {
- enqueueMutation(df, 'childList', {
- removedNodes: nodes
- });
- }
-
- /**
- * 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 instanceof DocumentFragment) {
- var nodes = collectNodesForDocumentFragment(node);
-
- // The extra loop is to work around bugs with DocumentFragments in IE.
- surpressMutations = true;
- for (var i = nodes.length - 1; i >= 0; i--) {
- node.removeChild(nodes[i]);
- nodes[i].parentNode_ = parentNode;
- }
- surpressMutations = false;
-
- 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;
- }
-
- var nodes = createOneElementNodeList(node);
- var oldParent = node.parentNode;
- if (oldParent) {
- // This will enqueue the mutation record for the removal as needed.
- oldParent.removeChild(node);
- }
-
- node.parentNode_ = parentNode;
- node.previousSibling_ = previousNode;
- node.nextSibling_ = nextNode;
- if (previousNode)
- previousNode.nextSibling_ = node;
- if (nextNode)
- nextNode.previousSibling_ = node;
-
- return nodes;
- }
-
- function collectNodesNative(node) {
- if (node instanceof DocumentFragment)
- return collectNodesForDocumentFragment(node);
-
- var nodes = createOneElementNodeList(node);
- var oldParent = node.parentNode;
- if (oldParent)
- enqueueRemovalForInsertedNodes(node, oldParent, nodes);
- return nodes;
- }
-
- function collectNodesForDocumentFragment(node) {
- var nodes = new NodeList();
- var i = 0;
- for (var child = node.firstChild; child; child = child.nextSibling) {
- nodes[i++] = child;
- }
- nodes.length = i;
- enqueueRemovalForInsertedDocumentFragment(node, nodes);
- return nodes;
- }
-
- function snapshotNodeList(nodeList) {
- // NodeLists are not live at the moment so just return the same object.
- return nodeList;
- }
-
- // http://dom.spec.whatwg.org/#node-is-inserted
- function nodeWasAdded(node, treeScope) {
- setTreeScope(node, treeScope);
- node.nodeIsInserted_();
- }
-
- function nodesWereAdded(nodes, parent) {
- var treeScope = getTreeScope(parent);
- for (var i = 0; i < nodes.length; i++) {
- nodeWasAdded(nodes[i], treeScope);
- }
- }
-
- // http://dom.spec.whatwg.org/#node-is-removed
- function nodeWasRemoved(node) {
- setTreeScope(node, new TreeScope(node, null));
- }
-
- function nodesWereRemoved(nodes) {
- for (var i = 0; i < nodes.length; i++) {
- nodeWasRemoved(nodes[i]);
- }
- }
-
- function ensureSameOwnerDocument(parent, child) {
- var ownerDoc = parent.nodeType === Node.DOCUMENT_NODE ?
- parent : parent.ownerDocument;
- if (ownerDoc !== child.ownerDocument)
- ownerDoc.adoptNode(child);
- }
-
- function adoptNodesIfNeeded(owner, nodes) {
- if (!nodes.length)
- return;
-
- var ownerDoc = owner.ownerDocument;
-
- // All nodes have the same ownerDocument when we get here.
- if (ownerDoc === nodes[0].ownerDocument)
- return;
-
- for (var i = 0; i < nodes.length; i++) {
- scope.adoptNodeNoRemove(nodes[i], ownerDoc);
- }
- }
-
- function unwrapNodesForInsertion(owner, nodes) {
- adoptNodesIfNeeded(owner, nodes);
- var length = nodes.length;
-
- if (length === 1)
- return unwrap(nodes[0]);
-
- var df = unwrap(owner.ownerDocument.createDocumentFragment());
- for (var i = 0; i < length; i++) {
- df.appendChild(unwrap(nodes[i]));
- }
- return df;
- }
-
- function clearChildNodes(wrapper) {
- if (wrapper.firstChild_ !== undefined) {
- var child = wrapper.firstChild_;
- while (child) {
- var tmp = child;
- child = child.nextSibling_;
- tmp.parentNode_ = tmp.previousSibling_ = tmp.nextSibling_ = undefined;
- }
- }
- wrapper.firstChild_ = wrapper.lastChild_ = undefined;
- }
-
- function removeAllChildNodes(wrapper) {
- if (wrapper.invalidateShadowRenderer()) {
- 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;
- } else {
- var node = unwrap(wrapper);
- var child = node.firstChild;
- var nextSibling;
- while (child) {
- nextSibling = child.nextSibling;
- originalRemoveChild.call(node, child);
- child = nextSibling;
- }
- }
- }
-
- function invalidateParent(node) {
- var p = node.parentNode;
- return p && p.invalidateShadowRenderer();
- }
-
- function cleanupNodes(nodes) {
- for (var i = 0, n; i < nodes.length; i++) {
- n = nodes[i];
- n.parentNode.removeChild(n);
- }
- }
-
- var originalImportNode = document.importNode;
- var originalCloneNode = window.Node.prototype.cloneNode;
-
- function cloneNode(node, deep, opt_doc) {
- var clone;
- if (opt_doc)
- clone = wrap(originalImportNode.call(opt_doc, node.impl, false));
- else
- clone = wrap(originalCloneNode.call(node.impl, false));
-
- if (deep) {
- for (var child = node.firstChild; child; child = child.nextSibling) {
- clone.appendChild(cloneNode(child, true, opt_doc));
- }
-
- if (node instanceof wrappers.HTMLTemplateElement) {
- var cloneContent = clone.content;
- for (var child = node.content.firstChild;
- child;
- child = child.nextSibling) {
- cloneContent.appendChild(cloneNode(child, true, opt_doc));
- }
- }
- }
- // TODO(arv): Some HTML elements also clone other data like value.
- return clone;
- }
-
- function contains(self, child) {
- if (!child || getTreeScope(self) !== getTreeScope(child))
- return false;
-
- for (var node = child; node; node = node.parentNode) {
- if (node === self)
- return true;
- }
- return false;
- }
-
- 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;
-
- this.treeScope_ = undefined;
- }
-
- var OriginalDocumentFragment = window.DocumentFragment;
- var originalAppendChild = OriginalNode.prototype.appendChild;
- var originalCompareDocumentPosition =
- OriginalNode.prototype.compareDocumentPosition;
- var originalInsertBefore = OriginalNode.prototype.insertBefore;
- var originalRemoveChild = OriginalNode.prototype.removeChild;
- var originalReplaceChild = OriginalNode.prototype.replaceChild;
-
- var isIe = /Trident/.test(navigator.userAgent);
-
- var removeChildOriginalHelper = isIe ?
- function(parent, child) {
- try {
- originalRemoveChild.call(parent, child);
- } catch (ex) {
- if (!(parent instanceof OriginalDocumentFragment))
- throw ex;
- }
- } :
- function(parent, child) {
- originalRemoveChild.call(parent, child);
- };
-
- Node.prototype = Object.create(EventTarget.prototype);
- mixin(Node.prototype, {
- appendChild: function(childWrapper) {
- return this.insertBefore(childWrapper, null);
- },
-
- insertBefore: function(childWrapper, refWrapper) {
- assertIsNodeWrapper(childWrapper);
-
- var refNode;
- if (refWrapper) {
- if (isWrapper(refWrapper)) {
- refNode = unwrap(refWrapper);
- } else {
- refNode = refWrapper;
- refWrapper = wrap(refNode);
- }
- } else {
- refWrapper = null;
- refNode = null;
- }
-
- refWrapper && assert(refWrapper.parentNode === this);
-
- var nodes;
- var previousNode =
- refWrapper ? refWrapper.previousSibling : this.lastChild;
-
- var useNative = !this.invalidateShadowRenderer() &&
- !invalidateParent(childWrapper);
-
- if (useNative)
- nodes = collectNodesNative(childWrapper);
- else
- nodes = collectNodes(childWrapper, this, previousNode, refWrapper);
-
- if (useNative) {
- ensureSameOwnerDocument(this, childWrapper);
- clearChildNodes(this);
- originalInsertBefore.call(this.impl, unwrap(childWrapper), refNode);
- } else {
- if (!previousNode)
- this.firstChild_ = nodes[0];
- if (!refWrapper)
- this.lastChild_ = nodes[nodes.length - 1];
-
- var parentNode = refNode ? refNode.parentNode : this.impl;
-
- // insertBefore refWrapper no matter what the parent is?
- if (parentNode) {
- originalInsertBefore.call(parentNode,
- unwrapNodesForInsertion(this, nodes), refNode);
- } else {
- adoptNodesIfNeeded(this, nodes);
- }
- }
-
- enqueueMutation(this, 'childList', {
- addedNodes: nodes,
- nextSibling: refWrapper,
- previousSibling: previousNode
- });
-
- nodesWereAdded(nodes, this);
-
- return childWrapper;
- },
-
- removeChild: function(childWrapper) {
- assertIsNodeWrapper(childWrapper);
- if (childWrapper.parentNode !== this) {
- // IE has invalid DOM trees at times.
- var found = false;
- var childNodes = this.childNodes;
- for (var ieChild = this.firstChild; ieChild;
- ieChild = ieChild.nextSibling) {
- if (ieChild === childWrapper) {
- found = true;
- break;
- }
- }
- if (!found) {
- // TODO(arv): DOMException
- throw new Error('NotFoundError');
- }
- }
-
- var childNode = unwrap(childWrapper);
- var childWrapperNextSibling = childWrapper.nextSibling;
- var childWrapperPreviousSibling = childWrapper.previousSibling;
-
- if (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 parentNode = childNode.parentNode;
- if (parentNode)
- removeChildOriginalHelper(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_ = undefined;
- } else {
- clearChildNodes(this);
- removeChildOriginalHelper(this.impl, childNode);
- }
-
- if (!surpressMutations) {
- enqueueMutation(this, 'childList', {
- removedNodes: createOneElementNodeList(childWrapper),
- nextSibling: childWrapperNextSibling,
- previousSibling: childWrapperPreviousSibling
- });
- }
-
- registerTransientObservers(this, childWrapper);
-
- return childWrapper;
- },
-
- replaceChild: function(newChildWrapper, oldChildWrapper) {
- assertIsNodeWrapper(newChildWrapper);
-
- var oldChildNode;
- if (isWrapper(oldChildWrapper)) {
- oldChildNode = unwrap(oldChildWrapper);
- } else {
- oldChildNode = oldChildWrapper;
- oldChildWrapper = wrap(oldChildNode);
- }
-
- if (oldChildWrapper.parentNode !== this) {
- // TODO(arv): DOMException
- throw new Error('NotFoundError');
- }
-
- var nextNode = oldChildWrapper.nextSibling;
- var previousNode = oldChildWrapper.previousSibling;
- var nodes;
-
- var useNative = !this.invalidateShadowRenderer() &&
- !invalidateParent(newChildWrapper);
-
- if (useNative) {
- nodes = collectNodesNative(newChildWrapper);
- } else {
- if (nextNode === newChildWrapper)
- nextNode = newChildWrapper.nextSibling;
- nodes = collectNodes(newChildWrapper, this, previousNode, nextNode);
- }
-
- if (!useNative) {
- if (this.firstChild === oldChildWrapper)
- this.firstChild_ = nodes[0];
- if (this.lastChild === oldChildWrapper)
- this.lastChild_ = nodes[nodes.length - 1];
-
- oldChildWrapper.previousSibling_ = oldChildWrapper.nextSibling_ =
- oldChildWrapper.parentNode_ = undefined;
-
- // replaceChild no matter what the parent is?
- if (oldChildNode.parentNode) {
- originalReplaceChild.call(
- oldChildNode.parentNode,
- unwrapNodesForInsertion(this, nodes),
- oldChildNode);
- }
- } else {
- ensureSameOwnerDocument(this, newChildWrapper);
- clearChildNodes(this);
- originalReplaceChild.call(this.impl, unwrap(newChildWrapper),
- oldChildNode);
- }
-
- enqueueMutation(this, 'childList', {
- addedNodes: nodes,
- removedNodes: createOneElementNodeList(oldChildWrapper),
- nextSibling: nextNode,
- previousSibling: previousNode
- });
-
- nodeWasRemoved(oldChildWrapper);
- nodesWereAdded(nodes, this);
-
- return oldChildWrapper;
- },
-
- /**
- * Called after a node was inserted. Subclasses override this to invalidate
- * the renderer as needed.
- * @private
- */
- nodeIsInserted_: function() {
- for (var child = this.firstChild; child; child = child.nextSibling) {
- child.nodeIsInserted_();
- }
- },
-
- 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) {
- if (child.nodeType != Node.COMMENT_NODE) {
- s += child.textContent;
- }
- }
- return s;
- },
- set textContent(textContent) {
- var removedNodes = snapshotNodeList(this.childNodes);
-
- if (this.invalidateShadowRenderer()) {
- removeAllChildNodes(this);
- if (textContent !== '') {
- var textNode = this.impl.ownerDocument.createTextNode(textContent);
- this.appendChild(textNode);
- }
- } else {
- clearChildNodes(this);
- this.impl.textContent = textContent;
- }
-
- var addedNodes = snapshotNodeList(this.childNodes);
-
- enqueueMutation(this, 'childList', {
- addedNodes: addedNodes,
- removedNodes: removedNodes
- });
-
- nodesWereRemoved(removedNodes);
- nodesWereAdded(addedNodes, this);
- },
-
- 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) {
- return cloneNode(this, deep);
- },
-
- contains: function(child) {
- return contains(this, wrapIfNeeded(child));
- },
-
- compareDocumentPosition: function(otherNode) {
- // This only wraps, it therefore only operates on the composed DOM and not
- // the logical DOM.
- return originalCompareDocumentPosition.call(this.impl,
- unwrapIfNeeded(otherNode));
- },
-
- normalize: function() {
- var nodes = snapshotNodeList(this.childNodes);
- var remNodes = [];
- var s = '';
- var modNode;
-
- for (var i = 0, n; i < nodes.length; i++) {
- n = nodes[i];
- if (n.nodeType === Node.TEXT_NODE) {
- if (!modNode && !n.data.length)
- this.removeNode(n);
- else if (!modNode)
- modNode = n;
- else {
- s += n.data;
- remNodes.push(n);
- }
- } else {
- if (modNode && remNodes.length) {
- modNode.data += s;
- cleanUpNodes(remNodes);
- }
- remNodes = [];
- s = '';
- modNode = null;
- if (n.childNodes.length)
- n.normalize();
- }
- }
-
- // handle case where >1 text nodes are the last children
- if (modNode && remNodes.length) {
- modNode.data += s;
- cleanupNodes(remNodes);
- }
- }
- });
-
- 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.cloneNode = cloneNode;
- scope.nodeWasAdded = nodeWasAdded;
- scope.nodeWasRemoved = nodeWasRemoved;
- scope.nodesWereAdded = nodesWereAdded;
- scope.nodesWereRemoved = nodesWereRemoved;
- scope.snapshotNodeList = snapshotNodeList;
- scope.wrappers.Node = Node;
-
-})(window.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;
-
-})(window.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;
- },
-
- remove: function() {
- var p = this.parentNode;
- if (p)
- p.removeChild(this);
- }
- };
-
- var ChildNodeInterface = {
- get nextElementSibling() {
- return forwardElement(this.nextSibling);
- },
-
- get previousElementSibling() {
- return backwardsElement(this.previousSibling);
- }
- };
-
- scope.ChildNodeInterface = ChildNodeInterface;
- scope.ParentNodeInterface = ParentNodeInterface;
-
-})(window.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 enqueueMutation = scope.enqueueMutation;
- 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;
- },
- get data() {
- return this.impl.data;
- },
- set data(value) {
- var oldValue = this.impl.data;
- enqueueMutation(this, 'characterData', {
- oldValue: oldValue
- });
- this.impl.data = value;
- }
- });
-
- mixin(CharacterData.prototype, ChildNodeInterface);
-
- registerWrapper(OriginalCharacterData, CharacterData,
- document.createTextNode(''));
-
- scope.wrappers.CharacterData = CharacterData;
-})(window.ShadowDOMPolyfill);
-
-// Copyright 2014 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 CharacterData = scope.wrappers.CharacterData;
- var enqueueMutation = scope.enqueueMutation;
- var mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
-
- function toUInt32(x) {
- return x >>> 0;
- }
-
- var OriginalText = window.Text;
-
- function Text(node) {
- CharacterData.call(this, node);
- }
- Text.prototype = Object.create(CharacterData.prototype);
- mixin(Text.prototype, {
- splitText: function(offset) {
- offset = toUInt32(offset);
- var s = this.data;
- if (offset > s.length)
- throw new Error('IndexSizeError');
- var head = s.slice(0, offset);
- var tail = s.slice(offset);
- this.data = head;
- var newTextNode = this.ownerDocument.createTextNode(tail);
- if (this.parentNode)
- this.parentNode.insertBefore(newTextNode, this.nextSibling);
- return newTextNode;
- }
- });
-
- registerWrapper(OriginalText, Text, document.createTextNode(''));
-
- scope.wrappers.Text = Text;
-})(window.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 enqueueMutation = scope.enqueueMutation;
- var mixin = scope.mixin;
- var oneOf = scope.oneOf;
- var registerWrapper = scope.registerWrapper;
- var wrappers = scope.wrappers;
-
- var OriginalElement = window.Element;
-
- var matchesNames = [
- 'matches', // needs to come first.
- 'mozMatchesSelector',
- 'msMatchesSelector',
- 'webkitMatchesSelector',
- ].filter(function(name) {
- return OriginalElement.prototype[name];
- });
-
- var matchesName = matchesNames[0];
-
- var originalMatches = OriginalElement.prototype[matchesName];
-
- function invalidateRendererBasedOnAttribute(element, name) {
- // Only invalidate if parent node is a shadow host.
- var p = element.parentNode;
- if (!p || !p.shadowRoot)
- return;
-
- var renderer = scope.getRendererForHost(p);
- if (renderer.dependsOnAttribute(name))
- renderer.invalidate();
- }
-
- function enqueAttributeChange(element, name, oldValue) {
- // This is not fully spec compliant. We should use localName (which might
- // have a different case than name) and the namespace (which requires us
- // to get the Attr object).
- enqueueMutation(element, 'attributes', {
- name: name,
- namespace: null,
- oldValue: oldValue
- });
- }
-
- function Element(node) {
- Node.call(this, node);
- }
- Element.prototype = Object.create(Node.prototype);
- mixin(Element.prototype, {
- createShadowRoot: function() {
- var newShadowRoot = new wrappers.ShadowRoot(this);
- this.impl.polymerShadowRoot_ = newShadowRoot;
-
- var renderer = scope.getRendererForHost(this);
- renderer.invalidate();
-
- return newShadowRoot;
- },
-
- get shadowRoot() {
- return this.impl.polymerShadowRoot_ || null;
- },
-
- setAttribute: function(name, value) {
- var oldValue = this.impl.getAttribute(name);
- this.impl.setAttribute(name, value);
- enqueAttributeChange(this, name, oldValue);
- invalidateRendererBasedOnAttribute(this, name);
- },
-
- removeAttribute: function(name) {
- var oldValue = this.impl.getAttribute(name);
- this.impl.removeAttribute(name);
- enqueAttributeChange(this, name, oldValue);
- invalidateRendererBasedOnAttribute(this, name);
- },
-
- matches: function(selector) {
- return originalMatches.call(this.impl, selector);
- }
- });
-
- matchesNames.forEach(function(name) {
- if (name !== 'matches') {
- Element.prototype[name] = function(selector) {
- return this.matches(selector);
- };
- }
- });
-
- if (OriginalElement.prototype.webkitCreateShadowRoot) {
- Element.prototype.webkitCreateShadowRoot =
- Element.prototype.createShadowRoot;
- }
-
- /**
- * Useful for generating the accessor pair for a property that reflects an
- * attribute.
- */
- function setterDirtiesAttribute(prototype, propertyName, opt_attrName) {
- var attrName = opt_attrName || propertyName;
- Object.defineProperty(prototype, propertyName, {
- get: function() {
- return this.impl[propertyName];
- },
- set: function(v) {
- this.impl[propertyName] = v;
- invalidateRendererBasedOnAttribute(this, attrName);
- },
- configurable: true,
- enumerable: true
- });
- }
-
- setterDirtiesAttribute(Element.prototype, 'id');
- setterDirtiesAttribute(Element.prototype, 'className', 'class');
-
- mixin(Element.prototype, ChildNodeInterface);
- mixin(Element.prototype, GetElementsByInterface);
- mixin(Element.prototype, ParentNodeInterface);
- mixin(Element.prototype, SelectorsInterface);
-
- registerWrapper(OriginalElement, Element,
- document.createElementNS(null, 'x'));
-
- // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings
- // that reflect attributes.
- scope.matchesNames = matchesNames;
- scope.wrappers.Element = Element;
-})(window.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 enqueueMutation = scope.enqueueMutation;
- var mixin = scope.mixin;
- var nodesWereAdded = scope.nodesWereAdded;
- var nodesWereRemoved = scope.nodesWereRemoved;
- var registerWrapper = scope.registerWrapper;
- var snapshotNodeList = scope.snapshotNodeList;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
- var wrappers = scope.wrappers;
-
- /////////////////////////////////////////////////////////////////////////////
- // innerHTML and outerHTML
-
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
- var escapeAttrRegExp = /[&\u00A0"]/g;
- var escapeDataRegExp = /[&\u00A0<>]/g;
-
- function escapeReplace(c) {
- switch (c) {
- case '&':
- return '&amp;';
- case '<':
- return '&lt;';
- case '>':
- return '&gt;';
- case '"':
- return '&quot;'
- case '\u00A0':
- return '&nbsp;';
- }
- }
-
- function escapeAttr(s) {
- return s.replace(escapeAttrRegExp, escapeReplace);
- }
-
- function escapeData(s) {
- return s.replace(escapeDataRegExp, escapeReplace);
- }
-
- function makeSet(arr) {
- var set = {};
- for (var i = 0; i < arr.length; i++) {
- set[arr[i]] = true;
- }
- return set;
- }
-
- // http://www.whatwg.org/specs/web-apps/current-work/#void-elements
- var voidElements = makeSet([
- 'area',
- 'base',
- 'br',
- 'col',
- 'command',
- 'embed',
- 'hr',
- 'img',
- 'input',
- 'keygen',
- 'link',
- 'meta',
- 'param',
- 'source',
- 'track',
- 'wbr'
- ]);
-
- var plaintextParents = makeSet([
- 'style',
- 'script',
- 'xmp',
- 'iframe',
- 'noembed',
- 'noframes',
- 'plaintext',
- 'noscript'
- ]);
-
- function getOuterHTML(node, parentNode) {
- 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 + '="' + escapeAttr(attr.value) + '"';
- }
- s += '>';
- if (voidElements[tagName])
- return s;
-
- return s + getInnerHTML(node) + '</' + tagName + '>';
-
- case Node.TEXT_NODE:
- var data = node.data;
- if (parentNode && plaintextParents[parentNode.localName])
- return data;
- return escapeData(data);
-
- case Node.COMMENT_NODE:
- return '<!--' + node.data + '-->';
-
- default:
- console.error(node);
- throw new Error('not implemented');
- }
- }
-
- function getInnerHTML(node) {
- if (node instanceof wrappers.HTMLTemplateElement)
- node = node.content;
-
- var s = '';
- for (var child = node.firstChild; child; child = child.nextSibling) {
- s += getOuterHTML(child, node);
- }
- 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));
- }
- }
-
- // IE11 does not have MSIE in the user agent string.
- var oldIe = /MSIE/.test(navigator.userAgent);
-
- var OriginalHTMLElement = window.HTMLElement;
- var OriginalHTMLTemplateElement = window.HTMLTemplateElement;
-
- function HTMLElement(node) {
- Element.call(this, node);
- }
- HTMLElement.prototype = Object.create(Element.prototype);
- mixin(HTMLElement.prototype, {
- get innerHTML() {
- return getInnerHTML(this);
- },
- set innerHTML(value) {
- // IE9 does not handle set innerHTML correctly on plaintextParents. It
- // creates element children. For example
- //
- // scriptElement.innerHTML = '<a>test</a>'
- //
- // Creates a single HTMLAnchorElement child.
- if (oldIe && plaintextParents[this.localName]) {
- this.textContent = value;
- return;
- }
-
- var removedNodes = snapshotNodeList(this.childNodes);
-
- if (this.invalidateShadowRenderer()) {
- if (this instanceof wrappers.HTMLTemplateElement)
- setInnerHTML(this.content, value);
- else
- setInnerHTML(this, value, this.tagName);
-
- // If we have a non native template element we need to handle this
- // manually since setting impl.innerHTML would add the html as direct
- // children and not be moved over to the content fragment.
- } else if (!OriginalHTMLTemplateElement &&
- this instanceof wrappers.HTMLTemplateElement) {
- setInnerHTML(this.content, value);
- } else {
- this.impl.innerHTML = value;
- }
-
- var addedNodes = snapshotNodeList(this.childNodes);
-
- enqueueMutation(this, 'childList', {
- addedNodes: addedNodes,
- removedNodes: removedNodes
- });
-
- nodesWereRemoved(removedNodes);
- nodesWereAdded(addedNodes, this);
- },
-
- get outerHTML() {
- return getOuterHTML(this, this.parentNode);
- },
- set outerHTML(value) {
- var p = this.parentNode;
- if (p) {
- p.invalidateShadowRenderer();
- var df = frag(p, value);
- p.replaceChild(df, this);
- }
- },
-
- insertAdjacentHTML: function(position, text) {
- var contextElement, refNode;
- switch (String(position).toLowerCase()) {
- case 'beforebegin':
- contextElement = this.parentNode;
- refNode = this;
- break;
- case 'afterend':
- contextElement = this.parentNode;
- refNode = this.nextSibling;
- break;
- case 'afterbegin':
- contextElement = this;
- refNode = this.firstChild;
- break;
- case 'beforeend':
- contextElement = this;
- refNode = null;
- break;
- default:
- return;
- }
-
- var df = frag(contextElement, text);
- contextElement.insertBefore(df, refNode);
- }
- });
-
- function frag(contextElement, html) {
- // TODO(arv): This does not work with SVG and other non HTML elements.
- var p = unwrap(contextElement.cloneNode(false));
- p.innerHTML = html;
- var df = unwrap(document.createDocumentFragment());
- var c;
- while (c = p.firstChild) {
- df.appendChild(c);
- }
- return wrap(df);
- }
-
- function getter(name) {
- return function() {
- scope.renderAllPending();
- return this.impl[name];
- };
- }
-
- function getterRequiresRendering(name) {
- defineGetter(HTMLElement, name, getter(name));
- }
-
- [
- 'clientHeight',
- 'clientLeft',
- 'clientTop',
- 'clientWidth',
- 'offsetHeight',
- 'offsetLeft',
- 'offsetTop',
- 'offsetWidth',
- 'scrollHeight',
- 'scrollWidth',
- ].forEach(getterRequiresRendering);
-
- function getterAndSetterRequiresRendering(name) {
- Object.defineProperty(HTMLElement.prototype, name, {
- get: getter(name),
- set: function(v) {
- scope.renderAllPending();
- this.impl[name] = v;
- },
- configurable: true,
- enumerable: true
- });
- }
-
- [
- 'scrollLeft',
- 'scrollTop',
- ].forEach(getterAndSetterRequiresRendering);
-
- 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
-})(window.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 wrap = scope.wrap;
-
- var OriginalHTMLCanvasElement = window.HTMLCanvasElement;
-
- function HTMLCanvasElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLCanvasElement.prototype = Object.create(HTMLElement.prototype);
-
- mixin(HTMLCanvasElement.prototype, {
- getContext: function() {
- var context = this.impl.getContext.apply(this.impl, arguments);
- return context && wrap(context);
- }
- });
-
- registerWrapper(OriginalHTMLCanvasElement, HTMLCanvasElement,
- document.createElement('canvas'));
-
- scope.wrappers.HTMLCanvasElement = HTMLCanvasElement;
-})(window.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;
-})(window.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 registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var rewrap = scope.rewrap;
-
- var OriginalHTMLImageElement = window.HTMLImageElement;
-
- function HTMLImageElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLImageElement.prototype = Object.create(HTMLElement.prototype);
-
- registerWrapper(OriginalHTMLImageElement, HTMLImageElement,
- document.createElement('img'));
-
- function Image(width, height) {
- if (!(this instanceof Image)) {
- throw new TypeError(
- 'DOM object constructor cannot be called as a function.');
- }
-
- var node = unwrap(document.createElement('img'));
- HTMLElement.call(this, node);
- rewrap(node, this);
-
- if (width !== undefined)
- node.width = width;
- if (height !== undefined)
- node.height = height;
- }
-
- Image.prototype = HTMLImageElement.prototype;
-
- scope.wrappers.HTMLImageElement = HTMLImageElement;
- scope.wrappers.Image = Image;
-})(window.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);
- }
- HTMLShadowElement.prototype = Object.create(HTMLElement.prototype);
- mixin(HTMLShadowElement.prototype, {
- // TODO: attribute boolean resetStyleInheritance;
- });
-
- if (OriginalHTMLShadowElement)
- registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement);
-
- scope.wrappers.HTMLShadowElement = HTMLShadowElement;
-})(window.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 unwrap = scope.unwrap;
- var wrap = scope.wrap;
-
- var contentTable = new WeakMap();
- var templateContentsOwnerTable = new WeakMap();
-
- // 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) {
- // templateElement is not a wrapper here.
- var doc = getTemplateContentsOwner(templateElement.ownerDocument);
- var df = unwrap(doc.createDocumentFragment());
- var child;
- while (child = templateElement.firstChild) {
- df.appendChild(child);
- }
- return df;
- }
-
- var OriginalHTMLTemplateElement = window.HTMLTemplateElement;
-
- function HTMLTemplateElement(node) {
- HTMLElement.call(this, node);
- if (!OriginalHTMLTemplateElement) {
- var content = extractContent(node);
- contentTable.set(this, wrap(content));
- }
- }
- HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);
-
- mixin(HTMLTemplateElement.prototype, {
- get content() {
- if (OriginalHTMLTemplateElement)
- return wrap(this.impl.content);
- return contentTable.get(this);
- },
-
- // TODO(arv): cloneNode needs to clone content.
-
- });
-
- if (OriginalHTMLTemplateElement)
- registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement);
-
- scope.wrappers.HTMLTemplateElement = HTMLTemplateElement;
-})(window.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 registerWrapper = scope.registerWrapper;
-
- var OriginalHTMLMediaElement = window.HTMLMediaElement;
-
- function HTMLMediaElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLMediaElement.prototype = Object.create(HTMLElement.prototype);
-
- registerWrapper(OriginalHTMLMediaElement, HTMLMediaElement,
- document.createElement('audio'));
-
- scope.wrappers.HTMLMediaElement = HTMLMediaElement;
-})(window.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 HTMLMediaElement = scope.wrappers.HTMLMediaElement;
- var registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var rewrap = scope.rewrap;
-
- var OriginalHTMLAudioElement = window.HTMLAudioElement;
-
- function HTMLAudioElement(node) {
- HTMLMediaElement.call(this, node);
- }
- HTMLAudioElement.prototype = Object.create(HTMLMediaElement.prototype);
-
- registerWrapper(OriginalHTMLAudioElement, HTMLAudioElement,
- document.createElement('audio'));
-
- function Audio(src) {
- if (!(this instanceof Audio)) {
- throw new TypeError(
- 'DOM object constructor cannot be called as a function.');
- }
-
- var node = unwrap(document.createElement('audio'));
- HTMLMediaElement.call(this, node);
- rewrap(node, this);
-
- node.setAttribute('preload', 'auto');
- if (src !== undefined)
- node.setAttribute('src', src);
- }
-
- Audio.prototype = HTMLAudioElement.prototype;
-
- scope.wrappers.HTMLAudioElement = HTMLAudioElement;
- scope.wrappers.Audio = Audio;
-})(window.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 rewrap = scope.rewrap;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
-
- var OriginalHTMLOptionElement = window.HTMLOptionElement;
-
- function trimText(s) {
- return s.replace(/\s+/g, ' ').trim();
- }
-
- function HTMLOptionElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLOptionElement.prototype = Object.create(HTMLElement.prototype);
- mixin(HTMLOptionElement.prototype, {
- get text() {
- return trimText(this.textContent);
- },
- set text(value) {
- this.textContent = trimText(String(value));
- },
- get form() {
- return wrap(unwrap(this).form);
- }
- });
-
- registerWrapper(OriginalHTMLOptionElement, HTMLOptionElement,
- document.createElement('option'));
-
- function Option(text, value, defaultSelected, selected) {
- if (!(this instanceof Option)) {
- throw new TypeError(
- 'DOM object constructor cannot be called as a function.');
- }
-
- var node = unwrap(document.createElement('option'));
- HTMLElement.call(this, node);
- rewrap(node, this);
-
- if (text !== undefined)
- node.text = text;
- if (value !== undefined)
- node.setAttribute('value', value);
- if (defaultSelected === true)
- node.setAttribute('selected', '');
- node.selected = selected === true;
- }
-
- Option.prototype = HTMLOptionElement.prototype;
-
- scope.wrappers.HTMLOptionElement = HTMLOptionElement;
- scope.wrappers.Option = Option;
-})(window.ShadowDOMPolyfill);
-
-// Copyright 2014 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 unwrap = scope.unwrap;
- var wrap = scope.wrap;
-
- var OriginalHTMLSelectElement = window.HTMLSelectElement;
-
- function HTMLSelectElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLSelectElement.prototype = Object.create(HTMLElement.prototype);
- mixin(HTMLSelectElement.prototype, {
- add: function(element, before) {
- if (typeof before === 'object') // also includes null
- before = unwrap(before);
- unwrap(this).add(unwrap(element), before);
- },
-
- remove: function(indexOrNode) {
- // Spec only allows index but implementations allow index or node.
- // remove() is also allowed which is same as remove(undefined)
- if (indexOrNode === undefined) {
- HTMLElement.prototype.remove.call(this);
- return;
- }
-
- if (typeof indexOrNode === 'object')
- indexOrNode = unwrap(indexOrNode);
-
- unwrap(this).remove(indexOrNode);
- },
-
- get form() {
- return wrap(unwrap(this).form);
- }
- });
-
- registerWrapper(OriginalHTMLSelectElement, HTMLSelectElement,
- document.createElement('select'));
-
- scope.wrappers.HTMLSelectElement = HTMLSelectElement;
-})(window.ShadowDOMPolyfill);
-
-/*
- * Copyright 2014 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 unwrap = scope.unwrap;
- var wrap = scope.wrap;
- var wrapHTMLCollection = scope.wrapHTMLCollection;
-
- var OriginalHTMLTableElement = window.HTMLTableElement;
-
- function HTMLTableElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLTableElement.prototype = Object.create(HTMLElement.prototype);
- mixin(HTMLTableElement.prototype, {
- get caption() {
- return wrap(unwrap(this).caption);
- },
- createCaption: function() {
- return wrap(unwrap(this).createCaption());
- },
-
- get tHead() {
- return wrap(unwrap(this).tHead);
- },
- createTHead: function() {
- return wrap(unwrap(this).createTHead());
- },
-
- createTFoot: function() {
- return wrap(unwrap(this).createTFoot());
- },
- get tFoot() {
- return wrap(unwrap(this).tFoot);
- },
-
- get tBodies() {
- return wrapHTMLCollection(unwrap(this).tBodies);
- },
- createTBody: function() {
- return wrap(unwrap(this).createTBody());
- },
-
- get rows() {
- return wrapHTMLCollection(unwrap(this).rows);
- },
- insertRow: function(index) {
- return wrap(unwrap(this).insertRow(index));
- }
- });
-
- registerWrapper(OriginalHTMLTableElement, HTMLTableElement,
- document.createElement('table'));
-
- scope.wrappers.HTMLTableElement = HTMLTableElement;
-})(window.ShadowDOMPolyfill);
-
-/*
- * Copyright 2014 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 wrapHTMLCollection = scope.wrapHTMLCollection;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
-
- var OriginalHTMLTableSectionElement = window.HTMLTableSectionElement;
-
- function HTMLTableSectionElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLTableSectionElement.prototype = Object.create(HTMLElement.prototype);
- mixin(HTMLTableSectionElement.prototype, {
- get rows() {
- return wrapHTMLCollection(unwrap(this).rows);
- },
- insertRow: function(index) {
- return wrap(unwrap(this).insertRow(index));
- }
- });
-
- registerWrapper(OriginalHTMLTableSectionElement, HTMLTableSectionElement,
- document.createElement('thead'));
-
- scope.wrappers.HTMLTableSectionElement = HTMLTableSectionElement;
-})(window.ShadowDOMPolyfill);
-
-/*
- * Copyright 2014 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 wrapHTMLCollection = scope.wrapHTMLCollection;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
-
- var OriginalHTMLTableRowElement = window.HTMLTableRowElement;
-
- function HTMLTableRowElement(node) {
- HTMLElement.call(this, node);
- }
- HTMLTableRowElement.prototype = Object.create(HTMLElement.prototype);
- mixin(HTMLTableRowElement.prototype, {
- get cells() {
- return wrapHTMLCollection(unwrap(this).cells);
- },
-
- insertCell: function(index) {
- return wrap(unwrap(this).insertCell(index));
- }
- });
-
- registerWrapper(OriginalHTMLTableRowElement, HTMLTableRowElement,
- document.createElement('tr'));
-
- scope.wrappers.HTMLTableRowElement = HTMLTableRowElement;
-})(window.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;
-})(window.ShadowDOMPolyfill);
-
-// Copyright 2014 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 registerObject = scope.registerObject;
-
- var SVG_NS = 'http://www.w3.org/2000/svg';
- var svgTitleElement = document.createElementNS(SVG_NS, 'title');
- var SVGTitleElement = registerObject(svgTitleElement);
- var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor;
-
- scope.wrappers.SVGElement = SVGElement;
-})(window.ShadowDOMPolyfill);
-
-// Copyright 2014 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 mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
-
- var OriginalSVGUseElement = window.SVGUseElement;
-
- // IE uses SVGElement as parent interface, SVG2 (Blink & Gecko) uses
- // SVGGraphicsElement. Use the <g> element to get the right prototype.
-
- var SVG_NS = 'http://www.w3.org/2000/svg';
- var gWrapper = wrap(document.createElementNS(SVG_NS, 'g'));
- var useElement = document.createElementNS(SVG_NS, 'use');
- var SVGGElement = gWrapper.constructor;
- var parentInterfacePrototype = Object.getPrototypeOf(SVGGElement.prototype);
- var parentInterface = parentInterfacePrototype.constructor;
-
- function SVGUseElement(impl) {
- parentInterface.call(this, impl);
- }
-
- SVGUseElement.prototype = Object.create(parentInterfacePrototype);
-
- // Firefox does not expose instanceRoot.
- if ('instanceRoot' in useElement) {
- mixin(SVGUseElement.prototype, {
- get instanceRoot() {
- return wrap(unwrap(this).instanceRoot);
- },
- get animatedInstanceRoot() {
- return wrap(unwrap(this).animatedInstanceRoot);
- },
- });
- }
-
- registerWrapper(OriginalSVGUseElement, SVGUseElement, useElement);
-
- scope.wrappers.SVGUseElement = SVGUseElement;
-})(window.ShadowDOMPolyfill);
-
-// Copyright 2014 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 wrap = scope.wrap;
-
- var OriginalSVGElementInstance = window.SVGElementInstance;
- if (!OriginalSVGElementInstance)
- return;
-
- function SVGElementInstance(impl) {
- EventTarget.call(this, impl);
- }
-
- SVGElementInstance.prototype = Object.create(EventTarget.prototype);
- mixin(SVGElementInstance.prototype, {
- /** @type {SVGElement} */
- get correspondingElement() {
- return wrap(this.impl.correspondingElement);
- },
-
- /** @type {SVGUseElement} */
- get correspondingUseElement() {
- return wrap(this.impl.correspondingUseElement);
- },
-
- /** @type {SVGElementInstance} */
- get parentNode() {
- return wrap(this.impl.parentNode);
- },
-
- /** @type {SVGElementInstanceList} */
- get childNodes() {
- throw new Error('Not implemented');
- },
-
- /** @type {SVGElementInstance} */
- get firstChild() {
- return wrap(this.impl.firstChild);
- },
-
- /** @type {SVGElementInstance} */
- get lastChild() {
- return wrap(this.impl.lastChild);
- },
-
- /** @type {SVGElementInstance} */
- get previousSibling() {
- return wrap(this.impl.previousSibling);
- },
-
- /** @type {SVGElementInstance} */
- get nextSibling() {
- return wrap(this.impl.nextSibling);
- }
- });
-
- registerWrapper(OriginalSVGElementInstance, SVGElementInstance);
-
- scope.wrappers.SVGElementInstance = SVGElementInstance;
-})(window.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 mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var unwrapIfNeeded = scope.unwrapIfNeeded;
- var wrap = scope.wrap;
-
- var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D;
-
- function CanvasRenderingContext2D(impl) {
- this.impl = impl;
- }
-
- mixin(CanvasRenderingContext2D.prototype, {
- get canvas() {
- return wrap(this.impl.canvas);
- },
-
- drawImage: function() {
- arguments[0] = unwrapIfNeeded(arguments[0]);
- this.impl.drawImage.apply(this.impl, arguments);
- },
-
- createPattern: function() {
- arguments[0] = unwrap(arguments[0]);
- return this.impl.createPattern.apply(this.impl, arguments);
- }
- });
-
- registerWrapper(OriginalCanvasRenderingContext2D, CanvasRenderingContext2D,
- document.createElement('canvas').getContext('2d'));
-
- scope.wrappers.CanvasRenderingContext2D = CanvasRenderingContext2D;
-})(window.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 mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
- var unwrapIfNeeded = scope.unwrapIfNeeded;
- var wrap = scope.wrap;
-
- var OriginalWebGLRenderingContext = window.WebGLRenderingContext;
-
- // IE10 does not have WebGL.
- if (!OriginalWebGLRenderingContext)
- return;
-
- function WebGLRenderingContext(impl) {
- this.impl = impl;
- }
-
- mixin(WebGLRenderingContext.prototype, {
- get canvas() {
- return wrap(this.impl.canvas);
- },
-
- texImage2D: function() {
- arguments[5] = unwrapIfNeeded(arguments[5]);
- this.impl.texImage2D.apply(this.impl, arguments);
- },
-
- texSubImage2D: function() {
- arguments[6] = unwrapIfNeeded(arguments[6]);
- this.impl.texSubImage2D.apply(this.impl, arguments);
- }
- });
-
- // Blink/WebKit has broken DOM bindings. Usually we would create an instance
- // of the object and pass it into registerWrapper as a "blueprint" but
- // creating WebGL contexts is expensive and might fail so we use a dummy
- // object with dummy instance properties for these broken browsers.
- var instanceProperties = /WebKit/.test(navigator.userAgent) ?
- {drawingBufferHeight: null, drawingBufferWidth: null} : {};
-
- registerWrapper(OriginalWebGLRenderingContext, WebGLRenderingContext,
- instanceProperties);
-
- scope.wrappers.WebGLRenderingContext = WebGLRenderingContext;
-})(window.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 registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var unwrapIfNeeded = scope.unwrapIfNeeded;
- var wrap = scope.wrap;
-
- var OriginalRange = window.Range;
-
- function Range(impl) {
- this.impl = impl;
- }
- Range.prototype = {
- get startContainer() {
- return wrap(this.impl.startContainer);
- },
- get endContainer() {
- return wrap(this.impl.endContainer);
- },
- get commonAncestorContainer() {
- return wrap(this.impl.commonAncestorContainer);
- },
- setStart: function(refNode,offset) {
- this.impl.setStart(unwrapIfNeeded(refNode), offset);
- },
- setEnd: function(refNode,offset) {
- this.impl.setEnd(unwrapIfNeeded(refNode), offset);
- },
- setStartBefore: function(refNode) {
- this.impl.setStartBefore(unwrapIfNeeded(refNode));
- },
- setStartAfter: function(refNode) {
- this.impl.setStartAfter(unwrapIfNeeded(refNode));
- },
- setEndBefore: function(refNode) {
- this.impl.setEndBefore(unwrapIfNeeded(refNode));
- },
- setEndAfter: function(refNode) {
- this.impl.setEndAfter(unwrapIfNeeded(refNode));
- },
- selectNode: function(refNode) {
- this.impl.selectNode(unwrapIfNeeded(refNode));
- },
- selectNodeContents: function(refNode) {
- this.impl.selectNodeContents(unwrapIfNeeded(refNode));
- },
- compareBoundaryPoints: function(how, sourceRange) {
- return this.impl.compareBoundaryPoints(how, unwrap(sourceRange));
- },
- extractContents: function() {
- return wrap(this.impl.extractContents());
- },
- cloneContents: function() {
- return wrap(this.impl.cloneContents());
- },
- insertNode: function(node) {
- this.impl.insertNode(unwrapIfNeeded(node));
- },
- surroundContents: function(newParent) {
- this.impl.surroundContents(unwrapIfNeeded(newParent));
- },
- cloneRange: function() {
- return wrap(this.impl.cloneRange());
- },
- isPointInRange: function(node, offset) {
- return this.impl.isPointInRange(unwrapIfNeeded(node), offset);
- },
- comparePoint: function(node, offset) {
- return this.impl.comparePoint(unwrapIfNeeded(node), offset);
- },
- intersectsNode: function(node) {
- return this.impl.intersectsNode(unwrapIfNeeded(node));
- },
- toString: function() {
- return this.impl.toString();
- }
- };
-
- // IE9 does not have createContextualFragment.
- if (OriginalRange.prototype.createContextualFragment) {
- Range.prototype.createContextualFragment = function(html) {
- return wrap(this.impl.createContextualFragment(html));
- };
- }
-
- registerWrapper(window.Range, Range, document.createRange());
-
- scope.wrappers.Range = Range;
-
-})(window.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 Comment = registerObject(document.createComment(''));
-
- scope.wrappers.Comment = Comment;
- scope.wrappers.DocumentFragment = DocumentFragment;
-
-})(window.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 TreeScope = scope.TreeScope;
- var elementFromPoint = scope.elementFromPoint;
- var getInnerHTML = scope.getInnerHTML;
- var getTreeScope = scope.getTreeScope;
- var mixin = scope.mixin;
- var rewrap = scope.rewrap;
- var setInnerHTML = scope.setInnerHTML;
- var unwrap = scope.unwrap;
-
- var shadowHostTable = new WeakMap();
- var nextOlderShadowTreeTable = new WeakMap();
-
- var spaceCharRe = /[ \t\n\r\f]/;
-
- 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);
-
- this.treeScope_ = new TreeScope(this, getTreeScope(hostWrapper));
-
- var oldShadowRoot = hostWrapper.shadowRoot;
- 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();
- },
-
- get olderShadowRoot() {
- return nextOlderShadowTreeTable.get(this) || null;
- },
-
- get host() {
- return shadowHostTable.get(this) || null;
- },
-
- invalidateShadowRenderer: function() {
- return shadowHostTable.get(this).invalidateShadowRenderer();
- },
-
- elementFromPoint: function(x, y) {
- return elementFromPoint(this, this.ownerDocument, x, y);
- },
-
- getElementById: function(id) {
- if (spaceCharRe.test(id))
- return null;
- return this.querySelector('[id="' + id + '"]');
- }
- });
-
- scope.wrappers.ShadowRoot = ShadowRoot;
-
-})(window.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 Element = scope.wrappers.Element;
- var HTMLContentElement = scope.wrappers.HTMLContentElement;
- var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
- var Node = scope.wrappers.Node;
- var ShadowRoot = scope.wrappers.ShadowRoot;
- var assert = scope.assert;
- var getTreeScope = scope.getTreeScope;
- var mixin = scope.mixin;
- var oneOf = scope.oneOf;
- 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);
- }
-
- function insertBefore(parentNodeWrapper, newChildWrapper, refChildWrapper) {
- var parentNode = unwrap(parentNodeWrapper);
- var newChild = unwrap(newChildWrapper);
- var refChild = refChildWrapper ? unwrap(refChildWrapper) : null;
-
- remove(newChildWrapper);
- updateWrapperUpAndSideways(newChildWrapper);
-
- if (!refChildWrapper) {
- parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild;
- if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild)
- parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild;
-
- var lastChildWrapper = wrap(parentNode.lastChild);
- if (lastChildWrapper)
- lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling;
- } else {
- if (parentNodeWrapper.firstChild === refChildWrapper)
- parentNodeWrapper.firstChild_ = refChildWrapper;
-
- refChildWrapper.previousSibling_ = refChildWrapper.previousSibling;
- }
-
- parentNode.insertBefore(newChild, refChild);
- }
-
- function remove(nodeWrapper) {
- var node = unwrap(nodeWrapper)
- var parentNode = node.parentNode;
- if (!parentNode)
- return;
-
- var parentNodeWrapper = wrap(parentNode);
- updateWrapperUpAndSideways(nodeWrapper);
-
- if (nodeWrapper.previousSibling)
- nodeWrapper.previousSibling.nextSibling_ = nodeWrapper;
- if (nodeWrapper.nextSibling)
- nodeWrapper.nextSibling.previousSibling_ = nodeWrapper;
-
- if (parentNodeWrapper.lastChild === nodeWrapper)
- parentNodeWrapper.lastChild_ = nodeWrapper;
- if (parentNodeWrapper.firstChild === nodeWrapper)
- parentNodeWrapper.firstChild_ = nodeWrapper;
-
- parentNode.removeChild(node);
- }
-
- var distributedChildNodesTable = new WeakMap();
- var eventParentsTable = new WeakMap();
- var insertionParentTable = new WeakMap();
- var rendererForHostTable = new WeakMap();
-
- function distributeChildToInsertionPoint(child, insertionPoint) {
- getDistributedChildNodes(insertionPoint).push(child);
- assignToInsertionPoint(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) {
- var rv = distributedChildNodesTable.get(insertionPoint);
- if (!rv)
- distributedChildNodesTable.set(insertionPoint, rv = []);
- return rv;
- }
-
- 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.
- for (var node = tree.firstChild; node; node = node.nextSibling) {
- if (predicate(node)) {
- if (visitor(node) === false)
- return;
- } else {
- visit(node, predicate, visitor);
- }
- }
- }
-
- // 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('|') + ')');
-
-
- /**
- * @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 instanceof Element))
- return false;
-
- // The native matches function in IE9 does not correctly work with elements
- // that are not in the document.
- // TODO(arv): Implement matching in JS.
- // https://github.com/Polymer/ShadowDOM/issues/361
- if (select === '*' || select === node.localName)
- return true;
-
- // TODO(arv): This does not seem right. Need to check for a simple selector.
- if (!selectorMatchRegExp.test(select))
- return false;
-
- // TODO(arv): This no longer matches the spec.
- 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() {
- // TODO(arv): Order these in document order. That way we do not have to
- // render something twice.
- for (var i = 0; i < pendingDirtyRenderers.length; i++) {
- var renderer = pendingDirtyRenderers[i];
- var parentRenderer = renderer.parentRenderer;
- if (parentRenderer && parentRenderer.dirty)
- continue;
- renderer.render();
- }
-
- pendingDirtyRenderers = [];
- }
-
- function handleRequestAnimationFrame() {
- renderTimer = null;
- renderAllPending();
- }
-
- /**
- * Returns existing shadow renderer for a host or creates it if it is needed.
- * @params {!Element} host
- * @return {!ShadowRenderer}
- */
- function getRendererForHost(host) {
- var renderer = rendererForHostTable.get(host);
- if (!renderer) {
- renderer = new ShadowRenderer(host);
- rendererForHostTable.set(host, renderer);
- }
- return renderer;
- }
-
- function getShadowRootAncestor(node) {
- var root = getTreeScope(node).root;
- if (root instanceof ShadowRoot)
- return root;
- return null;
- }
-
- function getRendererForShadowRoot(shadowRoot) {
- return getRendererForHost(shadowRoot.host);
- }
-
- var spliceDiff = new ArraySplice();
- spliceDiff.equals = function(renderNode, rawNode) {
- return unwrap(renderNode.node) === rawNode;
- };
-
- /**
- * RenderNode is used as an in memory "render tree". When we render the
- * composed tree we create a tree of RenderNodes, then we diff this against
- * the real DOM tree and make minimal changes as needed.
- */
- function RenderNode(node) {
- this.skip = false;
- this.node = node;
- this.childNodes = [];
- }
-
- RenderNode.prototype = {
- append: function(node) {
- var rv = new RenderNode(node);
- this.childNodes.push(rv);
- return rv;
- },
-
- sync: function(opt_added) {
- if (this.skip)
- return;
-
- var nodeWrapper = this.node;
- // plain array of RenderNodes
- var newChildren = this.childNodes;
- // plain array of real nodes.
- var oldChildren = getChildNodesSnapshot(unwrap(nodeWrapper));
- var added = opt_added || new WeakMap();
-
- var splices = spliceDiff.calculateSplices(newChildren, oldChildren);
-
- var newIndex = 0, oldIndex = 0;
- var lastIndex = 0;
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- for (; lastIndex < splice.index; lastIndex++) {
- oldIndex++;
- newChildren[newIndex++].sync(added);
- }
-
- var removedCount = splice.removed.length;
- for (var j = 0; j < removedCount; j++) {
- var wrapper = wrap(oldChildren[oldIndex++]);
- if (!added.get(wrapper))
- remove(wrapper);
- }
-
- var addedCount = splice.addedCount;
- var refNode = oldChildren[oldIndex] && wrap(oldChildren[oldIndex]);
- for (var j = 0; j < addedCount; j++) {
- var newChildRenderNode = newChildren[newIndex++];
- var newChildWrapper = newChildRenderNode.node;
- insertBefore(nodeWrapper, newChildWrapper, refNode);
-
- // Keep track of added so that we do not remove the node after it
- // has been added.
- added.set(newChildWrapper, true);
-
- newChildRenderNode.sync(added);
- }
-
- lastIndex += addedCount;
- }
-
- for (var i = lastIndex; i < newChildren.length; i++) {
- newChildren[i].sync(added);
- }
- }
- };
-
- function ShadowRenderer(host) {
- this.host = host;
- this.dirty = false;
- this.invalidateAttributes();
- this.associateNode(host);
- }
-
- ShadowRenderer.prototype = {
-
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#rendering-shadow-trees
- render: function(opt_renderNode) {
- if (!this.dirty)
- return;
-
- this.invalidateAttributes();
- this.treeComposition();
-
- var host = this.host;
- var shadowRoot = host.shadowRoot;
-
- this.associateNode(host);
- var topMostRenderer = !renderNode;
- var renderNode = opt_renderNode || new RenderNode(host);
-
- for (var node = shadowRoot.firstChild; node; node = node.nextSibling) {
- this.renderNode(shadowRoot, renderNode, node, false);
- }
-
- if (topMostRenderer)
- renderNode.sync();
-
- this.dirty = false;
- },
-
- get parentRenderer() {
- return getTreeScope(this.host).renderer;
- },
-
- invalidate: function() {
- if (!this.dirty) {
- this.dirty = true;
- pendingDirtyRenderers.push(this);
- if (renderTimer)
- return;
- renderTimer = window[request](handleRequestAnimationFrame, 0);
- }
- },
-
- renderNode: function(shadowRoot, renderNode, node, isNested) {
- if (isShadowHost(node)) {
- renderNode = renderNode.append(node);
- var renderer = getRendererForHost(node);
- renderer.dirty = true; // Need to rerender due to reprojection.
- renderer.render(renderNode);
- } else if (isInsertionPoint(node)) {
- this.renderInsertionPoint(shadowRoot, renderNode, node, isNested);
- } else if (isShadowInsertionPoint(node)) {
- this.renderShadowInsertionPoint(shadowRoot, renderNode, node);
- } else {
- this.renderAsAnyDomTree(shadowRoot, renderNode, node, isNested);
- }
- },
-
- renderAsAnyDomTree: function(shadowRoot, renderNode, node, isNested) {
- renderNode = renderNode.append(node);
-
- if (isShadowHost(node)) {
- var renderer = getRendererForHost(node);
- renderNode.skip = !renderer.dirty;
- renderer.render(renderNode);
- } else {
- for (var child = node.firstChild; child; child = child.nextSibling) {
- this.renderNode(shadowRoot, renderNode, child, isNested);
- }
- }
- },
-
- renderInsertionPoint: function(shadowRoot, renderNode, insertionPoint,
- isNested) {
- var distributedChildNodes = getDistributedChildNodes(insertionPoint);
- if (distributedChildNodes.length) {
- this.associateNode(insertionPoint);
-
- for (var i = 0; i < distributedChildNodes.length; i++) {
- var child = distributedChildNodes[i];
- if (isInsertionPoint(child) && isNested)
- this.renderInsertionPoint(shadowRoot, renderNode, child, isNested);
- else
- this.renderAsAnyDomTree(shadowRoot, renderNode, child, isNested);
- }
- } else {
- this.renderFallbackContent(shadowRoot, renderNode, insertionPoint);
- }
- this.associateNode(insertionPoint.parentNode);
- },
-
- renderShadowInsertionPoint: function(shadowRoot, renderNode,
- shadowInsertionPoint) {
- var nextOlderTree = shadowRoot.olderShadowRoot;
- if (nextOlderTree) {
- assignToInsertionPoint(nextOlderTree, shadowInsertionPoint);
- this.associateNode(shadowInsertionPoint.parentNode);
- for (var node = nextOlderTree.firstChild;
- node;
- node = node.nextSibling) {
- this.renderNode(nextOlderTree, renderNode, node, true);
- }
- } else {
- this.renderFallbackContent(shadowRoot, renderNode,
- shadowInsertionPoint);
- }
- },
-
- renderFallbackContent: function(shadowRoot, renderNode, fallbackHost) {
- this.associateNode(fallbackHost);
- this.associateNode(fallbackHost.parentNode);
- for (var node = fallbackHost.firstChild; node; node = node.nextSibling) {
- this.renderAsAnyDomTree(shadowRoot, renderNode, node, false);
- }
- },
-
- /**
- * Invalidates the attributes used to keep track of which attributes may
- * cause the renderer to be invalidated.
- */
- invalidateAttributes: function() {
- this.attributes = Object.create(null);
- },
-
- /**
- * Parses the selector and makes this renderer dependent on the attribute
- * being used in the selector.
- * @param {string} selector
- */
- updateDependentAttributes: function(selector) {
- if (!selector)
- return;
-
- var attributes = this.attributes;
-
- // .class
- if (/\.\w+/.test(selector))
- attributes['class'] = true;
-
- // #id
- if (/#\w+/.test(selector))
- attributes['id'] = true;
-
- selector.replace(/\[\s*([^\s=\|~\]]+)/g, function(_, name) {
- attributes[name] = true;
- });
-
- // Pseudo selectors have been removed from the spec.
- },
-
- dependsOnAttribute: function(name) {
- return this.attributes[name];
- },
-
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn-distribution-algorithm
- distribute: function(tree, pool) {
- var self = this;
-
- visit(tree, isActiveInsertionPoint,
- function(insertionPoint) {
- resetDistributedChildNodes(insertionPoint);
- self.updateDependentAttributes(
- insertionPoint.getAttribute('select'));
-
- 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
- }
- }
- });
- },
-
- // 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.
-
- for (var child = shadowHost.firstChild;
- child;
- child = child.nextSibling) { // 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;
-
- this.distribute(tree, pool); // 4.2.
- if (point) { // 4.3.
- var nextOlderTree = tree.olderShadowRoot; // 4.3.1.
- if (!nextOlderTree) {
- break; // 4.3.1.1.
- } else {
- tree = nextOlderTree; // 4.3.2.2.
- assignToInsertionPoint(tree, point); // 4.3.2.2.
- continue; // 4.3.2.3.
- }
- } else {
- break; // 4.4.
- }
- }
- },
-
- associateNode: function(node) {
- node.impl.polymerShadowRenderer_ = this;
- }
- };
-
- function isInsertionPoint(node) {
- // Should this include <shadow>?
- return node instanceof HTMLContentElement;
- }
-
- function isActiveInsertionPoint(node) {
- // <content> inside another <content> or <shadow> is considered inactive.
- return node instanceof HTMLContentElement;
- }
-
- function isShadowInsertionPoint(node) {
- return node instanceof HTMLShadowElement;
- }
-
- function isActiveShadowInsertionPoint(node) {
- // <shadow> inside another <content> or <shadow> is considered inactive.
- return node instanceof HTMLShadowElement;
- }
-
- function isShadowHost(shadowHost) {
- return shadowHost.shadowRoot;
- }
-
- function getShadowTrees(host) {
- var trees = [];
-
- for (var tree = host.shadowRoot; tree; tree = tree.olderShadowRoot) {
- trees.push(tree);
- }
- return trees;
- }
-
- function assignToInsertionPoint(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();
- };
-
- // Need to rerender shadow host when:
- //
- // - a direct child to the ShadowRoot is added or removed
- // - a direct child to the host is added or removed
- // - a new shadow root is created
- // - a direct child to a content/shadow element is added or removed
- // - a sibling to a content/shadow element is added or removed
- // - content[select] is changed
- // - an attribute in a direct child to a host is modified
-
- /**
- * This gets called when a node was added or removed to it.
- */
- Node.prototype.invalidateShadowRenderer = function(force) {
- var renderer = this.impl.polymerShadowRenderer_;
- if (renderer) {
- renderer.invalidate();
- return true;
- }
-
- return false;
- };
-
- HTMLContentElement.prototype.getDistributedNodes = function() {
- // TODO(arv): We should only rerender the dirty ancestor renderers (from
- // the root and down).
- renderAllPending();
- return getDistributedChildNodes(this);
- };
-
- HTMLShadowElement.prototype.nodeIsInserted_ =
- HTMLContentElement.prototype.nodeIsInserted_ = function() {
- // Invalidate old renderer if any.
- this.invalidateShadowRenderer();
-
- var shadowRoot = getShadowRootAncestor(this);
- var renderer;
- if (shadowRoot)
- renderer = getRendererForShadowRoot(shadowRoot);
- this.impl.polymerShadowRenderer_ = renderer;
- if (renderer)
- renderer.invalidate();
- };
-
- scope.eventParentsTable = eventParentsTable;
- scope.getRendererForHost = getRendererForHost;
- scope.getShadowTrees = getShadowTrees;
- scope.insertionParentTable = insertionParentTable;
- scope.renderAllPending = renderAllPending;
-
- // Exposed for testing
- scope.visual = {
- insertBefore: insertBefore,
- remove: remove,
- };
-
-})(window.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 assert = scope.assert;
- var mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
-
- var elementsWithFormProperty = [
- 'HTMLButtonElement',
- 'HTMLFieldSetElement',
- 'HTMLInputElement',
- 'HTMLKeygenElement',
- 'HTMLLabelElement',
- 'HTMLLegendElement',
- 'HTMLObjectElement',
- // HTMLOptionElement is handled in HTMLOptionElement.js
- 'HTMLOutputElement',
- // HTMLSelectElement is handled in HTMLSelectElement.js
- 'HTMLTextAreaElement',
- ];
-
- function createWrapperConstructor(name) {
- if (!window[name])
- return;
-
- // Ensure we are not overriding an already existing constructor.
- assert(!scope.wrappers[name]);
-
- var GeneratedWrapper = function(node) {
- // At this point all of them extend HTMLElement.
- HTMLElement.call(this, node);
- }
- GeneratedWrapper.prototype = Object.create(HTMLElement.prototype);
- mixin(GeneratedWrapper.prototype, {
- get form() {
- return wrap(unwrap(this).form);
- },
- });
-
- registerWrapper(window[name], GeneratedWrapper,
- document.createElement(name.slice(4, -7)));
- scope.wrappers[name] = GeneratedWrapper;
- }
-
- elementsWithFormProperty.forEach(createWrapperConstructor);
-
-})(window.ShadowDOMPolyfill);
-
-// Copyright 2014 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 registerWrapper = scope.registerWrapper;
- var unwrap = scope.unwrap;
- var unwrapIfNeeded = scope.unwrapIfNeeded;
- var wrap = scope.wrap;
-
- var OriginalSelection = window.Selection;
-
- function Selection(impl) {
- this.impl = impl;
- }
- Selection.prototype = {
- get anchorNode() {
- return wrap(this.impl.anchorNode);
- },
- get focusNode() {
- return wrap(this.impl.focusNode);
- },
- addRange: function(range) {
- this.impl.addRange(unwrap(range));
- },
- collapse: function(node, index) {
- this.impl.collapse(unwrapIfNeeded(node), index);
- },
- containsNode: function(node, allowPartial) {
- return this.impl.containsNode(unwrapIfNeeded(node), allowPartial);
- },
- extend: function(node, offset) {
- this.impl.extend(unwrapIfNeeded(node), offset);
- },
- getRangeAt: function(index) {
- return wrap(this.impl.getRangeAt(index));
- },
- removeRange: function(range) {
- this.impl.removeRange(unwrap(range));
- },
- selectAllChildren: function(node) {
- this.impl.selectAllChildren(unwrapIfNeeded(node));
- },
- toString: function() {
- return this.impl.toString();
- }
- };
-
- // WebKit extensions. Not implemented.
- // readonly attribute Node baseNode;
- // readonly attribute long baseOffset;
- // readonly attribute Node extentNode;
- // readonly attribute long extentOffset;
- // [RaisesException] void setBaseAndExtent([Default=Undefined] optional Node baseNode,
- // [Default=Undefined] optional long baseOffset,
- // [Default=Undefined] optional Node extentNode,
- // [Default=Undefined] optional long extentOffset);
- // [RaisesException, ImplementedAs=collapse] void setPosition([Default=Undefined] optional Node node,
- // [Default=Undefined] optional long offset);
-
- registerWrapper(window.Selection, Selection, window.getSelection());
-
- scope.wrappers.Selection = Selection;
-
-})(window.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 Selection = scope.wrappers.Selection;
- var SelectorsInterface = scope.SelectorsInterface;
- var ShadowRoot = scope.wrappers.ShadowRoot;
- var TreeScope = scope.TreeScope;
- var cloneNode = scope.cloneNode;
- var defineWrapGetter = scope.defineWrapGetter;
- var elementFromPoint = scope.elementFromPoint;
- var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
- var matchesNames = scope.matchesNames;
- var mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
- var renderAllPending = scope.renderAllPending;
- var rewrap = scope.rewrap;
- var unwrap = scope.unwrap;
- var wrap = scope.wrap;
- var wrapEventTargetMethods = scope.wrapEventTargetMethods;
- var wrapNodeList = scope.wrapNodeList;
-
- var implementationTable = new WeakMap();
-
- function Document(node) {
- Node.call(this, node);
- this.treeScope_ = new TreeScope(this, null);
- }
- 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));
- };
- }
-
- [
- 'createComment',
- 'createDocumentFragment',
- 'createElement',
- 'createElementNS',
- 'createEvent',
- 'createEventNS',
- 'createRange',
- 'createTextNode',
- 'getElementById'
- ].forEach(wrapMethod);
-
- var originalAdoptNode = document.adoptNode;
-
- function adoptNodeNoRemove(node, doc) {
- originalAdoptNode.call(doc.impl, unwrap(node));
- adoptSubtree(node, doc);
- }
-
- function adoptSubtree(node, doc) {
- if (node.shadowRoot)
- doc.adoptNode(node.shadowRoot);
- if (node instanceof ShadowRoot)
- adoptOlderShadowRoots(node, doc);
- for (var child = node.firstChild; child; child = child.nextSibling) {
- adoptSubtree(child, doc);
- }
- }
-
- function adoptOlderShadowRoots(shadowRoot, doc) {
- var oldShadowRoot = shadowRoot.olderShadowRoot;
- if (oldShadowRoot)
- doc.adoptNode(oldShadowRoot);
- }
-
- var originalGetSelection = document.getSelection;
-
- mixin(Document.prototype, {
- adoptNode: function(node) {
- if (node.parentNode)
- node.parentNode.removeChild(node);
- adoptNodeNoRemove(node, this);
- return node;
- },
- elementFromPoint: function(x, y) {
- return elementFromPoint(this, this, x, y);
- },
- importNode: function(node, deep) {
- return cloneNode(node, deep, this.impl);
- },
- getSelection: function() {
- renderAllPending();
- return new Selection(originalGetSelection.call(unwrap(this)));
- }
- });
-
- if (document.registerElement) {
- var originalRegisterElement = document.registerElement;
- Document.prototype.registerElement = function(tagName, object) {
- var prototype, extendsOption;
- if (object !== undefined) {
- prototype = object.prototype;
- extendsOption = object.extends;
- }
-
- if (!prototype)
- prototype = Object.create(HTMLElement.prototype);
-
-
- // If we already used the object as a prototype for another custom
- // element.
- if (scope.nativePrototypeTable.get(prototype)) {
- // TODO(arv): DOMException
- throw new Error('NotSupportedError');
- }
-
- // Find first object on the prototype chain that already have a native
- // prototype. Keep track of all the objects before that so we can create
- // a similar structure for the native case.
- var proto = Object.getPrototypeOf(prototype);
- var nativePrototype;
- var prototypes = [];
- while (proto) {
- nativePrototype = scope.nativePrototypeTable.get(proto);
- if (nativePrototype)
- break;
- prototypes.push(proto);
- proto = Object.getPrototypeOf(proto);
- }
-
- if (!nativePrototype) {
- // TODO(arv): DOMException
- throw new Error('NotSupportedError');
- }
-
- // This works by creating a new prototype object that is empty, but has
- // the native prototype as its proto. The original prototype object
- // passed into register is used as the wrapper prototype.
-
- var newPrototype = Object.create(nativePrototype);
- for (var i = prototypes.length - 1; i >= 0; i--) {
- newPrototype = Object.create(newPrototype);
- }
-
- // Add callbacks if present.
- // Names are taken from:
- // https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/bindings/v8/CustomElementConstructorBuilder.cpp&sq=package:chromium&type=cs&l=156
- // and not from the spec since the spec is out of date.
- [
- 'createdCallback',
- 'attachedCallback',
- 'detachedCallback',
- 'attributeChangedCallback',
- ].forEach(function(name) {
- var f = prototype[name];
- if (!f)
- return;
- newPrototype[name] = function() {
- // if this element has been wrapped prior to registration,
- // the wrapper is stale; in this case rewrap
- if (!(wrap(this) instanceof CustomElementConstructor)) {
- rewrap(this);
- }
- f.apply(wrap(this), arguments);
- };
- });
-
- var p = {prototype: newPrototype};
- if (extendsOption)
- p.extends = extendsOption;
-
- function CustomElementConstructor(node) {
- if (!node) {
- if (extendsOption) {
- return document.createElement(extendsOption, tagName);
- } else {
- return document.createElement(tagName);
- }
- }
- this.impl = node;
- }
- CustomElementConstructor.prototype = prototype;
- CustomElementConstructor.prototype.constructor = CustomElementConstructor;
-
- scope.constructorTable.set(newPrototype, CustomElementConstructor);
- scope.nativePrototypeTable.set(prototype, newPrototype);
-
- // registration is synchronous so do it last
- var nativeConstructor = originalRegisterElement.call(unwrap(this),
- tagName, p);
- return CustomElementConstructor;
- };
-
- forwardMethodsToWrapper([
- window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
- ], [
- 'registerElement',
- ]);
- }
-
- // 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,
- window.HTMLHtmlElement,
- ], [
- 'appendChild',
- 'compareDocumentPosition',
- 'contains',
- 'getElementsByClassName',
- 'getElementsByTagName',
- 'getElementsByTagNameNS',
- 'insertBefore',
- 'querySelector',
- 'querySelectorAll',
- 'removeChild',
- 'replaceChild',
- ].concat(matchesNames));
-
- forwardMethodsToWrapper([
- window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
- ], [
- 'adoptNode',
- 'importNode',
- 'contains',
- 'createComment',
- 'createDocumentFragment',
- 'createElement',
- 'createElementNS',
- 'createEvent',
- 'createEventNS',
- 'createRange',
- 'createTextNode',
- 'elementFromPoint',
- 'getElementById',
- 'getSelection',
- ]);
-
- 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.adoptNodeNoRemove = adoptNodeNoRemove;
- scope.wrappers.DOMImplementation = DOMImplementation;
- scope.wrappers.Document = Document;
-
-})(window.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 Selection = scope.wrappers.Selection;
- var mixin = scope.mixin;
- var registerWrapper = scope.registerWrapper;
- var renderAllPending = scope.renderAllPending;
- var unwrap = scope.unwrap;
- var unwrapIfNeeded = scope.unwrapIfNeeded;
- var wrap = scope.wrap;
-
- var OriginalWindow = window.Window;
- var originalGetComputedStyle = window.getComputedStyle;
- var originalGetSelection = window.getSelection;
-
- function Window(impl) {
- EventTarget.call(this, impl);
- }
- Window.prototype = Object.create(EventTarget.prototype);
-
- OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {
- return wrap(this || window).getComputedStyle(unwrapIfNeeded(el), pseudo);
- };
-
- OriginalWindow.prototype.getSelection = function() {
- return wrap(this || window).getSelection();
- };
-
- // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
- delete window.getComputedStyle;
- delete window.getSelection;
-
- ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(
- function(name) {
- OriginalWindow.prototype[name] = function() {
- var w = wrap(this || window);
- return w[name].apply(w, arguments);
- };
-
- // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
- delete window[name];
- });
-
- mixin(Window.prototype, {
- getComputedStyle: function(el, pseudo) {
- renderAllPending();
- return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el),
- pseudo);
- },
- getSelection: function() {
- renderAllPending();
- return new Selection(originalGetSelection.call(unwrap(this)));
- },
- });
-
- registerWrapper(OriginalWindow, Window);
-
- scope.wrappers.Window = Window;
-
-})(window.ShadowDOMPolyfill);
-
-/**
- * Copyright 2014 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 unwrap = scope.unwrap;
-
- // DataTransfer (Clipboard in old Blink/WebKit) has a single method that
- // requires wrapping. Since it is only a method we do not need a real wrapper,
- // we can just override the method.
-
- var OriginalDataTransfer = window.DataTransfer || window.Clipboard;
- var OriginalDataTransferSetDragImage =
- OriginalDataTransfer.prototype.setDragImage;
-
- OriginalDataTransfer.prototype.setDragImage = function(image, x, y) {
- OriginalDataTransferSetDragImage.call(this, unwrap(image), x, y);
- };
-
-})(window.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',
- // Do not create an applet element by default since it shows a warning in
- // IE.
- // https://github.com/Polymer/polymer/issues/217
- // 'applet': 'HTMLAppletElement',
- 'area': 'HTMLAreaElement',
- 'audio': 'HTMLAudioElement',
- 'base': 'HTMLBaseElement',
- 'body': 'HTMLBodyElement',
- 'br': 'HTMLBRElement',
- 'button': 'HTMLButtonElement',
- 'canvas': 'HTMLCanvasElement',
- 'caption': 'HTMLTableCaptionElement',
- 'col': 'HTMLTableColElement',
- // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko.
- 'content': 'HTMLContentElement',
- 'data': 'HTMLDataElement',
- 'datalist': 'HTMLDataListElement',
- 'del': 'HTMLModElement',
- 'dir': 'HTMLDirectoryElement',
- 'div': 'HTMLDivElement',
- 'dl': 'HTMLDListElement',
- 'embed': 'HTMLEmbedElement',
- 'fieldset': 'HTMLFieldSetElement',
- 'font': 'HTMLFontElement',
- 'form': 'HTMLFormElement',
- 'frame': 'HTMLFrameElement',
- 'frameset': 'HTMLFrameSetElement',
- 'h1': 'HTMLHeadingElement',
- 'head': 'HTMLHeadElement',
- 'hr': 'HTMLHRElement',
- 'html': 'HTMLHtmlElement',
- 'iframe': 'HTMLIFrameElement',
- 'img': 'HTMLImageElement',
- 'input': 'HTMLInputElement',
- 'keygen': 'HTMLKeygenElement',
- 'label': 'HTMLLabelElement',
- 'legend': 'HTMLLegendElement',
- 'li': 'HTMLLIElement',
- 'link': 'HTMLLinkElement',
- 'map': 'HTMLMapElement',
- 'marquee': 'HTMLMarqueeElement',
- 'menu': 'HTMLMenuElement',
- 'menuitem': 'HTMLMenuItemElement',
- 'meta': 'HTMLMetaElement',
- 'meter': 'HTMLMeterElement',
- 'object': 'HTMLObjectElement',
- 'ol': 'HTMLOListElement',
- 'optgroup': 'HTMLOptGroupElement',
- 'option': 'HTMLOptionElement',
- 'output': 'HTMLOutputElement',
- 'p': 'HTMLParagraphElement',
- 'param': 'HTMLParamElement',
- 'pre': 'HTMLPreElement',
- 'progress': 'HTMLProgressElement',
- 'q': 'HTMLQuoteElement',
- 'script': 'HTMLScriptElement',
- 'select': 'HTMLSelectElement',
- 'shadow': 'HTMLShadowElement',
- 'source': 'HTMLSourceElement',
- 'span': 'HTMLSpanElement',
- 'style': 'HTMLStyleElement',
- 'table': 'HTMLTableElement',
- 'tbody': 'HTMLTableSectionElement',
- // 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',
- 'template': 'HTMLTemplateElement',
- 'textarea': 'HTMLTextAreaElement',
- 'thead': 'HTMLTableSectionElement',
- 'time': 'HTMLTimeElement',
- 'title': 'HTMLTitleElement',
- 'tr': 'HTMLTableRowElement',
- 'track': 'HTMLTrackElement',
- '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]
- });
-
-})(window.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() {
-
- // convenient global
- window.wrap = ShadowDOMPolyfill.wrapIfNeeded;
- window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded;
-
- // users may want to customize other types
- // TODO(sjmiles): 'button' is now supported by ShadowDOMPolyfill, but
- // I've left this code here in case we need to temporarily patch another
- // type
- /*
- (function() {
- var elts = {HTMLButtonElement: 'button'};
- for (var c in elts) {
- window[c] = function() { throw 'Patched Constructor'; };
- window[c].prototype = Object.getPrototypeOf(
- document.createElement(elts[c]));
- }
- })();
- */
-
- // patch in prefixed name
- Object.defineProperty(Element.prototype, 'webkitShadowRoot',
- Object.getOwnPropertyDescriptor(Element.prototype, 'shadowRoot'));
-
- var originalCreateShadowRoot = Element.prototype.createShadowRoot;
- Element.prototype.createShadowRoot = function() {
- var root = originalCreateShadowRoot.call(this);
- CustomElements.watchShadow(this);
- return root;
- };
-
- Element.prototype.webkitCreateShadowRoot = Element.prototype.createShadowRoot;
-})();
-
-/*
- * Copyright 2012 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.
- */
-
-/*
- This is a limited shim for ShadowDOM css styling.
- https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles
-
- The intention here is to support only the styling features which can be
- relatively simply implemented. The goal is to allow users to avoid the
- most obvious pitfalls and do so without compromising performance significantly.
- For ShadowDOM styling that's not covered here, a set of best practices
- can be provided that should allow users to accomplish more complex styling.
-
- The following is a list of specific ShadowDOM styling features and a brief
- discussion of the approach used to shim.
-
- Shimmed features:
-
- * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
- element using the :host rule. To shim this feature, the :host styles are
- reformatted and prefixed with a given scope name and promoted to a
- document level stylesheet.
- For example, given a scope name of .foo, a rule like this:
-
- :host {
- background: red;
- }
- }
-
- becomes:
-
- .foo {
- background: red;
- }
-
- * encapsultion: Styles defined within ShadowDOM, apply only to
- dom inside the ShadowDOM. Polymer uses one of two techniques to imlement
- this feature.
-
- By default, rules are prefixed with the host element tag name
- as a descendant selector. This ensures styling does not leak out of the 'top'
- of the element's ShadowDOM. For example,
-
- div {
- font-weight: bold;
- }
-
- becomes:
-
- x-foo div {
- font-weight: bold;
- }
-
- becomes:
-
-
- Alternatively, if Platform.ShadowCSS.strictStyling is set to true then
- selectors are scoped by adding an attribute selector suffix to each
- simple selector that contains the host element tag name. Each element
- in the element's ShadowDOM template is also given the scope attribute.
- Thus, these rules match only elements that have the scope attribute.
- For example, given a scope name of x-foo, a rule like this:
-
- div {
- font-weight: bold;
- }
-
- becomes:
-
- div[x-foo] {
- font-weight: bold;
- }
-
- Note that elements that are dynamically added to a scope must have the scope
- selector added to them manually.
-
- * upper/lower bound encapsulation: Styles which are defined outside a
- shadowRoot should not cross the ShadowDOM boundary and should not apply
- inside a shadowRoot.
-
- This styling behavior is not emulated. Some possible ways to do this that
- were rejected due to complexity and/or performance concerns include: (1) reset
- every possible property for every possible selector for a given scope name;
- (2) re-implement css in javascript.
-
- As an alternative, users should make sure to use selectors
- specific to the scope in which they are working.
-
- * ::distributed: This behavior is not emulated. It's often not necessary
- to style the contents of a specific insertion point and instead, descendants
- of the host element can be styled selectively. Users can also create an
- extra node around an insertion point and style that node's contents
- via descendent selectors. For example, with a shadowRoot like this:
-
- <style>
- ::content(div) {
- background: red;
- }
- </style>
- <content></content>
-
- could become:
-
- <style>
- / *@polyfill .content-container div * /
- ::content(div) {
- background: red;
- }
- </style>
- <div class="content-container">
- <content></content>
- </div>
-
- Note the use of @polyfill in the comment above a ShadowDOM specific style
- declaration. This is a directive to the styling shim to use the selector
- in comments in lieu of the next selector when running under polyfill.
-*/
-(function(scope) {
-
-var ShadowCSS = {
- strictStyling: false,
- registry: {},
- // Shim styles for a given root associated with a name and extendsName
- // 1. cache root styles by name
- // 2. optionally tag root nodes with scope name
- // 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
- // 4. shim :host and scoping
- shimStyling: function(root, name, extendsName) {
- var scopeStyles = this.prepareRoot(root, name, extendsName);
- var typeExtension = this.isTypeExtension(extendsName);
- var scopeSelector = this.makeScopeSelector(name, typeExtension);
- // use caching to make working with styles nodes easier and to facilitate
- // lookup of extendee
- var cssText = stylesToCssText(scopeStyles, true);
- cssText = this.scopeCssText(cssText, scopeSelector);
- // cache shimmed css on root for user extensibility
- if (root) {
- root.shimmedStyle = cssText;
- }
- // add style to document
- this.addCssToDocument(cssText, name);
- },
- /*
- * Shim a style element with the given selector. Returns cssText that can
- * be included in the document via Platform.ShadowCSS.addCssToDocument(css).
- */
- shimStyle: function(style, selector) {
- return this.shimCssText(style.textContent, selector);
- },
- /*
- * Shim some cssText with the given selector. Returns cssText that can
- * be included in the document via Platform.ShadowCSS.addCssToDocument(css).
- */
- shimCssText: function(cssText, selector) {
- cssText = this.insertDirectives(cssText);
- return this.scopeCssText(cssText, selector);
- },
- makeScopeSelector: function(name, typeExtension) {
- if (name) {
- return typeExtension ? '[is=' + name + ']' : name;
- }
- return '';
- },
- isTypeExtension: function(extendsName) {
- return extendsName && extendsName.indexOf('-') < 0;
- },
- prepareRoot: function(root, name, extendsName) {
- var def = this.registerRoot(root, name, extendsName);
- this.replaceTextInStyles(def.rootStyles, this.insertDirectives);
- // remove existing style elements
- this.removeStyles(root, def.rootStyles);
- // apply strict attr
- if (this.strictStyling) {
- this.applyScopeToContent(root, name);
- }
- return def.scopeStyles;
- },
- removeStyles: function(root, styles) {
- for (var i=0, l=styles.length, s; (i<l) && (s=styles[i]); i++) {
- s.parentNode.removeChild(s);
- }
- },
- registerRoot: function(root, name, extendsName) {
- var def = this.registry[name] = {
- root: root,
- name: name,
- extendsName: extendsName
- }
- var styles = this.findStyles(root);
- def.rootStyles = styles;
- def.scopeStyles = def.rootStyles;
- var extendee = this.registry[def.extendsName];
- if (extendee) {
- def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles);
- }
- return def;
- },
- findStyles: function(root) {
- if (!root) {
- return [];
- }
- var styles = root.querySelectorAll('style');
- return Array.prototype.filter.call(styles, function(s) {
- return !s.hasAttribute(NO_SHIM_ATTRIBUTE);
- });
- },
- applyScopeToContent: function(root, name) {
- if (root) {
- // add the name attribute to each node in root.
- Array.prototype.forEach.call(root.querySelectorAll('*'),
- function(node) {
- node.setAttribute(name, '');
- });
- // and template contents too
- Array.prototype.forEach.call(root.querySelectorAll('template'),
- function(template) {
- this.applyScopeToContent(template.content, name);
- },
- this);
- }
- },
- insertDirectives: function(cssText) {
- cssText = this.insertPolyfillDirectivesInCssText(cssText);
- return this.insertPolyfillRulesInCssText(cssText);
- },
- /*
- * Process styles to convert native ShadowDOM rules that will trip
- * up the css parser; we rely on decorating the stylesheet with inert rules.
- *
- * For example, we convert this rule:
- *
- * polyfill-next-selector { content: ':host menu-item'; }
- * ::content menu-item {
- *
- * to this:
- *
- * scopeName menu-item {
- *
- **/
- insertPolyfillDirectivesInCssText: function(cssText) {
- // TODO(sorvell): remove either content or comment
- cssText = cssText.replace(cssCommentNextSelectorRe, function(match, p1) {
- // remove end comment delimiter and add block start
- return p1.slice(0, -2) + '{';
- });
- return cssText.replace(cssContentNextSelectorRe, function(match, p1) {
- return p1 + ' {';
- });
- },
- /*
- * Process styles to add rules which will only apply under the polyfill
- *
- * For example, we convert this rule:
- *
- * polyfill-rule {
- * content: ':host menu-item';
- * ...
- * }
- *
- * to this:
- *
- * scopeName menu-item {...}
- *
- **/
- insertPolyfillRulesInCssText: function(cssText) {
- // TODO(sorvell): remove either content or comment
- cssText = cssText.replace(cssCommentRuleRe, function(match, p1) {
- // remove end comment delimiter
- return p1.slice(0, -1);
- });
- return cssText.replace(cssContentRuleRe, function(match, p1, p2, p3) {
- var rule = match.replace(p1, '').replace(p2, '');
- return p3 + rule;
- });
- },
- /* Ensure styles are scoped. Pseudo-scoping takes a rule like:
- *
- * .foo {... }
- *
- * and converts this to
- *
- * scopeName .foo { ... }
- */
- scopeCssText: function(cssText, scopeSelector) {
- var unscoped = this.extractUnscopedRulesFromCssText(cssText);
- cssText = this.insertPolyfillHostInCssText(cssText);
- cssText = this.convertColonHost(cssText);
- cssText = this.convertColonHostContext(cssText);
- cssText = this.convertCombinators(cssText);
- if (scopeSelector) {
- var self = this, cssText;
- withCssRules(cssText, function(rules) {
- cssText = self.scopeRules(rules, scopeSelector);
- });
-
- }
- cssText = cssText + '\n' + unscoped;
- return cssText.trim();
- },
- /*
- * Process styles to add rules which will only apply under the polyfill
- * and do not process via CSSOM. (CSSOM is destructive to rules on rare
- * occasions, e.g. -webkit-calc on Safari.)
- * For example, we convert this rule:
- *
- * (comment start) @polyfill-unscoped-rule menu-item {
- * ... } (comment end)
- *
- * to this:
- *
- * menu-item {...}
- *
- **/
- extractUnscopedRulesFromCssText: function(cssText) {
- // TODO(sorvell): remove either content or comment
- var r = '', m;
- while (m = cssCommentUnscopedRuleRe.exec(cssText)) {
- r += m[1].slice(0, -1) + '\n\n';
- }
- while (m = cssContentUnscopedRuleRe.exec(cssText)) {
- r += m[0].replace(m[2], '').replace(m[1], m[3]) + '\n\n';
- }
- return r;
- },
- /*
- * convert a rule like :host(.foo) > .bar { }
- *
- * to
- *
- * scopeName.foo > .bar
- */
- convertColonHost: function(cssText) {
- return this.convertColonRule(cssText, cssColonHostRe,
- this.colonHostPartReplacer);
- },
- /*
- * convert a rule like :host-context(.foo) > .bar { }
- *
- * to
- *
- * scopeName.foo > .bar, .foo scopeName > .bar { }
- *
- * and
- *
- * :host-context(.foo:host) .bar { ... }
- *
- * to
- *
- * scopeName.foo .bar { ... }
- */
- convertColonHostContext: function(cssText) {
- return this.convertColonRule(cssText, cssColonHostContextRe,
- this.colonHostContextPartReplacer);
- },
- convertColonRule: function(cssText, regExp, partReplacer) {
- // p1 = :host, p2 = contents of (), p3 rest of rule
- return cssText.replace(regExp, function(m, p1, p2, p3) {
- p1 = polyfillHostNoCombinator;
- if (p2) {
- var parts = p2.split(','), r = [];
- for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) {
- p = p.trim();
- r.push(partReplacer(p1, p, p3));
- }
- return r.join(',');
- } else {
- return p1 + p3;
- }
- });
- },
- colonHostContextPartReplacer: function(host, part, suffix) {
- if (part.match(polyfillHost)) {
- return this.colonHostPartReplacer(host, part, suffix);
- } else {
- return host + part + suffix + ', ' + part + ' ' + host + suffix;
- }
- },
- colonHostPartReplacer: function(host, part, suffix) {
- return host + part.replace(polyfillHost, '') + suffix;
- },
- /*
- * Convert ^ and ^^ combinators by replacing with space.
- */
- convertCombinators: function(cssText) {
- for (var i=0; i < combinatorsRe.length; i++) {
- cssText = cssText.replace(combinatorsRe[i], ' ');
- }
- return cssText;
- },
- // change a selector like 'div' to 'name div'
- scopeRules: function(cssRules, scopeSelector) {
- var cssText = '';
- if (cssRules) {
- Array.prototype.forEach.call(cssRules, function(rule) {
- if (rule.selectorText && (rule.style && rule.style.cssText)) {
- cssText += this.scopeSelector(rule.selectorText, scopeSelector,
- this.strictStyling) + ' {\n\t';
- cssText += this.propertiesFromRule(rule) + '\n}\n\n';
- } else if (rule.type === CSSRule.MEDIA_RULE) {
- cssText += '@media ' + rule.media.mediaText + ' {\n';
- cssText += this.scopeRules(rule.cssRules, scopeSelector);
- cssText += '\n}\n\n';
- } else if (rule.cssText) {
- cssText += rule.cssText + '\n\n';
- }
- }, this);
- }
- return cssText;
- },
- scopeSelector: function(selector, scopeSelector, strict) {
- var r = [], parts = selector.split(',');
- parts.forEach(function(p) {
- p = p.trim();
- if (this.selectorNeedsScoping(p, scopeSelector)) {
- p = (strict && !p.match(polyfillHostNoCombinator)) ?
- this.applyStrictSelectorScope(p, scopeSelector) :
- this.applySimpleSelectorScope(p, scopeSelector);
- }
- r.push(p);
- }, this);
- return r.join(', ');
- },
- selectorNeedsScoping: function(selector, scopeSelector) {
- var re = this.makeScopeMatcher(scopeSelector);
- return !selector.match(re);
- },
- makeScopeMatcher: function(scopeSelector) {
- scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\[/g, '\\]');
- return new RegExp('^(' + scopeSelector + ')' + selectorReSuffix, 'm');
- },
- // scope via name and [is=name]
- applySimpleSelectorScope: function(selector, scopeSelector) {
- if (selector.match(polyfillHostRe)) {
- selector = selector.replace(polyfillHostNoCombinator, scopeSelector);
- return selector.replace(polyfillHostRe, scopeSelector + ' ');
- } else {
- return scopeSelector + ' ' + selector;
- }
- },
- // return a selector with [name] suffix on each simple selector
- // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]
- applyStrictSelectorScope: function(selector, scopeSelector) {
- scopeSelector = scopeSelector.replace(/\[is=([^\]]*)\]/g, '$1');
- var splits = [' ', '>', '+', '~'],
- scoped = selector,
- attrName = '[' + scopeSelector + ']';
- splits.forEach(function(sep) {
- var parts = scoped.split(sep);
- scoped = parts.map(function(p) {
- // remove :host since it should be unnecessary
- var t = p.trim().replace(polyfillHostRe, '');
- if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
- p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3')
- }
- return p;
- }).join(sep);
- });
- return scoped;
- },
- insertPolyfillHostInCssText: function(selector) {
- return selector.replace(colonHostContextRe, polyfillHostContext).replace(
- colonHostRe, polyfillHost);
- },
- propertiesFromRule: function(rule) {
- var cssText = rule.style.cssText;
- // TODO(sorvell): Safari cssom incorrectly removes quotes from the content
- // property. (https://bugs.webkit.org/show_bug.cgi?id=118045)
- // don't replace attr rules
- if (rule.style.content && !rule.style.content.match(/['"]+|attr/)) {
- cssText = cssText.replace(/content:[^;]*;/g, 'content: \'' +
- rule.style.content + '\';');
- }
- // TODO(sorvell): we can workaround this issue here, but we need a list
- // of troublesome properties to fix https://github.com/Polymer/platform/issues/53
- //
- // inherit rules can be omitted from cssText
- // TODO(sorvell): remove when Blink bug is fixed:
- // https://code.google.com/p/chromium/issues/detail?id=358273
- var style = rule.style;
- for (var i in style) {
- if (style[i] === 'initial') {
- cssText += i + ': initial; ';
- }
- }
- return cssText;
- },
- replaceTextInStyles: function(styles, action) {
- if (styles && action) {
- if (!(styles instanceof Array)) {
- styles = [styles];
- }
- Array.prototype.forEach.call(styles, function(s) {
- s.textContent = action.call(this, s.textContent);
- }, this);
- }
- },
- addCssToDocument: function(cssText, name) {
- if (cssText.match('@import')) {
- addOwnSheet(cssText, name);
- } else {
- addCssToDocument(cssText);
- }
- }
-};
-
-var selectorRe = /([^{]*)({[\s\S]*?})/gim,
- cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
- // TODO(sorvell): remove either content or comment
- cssCommentNextSelectorRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,
- cssContentNextSelectorRe = /polyfill-next-selector[^}]*content\:[\s]*'([^']*)'[^}]*}([^{]*?){/gim,
- // TODO(sorvell): remove either content or comment
- cssCommentRuleRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
- cssContentRuleRe = /(polyfill-rule)[^}]*(content\:[\s]*'([^']*)'[^;]*;)[^}]*}/gim,
- // TODO(sorvell): remove either content or comment
- cssCommentUnscopedRuleRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
- cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\:[\s]*'([^']*)'[^;]*;)[^}]*}/gim,
- cssPseudoRe = /::(x-[^\s{,(]*)/gim,
- cssPartRe = /::part\(([^)]*)\)/gim,
- // note: :host pre-processed to -shadowcsshost.
- polyfillHost = '-shadowcsshost',
- // note: :host-context pre-processed to -shadowcsshostcontext.
- polyfillHostContext = '-shadowcsscontext',
- parenSuffix = ')(?:\\((' +
- '(?:\\([^)(]*\\)|[^)(]*)+?' +
- ')\\))?([^,{]*)';
- cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
- cssColonHostContextRe = new RegExp('(' + polyfillHostContext + parenSuffix, 'gim'),
- selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
- colonHostRe = /\:host/gim,
- colonHostContextRe = /\:host-context/gim,
- /* host name without combinator */
- polyfillHostNoCombinator = polyfillHost + '-no-combinator',
- polyfillHostRe = new RegExp(polyfillHost, 'gim'),
- polyfillHostContextRe = new RegExp(polyfillHostContext, 'gim'),
- combinatorsRe = [
- /\^\^/g,
- /\^/g,
- /\/shadow\//g,
- /\/shadow-deep\//g,
- /::shadow/g,
- /\/deep\//g
- ];
-
-function stylesToCssText(styles, preserveComments) {
- var cssText = '';
- Array.prototype.forEach.call(styles, function(s) {
- cssText += s.textContent + '\n\n';
- });
- // strip comments for easier processing
- if (!preserveComments) {
- cssText = cssText.replace(cssCommentRe, '');
- }
- return cssText;
-}
-
-function cssTextToStyle(cssText) {
- var style = document.createElement('style');
- style.textContent = cssText;
- return style;
-}
-
-function cssToRules(cssText) {
- var style = cssTextToStyle(cssText);
- document.head.appendChild(style);
- var rules = [];
- if (style.sheet) {
- // TODO(sorvell): Firefox throws when accessing the rules of a stylesheet
- // with an @import
- // https://bugzilla.mozilla.org/show_bug.cgi?id=625013
- try {
- rules = style.sheet.cssRules;
- } catch(e) {
- //
- }
- } else {
- console.warn('sheet not found', style);
- }
- style.parentNode.removeChild(style);
- return rules;
-}
-
-var frame = document.createElement('iframe');
-frame.style.display = 'none';
-
-function initFrame() {
- frame.initialized = true;
- document.body.appendChild(frame);
- var doc = frame.contentDocument;
- var base = doc.createElement('base');
- base.href = document.baseURI;
- doc.head.appendChild(base);
-}
-
-function inFrame(fn) {
- if (!frame.initialized) {
- initFrame();
- }
- document.body.appendChild(frame);
- fn(frame.contentDocument);
- document.body.removeChild(frame);
-}
-
-// TODO(sorvell): use an iframe if the cssText contains an @import to workaround
-// https://code.google.com/p/chromium/issues/detail?id=345114
-var isChrome = navigator.userAgent.match('Chrome');
-function withCssRules(cssText, callback) {
- if (!callback) {
- return;
- }
- var rules;
- if (cssText.match('@import') && isChrome) {
- var style = cssTextToStyle(cssText);
- inFrame(function(doc) {
- doc.head.appendChild(style.impl);
- rules = style.sheet.cssRules;
- callback(rules);
- });
- } else {
- rules = cssToRules(cssText);
- callback(rules);
- }
-}
-
-function rulesToCss(cssRules) {
- for (var i=0, css=[]; i < cssRules.length; i++) {
- css.push(cssRules[i].cssText);
- }
- return css.join('\n\n');
-}
-
-function addCssToDocument(cssText) {
- if (cssText) {
- getSheet().appendChild(document.createTextNode(cssText));
- }
-}
-
-function addOwnSheet(cssText, name) {
- var style = cssTextToStyle(cssText);
- style.setAttribute(name, '');
- style.setAttribute(SHIMMED_ATTRIBUTE, '');
- document.head.appendChild(style);
-}
-
-var SHIM_ATTRIBUTE = 'shim-shadowdom';
-var SHIMMED_ATTRIBUTE = 'shim-shadowdom-css';
-var NO_SHIM_ATTRIBUTE = 'no-shim';
-
-var sheet;
-function getSheet() {
- if (!sheet) {
- sheet = document.createElement("style");
- sheet.setAttribute(SHIMMED_ATTRIBUTE, '');
- sheet[SHIMMED_ATTRIBUTE] = true;
- }
- return sheet;
-}
-
-// add polyfill stylesheet to document
-if (window.ShadowDOMPolyfill) {
- addCssToDocument('style { display: none !important; }\n');
- var doc = wrap(document);
- var head = doc.querySelector('head');
- head.insertBefore(getSheet(), head.childNodes[0]);
-
- // TODO(sorvell): monkey-patching HTMLImports is abusive;
- // consider a better solution.
- document.addEventListener('DOMContentLoaded', function() {
- var urlResolver = scope.urlResolver;
-
- if (window.HTMLImports && !HTMLImports.useNative) {
- var SHIM_SHEET_SELECTOR = 'link[rel=stylesheet]' +
- '[' + SHIM_ATTRIBUTE + ']';
- var SHIM_STYLE_SELECTOR = 'style[' + SHIM_ATTRIBUTE + ']';
- HTMLImports.importer.documentPreloadSelectors += ',' + SHIM_SHEET_SELECTOR;
- HTMLImports.importer.importsPreloadSelectors += ',' + SHIM_SHEET_SELECTOR;
-
- HTMLImports.parser.documentSelectors = [
- HTMLImports.parser.documentSelectors,
- SHIM_SHEET_SELECTOR,
- SHIM_STYLE_SELECTOR
- ].join(',');
-
- var originalParseGeneric = HTMLImports.parser.parseGeneric;
-
- HTMLImports.parser.parseGeneric = function(elt) {
- if (elt[SHIMMED_ATTRIBUTE]) {
- return;
- }
- var style = elt.__importElement || elt;
- if (!style.hasAttribute(SHIM_ATTRIBUTE)) {
- originalParseGeneric.call(this, elt);
- return;
- }
- if (elt.__resource) {
- style = elt.ownerDocument.createElement('style');
- style.textContent = urlResolver.resolveCssText(
- elt.__resource, elt.href);
- } else {
- urlResolver.resolveStyle(style);
- }
- style.textContent = ShadowCSS.shimStyle(style);
- style.removeAttribute(SHIM_ATTRIBUTE, '');
- style.setAttribute(SHIMMED_ATTRIBUTE, '');
- style[SHIMMED_ATTRIBUTE] = true;
- // place in document
- if (style.parentNode !== head) {
- // replace links in head
- if (elt.parentNode === head) {
- head.replaceChild(style, elt);
- } else {
- head.appendChild(style);
- }
- }
- style.__importParsed = true;
- this.markParsingComplete(elt);
- }
-
- var hasResource = HTMLImports.parser.hasResource;
- HTMLImports.parser.hasResource = function(node) {
- if (node.localName === 'link' && node.rel === 'stylesheet' &&
- node.hasAttribute(SHIM_ATTRIBUTE)) {
- return (node.__resource);
- } else {
- return hasResource.call(this, node);
- }
- }
-
- }
- });
-}
-
-// exports
-scope.ShadowCSS = ShadowCSS;
-
-})(window.Platform);
-} else {
-/*
- * 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() {
-
- // poor man's adapter for template.content on various platform scenarios
- window.templateContent = window.templateContent || function(inTemplate) {
- return inTemplate.content;
- };
-
- // so we can call wrap/unwrap without testing for ShadowDOMPolyfill
-
- window.wrap = window.unwrap = function(n){
- return n;
- }
-
- addEventListener('DOMContentLoaded', function() {
- if (CustomElements.useNative === false) {
- var originalCreateShadowRoot = Element.prototype.createShadowRoot;
- Element.prototype.createShadowRoot = function() {
- var root = originalCreateShadowRoot.call(this);
- CustomElements.watchShadow(this);
- return root;
- };
- }
- });
-
- window.templateContent = function(inTemplate) {
- // if MDV exists, it may need to boostrap this template to reveal content
- if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
- HTMLTemplateElement.bootstrap(inTemplate);
- }
- // fallback when there is no Shadow DOM polyfill, no MDV polyfill, and no
- // native template support
- if (!inTemplate.content && !inTemplate._content) {
- var frag = document.createDocumentFragment();
- while (inTemplate.firstChild) {
- frag.appendChild(inTemplate.firstChild);
- }
- inTemplate._content = frag;
- }
- return inTemplate.content || inTemplate._content;
- };
-
-})();
-}
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-(function(scope) {
- 'use strict';
-
- // feature detect for URL constructor
- var hasWorkingUrl = false;
- if (!scope.forceJURL) {
- try {
- var u = new URL('b', 'http://a');
- hasWorkingUrl = u.href === 'http://a/b';
- } catch(e) {}
- }
-
- if (hasWorkingUrl)
- return;
-
- var relative = Object.create(null);
- relative['ftp'] = 21;
- relative['file'] = 0;
- relative['gopher'] = 70;
- relative['http'] = 80;
- relative['https'] = 443;
- relative['ws'] = 80;
- relative['wss'] = 443;
-
- var relativePathDotMapping = Object.create(null);
- relativePathDotMapping['%2e'] = '.';
- relativePathDotMapping['.%2e'] = '..';
- relativePathDotMapping['%2e.'] = '..';
- relativePathDotMapping['%2e%2e'] = '..';
-
- function isRelativeScheme(scheme) {
- return relative[scheme] !== undefined;
- }
-
- function invalid() {
- clear.call(this);
- this._isInvalid = true;
- }
-
- function IDNAToASCII(h) {
- if ('' == h) {
- invalid.call(this)
- }
- // XXX
- return h.toLowerCase()
- }
-
- function percentEscape(c) {
- var unicode = c.charCodeAt(0);
- if (unicode > 0x20 &&
- unicode < 0x7F &&
- // " # < > ? `
- [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
- ) {
- return c;
- }
- return encodeURIComponent(c);
- }
-
- function percentEscapeQuery(c) {
- // XXX This actually needs to encode c using encoding and then
- // convert the bytes one-by-one.
-
- var unicode = c.charCodeAt(0);
- if (unicode > 0x20 &&
- unicode < 0x7F &&
- // " # < > ` (do not escape '?')
- [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
- ) {
- return c;
- }
- return encodeURIComponent(c);
- }
-
- var EOF = undefined,
- ALPHA = /[a-zA-Z]/,
- ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
-
- function parse(input, stateOverride, base) {
- function err(message) {
- errors.push(message)
- }
-
- var state = stateOverride || 'scheme start',
- cursor = 0,
- buffer = '',
- seenAt = false,
- seenBracket = false,
- errors = [];
-
- loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
- var c = input[cursor];
- switch (state) {
- case 'scheme start':
- if (c && ALPHA.test(c)) {
- buffer += c.toLowerCase(); // ASCII-safe
- state = 'scheme';
- } else if (!stateOverride) {
- buffer = '';
- state = 'no scheme';
- continue;
- } else {
- err('Invalid scheme.');
- break loop;
- }
- break;
-
- case 'scheme':
- if (c && ALPHANUMERIC.test(c)) {
- buffer += c.toLowerCase(); // ASCII-safe
- } else if (':' == c) {
- this._scheme = buffer;
- buffer = '';
- if (stateOverride) {
- break loop;
- }
- if (isRelativeScheme(this._scheme)) {
- this._isRelative = true;
- }
- if ('file' == this._scheme) {
- state = 'relative';
- } else if (this._isRelative && base && base._scheme == this._scheme) {
- state = 'relative or authority';
- } else if (this._isRelative) {
- state = 'authority first slash';
- } else {
- state = 'scheme data';
- }
- } else if (!stateOverride) {
- buffer = '';
- cursor = 0;
- state = 'no scheme';
- continue;
- } else if (EOF == c) {
- break loop;
- } else {
- err('Code point not allowed in scheme: ' + c)
- break loop;
- }
- break;
-
- case 'scheme data':
- if ('?' == c) {
- query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._fragment = '#';
- state = 'fragment';
- } else {
- // XXX error handling
- if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._schemeData += percentEscape(c);
- }
- }
- break;
-
- case 'no scheme':
- if (!base || !(isRelativeScheme(base._scheme))) {
- err('Missing scheme.');
- invalid.call(this);
- } else {
- state = 'relative';
- continue;
- }
- break;
-
- case 'relative or authority':
- if ('/' == c && '/' == input[cursor+1]) {
- state = 'authority ignore slashes';
- } else {
- err('Expected /, got: ' + c);
- state = 'relative';
- continue
- }
- break;
-
- case 'relative':
- this._isRelative = true;
- if ('file' != this._scheme)
- this._scheme = base._scheme;
- if (EOF == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = base._query;
- break loop;
- } else if ('/' == c || '\\' == c) {
- if ('\\' == c)
- err('\\ is an invalid code point.');
- state = 'relative slash';
- } else if ('?' == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = base._query;
- this._fragment = '#';
- state = 'fragment';
- } else {
- var nextC = input[cursor+1]
- var nextNextC = input[cursor+2]
- if (
- 'file' != this._scheme || !ALPHA.test(c) ||
- (nextC != ':' && nextC != '|') ||
- (EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._path.pop();
- }
- state = 'relative path';
- continue;
- }
- break;
-
- case 'relative slash':
- if ('/' == c || '\\' == c) {
- if ('\\' == c) {
- err('\\ is an invalid code point.');
- }
- if ('file' == this._scheme) {
- state = 'file host';
- } else {
- state = 'authority ignore slashes';
- }
- } else {
- if ('file' != this._scheme) {
- this._host = base._host;
- this._port = base._port;
- }
- state = 'relative path';
- continue;
- }
- break;
-
- case 'authority first slash':
- if ('/' == c) {
- state = 'authority second slash';
- } else {
- err("Expected '/', got: " + c);
- state = 'authority ignore slashes';
- continue;
- }
- break;
-
- case 'authority second slash':
- state = 'authority ignore slashes';
- if ('/' != c) {
- err("Expected '/', got: " + c);
- continue;
- }
- break;
-
- case 'authority ignore slashes':
- if ('/' != c && '\\' != c) {
- state = 'authority';
- continue;
- } else {
- err('Expected authority, got: ' + c);
- }
- break;
-
- case 'authority':
- if ('@' == c) {
- if (seenAt) {
- err('@ already seen.');
- buffer += '%40';
- }
- seenAt = true;
- for (var i = 0; i < buffer.length; i++) {
- var cp = buffer[i];
- if ('\t' == cp || '\n' == cp || '\r' == cp) {
- err('Invalid whitespace in authority.');
- continue;
- }
- // XXX check URL code points
- if (':' == cp && null === this._password) {
- this._password = '';
- continue;
- }
- var tempC = percentEscape(cp);
- (null !== this._password) ? this._password += tempC : this._username += tempC;
- }
- buffer = '';
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- cursor -= buffer.length;
- buffer = '';
- state = 'host';
- continue;
- } else {
- buffer += c;
- }
- break;
-
- case 'file host':
- if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
- state = 'relative path';
- } else if (buffer.length == 0) {
- state = 'relative path start';
- } else {
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'relative path start';
- }
- continue;
- } else if ('\t' == c || '\n' == c || '\r' == c) {
- err('Invalid whitespace in file host.');
- } else {
- buffer += c;
- }
- break;
-
- case 'host':
- case 'hostname':
- if (':' == c && !seenBracket) {
- // XXX host parsing
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'port';
- if ('hostname' == stateOverride) {
- break loop;
- }
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'relative path start';
- if (stateOverride) {
- break loop;
- }
- continue;
- } else if ('\t' != c && '\n' != c && '\r' != c) {
- if ('[' == c) {
- seenBracket = true;
- } else if (']' == c) {
- seenBracket = false;
- }
- buffer += c;
- } else {
- err('Invalid code point in host/hostname: ' + c);
- }
- break;
-
- case 'port':
- if (/[0-9]/.test(c)) {
- buffer += c;
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c || stateOverride) {
- if ('' != buffer) {
- var temp = parseInt(buffer, 10);
- if (temp != relative[this._scheme]) {
- this._port = temp + '';
- }
- buffer = '';
- }
- if (stateOverride) {
- break loop;
- }
- state = 'relative path start';
- continue;
- } else if ('\t' == c || '\n' == c || '\r' == c) {
- err('Invalid code point in port: ' + c);
- } else {
- invalid.call(this);
- }
- break;
-
- case 'relative path start':
- if ('\\' == c)
- err("'\\' not allowed in path.");
- state = 'relative path';
- if ('/' != c && '\\' != c) {
- continue;
- }
- break;
-
- case 'relative path':
- if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
- if ('\\' == c) {
- err('\\ not allowed in relative path.');
- }
- var tmp;
- if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
- buffer = tmp;
- }
- if ('..' == buffer) {
- this._path.pop();
- if ('/' != c && '\\' != c) {
- this._path.push('');
- }
- } else if ('.' == buffer && '/' != c && '\\' != c) {
- this._path.push('');
- } else if ('.' != buffer) {
- if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
- buffer = buffer[0] + ':';
- }
- this._path.push(buffer);
- }
- buffer = '';
- if ('?' == c) {
- this._query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._fragment = '#';
- state = 'fragment';
- }
- } else if ('\t' != c && '\n' != c && '\r' != c) {
- buffer += percentEscape(c);
- }
- break;
-
- case 'query':
- if (!stateOverride && '#' == c) {
- this._fragment = '#';
- state = 'fragment';
- } else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._query += percentEscapeQuery(c);
- }
- break;
-
- case 'fragment':
- if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._fragment += c;
- }
- break;
- }
-
- cursor++;
- }
- }
-
- function clear() {
- this._scheme = '';
- this._schemeData = '';
- this._username = '';
- this._password = null;
- this._host = '';
- this._port = '';
- this._path = [];
- this._query = '';
- this._fragment = '';
- this._isInvalid = false;
- this._isRelative = false;
- }
-
- // Does not process domain names or IP addresses.
- // Does not handle encoding for the query parameter.
- function jURL(url, base /* , encoding */) {
- if (base !== undefined && !(base instanceof jURL))
- base = new jURL(String(base));
-
- this._url = url;
- clear.call(this);
-
- var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
- // encoding = encoding || 'utf-8'
-
- parse.call(this, input, null, base);
- }
-
- jURL.prototype = {
- get href() {
- if (this._isInvalid)
- return this._url;
-
- var authority = '';
- if ('' != this._username || null != this._password) {
- authority = this._username +
- (null != this._password ? ':' + this._password : '') + '@';
- }
-
- return this.protocol +
- (this._isRelative ? '//' + authority + this.host : '') +
- this.pathname + this._query + this._fragment;
- },
- set href(href) {
- clear.call(this);
- parse.call(this, href);
- },
-
- get protocol() {
- return this._scheme + ':';
- },
- set protocol(protocol) {
- if (this._isInvalid)
- return;
- parse.call(this, protocol + ':', 'scheme start');
- },
-
- get host() {
- return this._isInvalid ? '' : this._port ?
- this._host + ':' + this._port : this._host;
- },
- set host(host) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, host, 'host');
- },
-
- get hostname() {
- return this._host;
- },
- set hostname(hostname) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, hostname, 'hostname');
- },
-
- get port() {
- return this._port;
- },
- set port(port) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, port, 'port');
- },
-
- get pathname() {
- return this._isInvalid ? '' : this._isRelative ?
- '/' + this._path.join('/') : this._schemeData;
- },
- set pathname(pathname) {
- if (this._isInvalid || !this._isRelative)
- return;
- this._path = [];
- parse.call(this, pathname, 'relative path start');
- },
-
- get search() {
- return this._isInvalid || !this._query || '?' == this._query ?
- '' : this._query;
- },
- set search(search) {
- if (this._isInvalid || !this._isRelative)
- return;
- this._query = '?';
- if ('?' == search[0])
- search = search.slice(1);
- parse.call(this, search, 'query');
- },
-
- get hash() {
- return this._isInvalid || !this._fragment || '#' == this._fragment ?
- '' : this._fragment;
- },
- set hash(hash) {
- if (this._isInvalid)
- return;
- this._fragment = '#';
- if ('#' == hash[0])
- hash = hash.slice(1);
- parse.call(this, hash, 'fragment');
- }
- };
-
- scope.URL = jURL;
-
-})(window);
-
-/*
- * 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) {
-
-// Old versions of iOS do not have bind.
-
-if (!Function.prototype.bind) {
- Function.prototype.bind = function(scope) {
- var self = this;
- var args = Array.prototype.slice.call(arguments, 1);
- return function() {
- var args2 = args.slice();
- args2.push.apply(args2, arguments);
- return self.apply(scope, args2);
- };
- };
-}
-
-// mixin
-
-// copy all properties from inProps (et al) to inObj
-function mixin(inObj/*, inProps, inMoreProps, ...*/) {
- var obj = inObj || {};
- for (var i = 1; i < arguments.length; i++) {
- var p = arguments[i];
- try {
- for (var n in p) {
- copyProperty(n, p, obj);
- }
- } catch(x) {
- }
- }
- return obj;
-}
-
-// copy property inName from inSource object to inTarget object
-function copyProperty(inName, inSource, inTarget) {
- var pd = getPropertyDescriptor(inSource, inName);
- Object.defineProperty(inTarget, inName, pd);
-}
-
-// get property descriptor for inName on inObject, even if
-// inName exists on some link in inObject's prototype chain
-function getPropertyDescriptor(inObject, inName) {
- if (inObject) {
- var pd = Object.getOwnPropertyDescriptor(inObject, inName);
- return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName);
- }
-}
-
-// export
-
-scope.mixin = mixin;
-
-})(window.Platform);
-// Copyright 2011 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-(function(scope) {
-
- 'use strict';
-
- // polyfill DOMTokenList
- // * add/remove: allow these methods to take multiple classNames
- // * toggle: add a 2nd argument which forces the given state rather
- // than toggling.
-
- var add = DOMTokenList.prototype.add;
- var remove = DOMTokenList.prototype.remove;
- DOMTokenList.prototype.add = function() {
- for (var i = 0; i < arguments.length; i++) {
- add.call(this, arguments[i]);
- }
- };
- DOMTokenList.prototype.remove = function() {
- for (var i = 0; i < arguments.length; i++) {
- remove.call(this, arguments[i]);
- }
- };
- DOMTokenList.prototype.toggle = function(name, bool) {
- if (arguments.length == 1) {
- bool = !this.contains(name);
- }
- bool ? this.add(name) : this.remove(name);
- };
- DOMTokenList.prototype.switch = function(oldName, newName) {
- oldName && this.remove(oldName);
- newName && this.add(newName);
- };
-
- // add array() to NodeList, NamedNodeMap, HTMLCollection
-
- var ArraySlice = function() {
- return Array.prototype.slice.call(this);
- };
-
- var namedNodeMap = (window.NamedNodeMap || window.MozNamedAttrMap || {});
-
- NodeList.prototype.array = ArraySlice;
- namedNodeMap.prototype.array = ArraySlice;
- HTMLCollection.prototype.array = ArraySlice;
-
- // polyfill performance.now
-
- if (!window.performance) {
- var start = Date.now();
- // only at millisecond precision
- window.performance = {now: function(){ return Date.now() - start }};
- }
-
- // polyfill for requestAnimationFrame
-
- if (!window.requestAnimationFrame) {
- window.requestAnimationFrame = (function() {
- var nativeRaf = window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame;
-
- return nativeRaf ?
- function(callback) {
- return nativeRaf(function() {
- callback(performance.now());
- });
- } :
- function( callback ){
- return window.setTimeout(callback, 1000 / 60);
- };
- })();
- }
-
- if (!window.cancelAnimationFrame) {
- window.cancelAnimationFrame = (function() {
- return window.webkitCancelAnimationFrame ||
- window.mozCancelAnimationFrame ||
- function(id) {
- clearTimeout(id);
- };
- })();
- }
-
- // utility
-
- function createDOM(inTagOrNode, inHTML, inAttrs) {
- var dom = typeof inTagOrNode == 'string' ?
- document.createElement(inTagOrNode) : inTagOrNode.cloneNode(true);
- dom.innerHTML = inHTML;
- if (inAttrs) {
- for (var n in inAttrs) {
- dom.setAttribute(n, inAttrs[n]);
- }
- }
- return dom;
- }
- // Make a stub for Polymer() for polyfill purposes; under the HTMLImports
- // polyfill, scripts in the main document run before imports. That means
- // if (1) polymer is imported and (2) Polymer() is called in the main document
- // in a script after the import, 2 occurs before 1. We correct this here
- // by specfiically patching Polymer(); this is not necessary under native
- // HTMLImports.
- var elementDeclarations = [];
-
- var polymerStub = function(name, dictionary) {
- elementDeclarations.push(arguments);
- }
- window.Polymer = polymerStub;
-
- // deliver queued delcarations
- scope.deliverDeclarations = function() {
- scope.deliverDeclarations = function() {
- throw 'Possible attempt to load Polymer twice';
- };
- return elementDeclarations;
- }
-
- // Once DOMContent has loaded, any main document scripts that depend on
- // Polymer() should have run. Calling Polymer() now is an error until
- // polymer is imported.
- window.addEventListener('DOMContentLoaded', function() {
- if (window.Polymer === polymerStub) {
- window.Polymer = function() {
- console.error('You tried to use polymer without loading it first. To ' +
- 'load polymer, <link rel="import" href="' +
- 'components/polymer/polymer.html">');
- };
- }
- });
-
- // exports
- scope.createDOM = createDOM;
-
-})(window.Platform);
-
-/*
- * 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.
- */
-
-// poor man's adapter for template.content on various platform scenarios
-window.templateContent = window.templateContent || function(inTemplate) {
- return inTemplate.content;
-};
-(function(scope) {
-
- scope = scope || (window.Inspector = {});
-
- var inspector;
-
- window.sinspect = function(inNode, inProxy) {
- if (!inspector) {
- inspector = window.open('', 'ShadowDOM Inspector', null, true);
- inspector.document.write(inspectorHTML);
- //inspector.document.close();
- inspector.api = {
- shadowize: shadowize
- };
- }
- inspect(inNode || wrap(document.body), inProxy);
- };
-
- var inspectorHTML = [
- '<!DOCTYPE html>',
- '<html>',
- ' <head>',
- ' <title>ShadowDOM Inspector</title>',
- ' <style>',
- ' body {',
- ' }',
- ' pre {',
- ' font: 9pt "Courier New", monospace;',
- ' line-height: 1.5em;',
- ' }',
- ' tag {',
- ' color: purple;',
- ' }',
- ' ul {',
- ' margin: 0;',
- ' padding: 0;',
- ' list-style: none;',
- ' }',
- ' li {',
- ' display: inline-block;',
- ' background-color: #f1f1f1;',
- ' padding: 4px 6px;',
- ' border-radius: 4px;',
- ' margin-right: 4px;',
- ' }',
- ' </style>',
- ' </head>',
- ' <body>',
- ' <ul id="crumbs">',
- ' </ul>',
- ' <div id="tree"></div>',
- ' </body>',
- '</html>'
- ].join('\n');
-
- var crumbs = [];
-
- var displayCrumbs = function() {
- // alias our document
- var d = inspector.document;
- // get crumbbar
- var cb = d.querySelector('#crumbs');
- // clear crumbs
- cb.textContent = '';
- // build new crumbs
- for (var i=0, c; c=crumbs[i]; i++) {
- var a = d.createElement('a');
- a.href = '#';
- a.textContent = c.localName;
- a.idx = i;
- a.onclick = function(event) {
- var c;
- while (crumbs.length > this.idx) {
- c = crumbs.pop();
- }
- inspect(c.shadow || c, c);
- event.preventDefault();
- };
- cb.appendChild(d.createElement('li')).appendChild(a);
- }
- };
-
- var inspect = function(inNode, inProxy) {
- // alias our document
- var d = inspector.document;
- // reset list of drillable nodes
- drillable = [];
- // memoize our crumb proxy
- var proxy = inProxy || inNode;
- crumbs.push(proxy);
- // update crumbs
- displayCrumbs();
- // reflect local tree
- d.body.querySelector('#tree').innerHTML =
- '<pre>' + output(inNode, inNode.childNodes) + '</pre>';
- };
-
- var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
-
- var blacklisted = {STYLE:1, SCRIPT:1, "#comment": 1, TEMPLATE: 1};
- var blacklist = function(inNode) {
- return blacklisted[inNode.nodeName];
- };
-
- var output = function(inNode, inChildNodes, inIndent) {
- if (blacklist(inNode)) {
- return '';
- }
- var indent = inIndent || '';
- if (inNode.localName || inNode.nodeType == 11) {
- var name = inNode.localName || 'shadow-root';
- //inChildNodes = ShadowDOM.localNodes(inNode);
- var info = indent + describe(inNode);
- // if only textNodes
- // TODO(sjmiles): make correct for ShadowDOM
- /*if (!inNode.children.length && inNode.localName !== 'content' && inNode.localName !== 'shadow') {
- info += catTextContent(inChildNodes);
- } else*/ {
- // TODO(sjmiles): native <shadow> has no reference to its projection
- if (name == 'content' /*|| name == 'shadow'*/) {
- inChildNodes = inNode.getDistributedNodes();
- }
- info += '<br/>';
- var ind = indent + '&nbsp;&nbsp;';
- forEach(inChildNodes, function(n) {
- info += output(n, n.childNodes, ind);
- });
- info += indent;
- }
- if (!({br:1}[name])) {
- info += '<tag>&lt;/' + name + '&gt;</tag>';
- info += '<br/>';
- }
- } else {
- var text = inNode.textContent.trim();
- info = text ? indent + '"' + text + '"' + '<br/>' : '';
- }
- return info;
- };
-
- var catTextContent = function(inChildNodes) {
- var info = '';
- forEach(inChildNodes, function(n) {
- info += n.textContent.trim();
- });
- return info;
- };
-
- var drillable = [];
-
- var describe = function(inNode) {
- var tag = '<tag>' + '&lt;';
- var name = inNode.localName || 'shadow-root';
- if (inNode.webkitShadowRoot || inNode.shadowRoot) {
- tag += ' <button idx="' + drillable.length +
- '" onclick="api.shadowize.call(this)">' + name + '</button>';
- drillable.push(inNode);
- } else {
- tag += name || 'shadow-root';
- }
- if (inNode.attributes) {
- forEach(inNode.attributes, function(a) {
- tag += ' ' + a.name + (a.value ? '="' + a.value + '"' : '');
- });
- }
- tag += '&gt;'+ '</tag>';
- return tag;
- };
-
- // remote api
-
- shadowize = function() {
- var idx = Number(this.attributes.idx.value);
- //alert(idx);
- var node = drillable[idx];
- if (node) {
- inspect(node.webkitShadowRoot || node.shadowRoot, node)
- } else {
- console.log("bad shadowize node");
- console.dir(this);
- }
- };
-
- // export
-
- scope.output = output;
-
-})(window.Inspector);
-
-
-
-/*
- * 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) {
-
- // TODO(sorvell): It's desireable to provide a default stylesheet
- // that's convenient for styling unresolved elements, but
- // it's cumbersome to have to include this manually in every page.
- // It would make sense to put inside some HTMLImport but
- // the HTMLImports polyfill does not allow loading of stylesheets
- // that block rendering. Therefore this injection is tolerated here.
-
- var style = document.createElement('style');
- style.textContent = ''
- + 'body {'
- + 'transition: opacity ease-in 0.2s;'
- + ' } \n'
- + 'body[unresolved] {'
- + 'opacity: 0; display: block; overflow: hidden;'
- + ' } \n'
- ;
- var head = document.querySelector('head');
- head.insertBefore(style, head.firstChild);
-
-})(Platform);
-
-(function(scope) {
-
- function withDependencies(task, depends) {
- depends = depends || [];
- if (!depends.map) {
- depends = [depends];
- }
- return task.apply(this, depends.map(marshal));
- }
-
- function module(name, dependsOrFactory, moduleFactory) {
- var module;
- switch (arguments.length) {
- case 0:
- return;
- case 1:
- module = null;
- break;
- case 2:
- module = dependsOrFactory.apply(this);
- break;
- default:
- module = withDependencies(moduleFactory, dependsOrFactory);
- break;
- }
- modules[name] = module;
- };
-
- function marshal(name) {
- return modules[name];
- }
-
- var modules = {};
-
- function using(depends, task) {
- HTMLImports.whenImportsReady(function() {
- withDependencies(task, depends);
- });
- };
-
- // exports
-
- scope.marshal = marshal;
- scope.module = module;
- scope.using = using;
-
-})(window);
-/*
- * 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) {
-
-var iterations = 0;
-var callbacks = [];
-var twiddle = document.createTextNode('');
-
-function endOfMicrotask(callback) {
- twiddle.textContent = iterations++;
- callbacks.push(callback);
-}
-
-function atEndOfMicrotask() {
- while (callbacks.length) {
- callbacks.shift()();
- }
-}
-
-new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask)
- .observe(twiddle, {characterData: true})
- ;
-
-// exports
-
-scope.endOfMicrotask = endOfMicrotask;
-
-})(Platform);
-
-
-/*
- * 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) {
-
-var urlResolver = {
- resolveDom: function(root, url) {
- url = url || root.ownerDocument.baseURI;
- this.resolveAttributes(root, url);
- this.resolveStyles(root, url);
- // handle template.content
- var templates = root.querySelectorAll('template');
- if (templates) {
- for (var i = 0, l = templates.length, t; (i < l) && (t = templates[i]); i++) {
- if (t.content) {
- this.resolveDom(t.content, url);
- }
- }
- }
- },
- resolveTemplate: function(template) {
- this.resolveDom(template.content, template.ownerDocument.baseURI);
- },
- resolveStyles: function(root, url) {
- var styles = root.querySelectorAll('style');
- if (styles) {
- for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) {
- this.resolveStyle(s, url);
- }
- }
- },
- resolveStyle: function(style, url) {
- url = url || style.ownerDocument.baseURI;
- style.textContent = this.resolveCssText(style.textContent, url);
- },
- resolveCssText: function(cssText, baseUrl) {
- cssText = replaceUrlsInCssText(cssText, baseUrl, CSS_URL_REGEXP);
- return replaceUrlsInCssText(cssText, baseUrl, CSS_IMPORT_REGEXP);
- },
- resolveAttributes: function(root, url) {
- if (root.hasAttributes && root.hasAttributes()) {
- this.resolveElementAttributes(root, url);
- }
- // search for attributes that host urls
- var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR);
- if (nodes) {
- for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) {
- this.resolveElementAttributes(n, url);
- }
- }
- },
- resolveElementAttributes: function(node, url) {
- url = url || node.ownerDocument.baseURI;
- URL_ATTRS.forEach(function(v) {
- var attr = node.attributes[v];
- if (attr && attr.value &&
- (attr.value.search(URL_TEMPLATE_SEARCH) < 0)) {
- var urlPath = resolveRelativeUrl(url, attr.value);
- attr.value = urlPath;
- }
- });
- }
-};
-
-var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
-var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
-var URL_ATTRS = ['href', 'src', 'action'];
-var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']';
-var URL_TEMPLATE_SEARCH = '{{.*}}';
-
-function replaceUrlsInCssText(cssText, baseUrl, regexp) {
- return cssText.replace(regexp, function(m, pre, url, post) {
- var urlPath = url.replace(/["']/g, '');
- urlPath = resolveRelativeUrl(baseUrl, urlPath);
- return pre + '\'' + urlPath + '\'' + post;
- });
-}
-
-function resolveRelativeUrl(baseUrl, url) {
- var u = new URL(url, baseUrl);
- return makeDocumentRelPath(u.href);
-}
-
-function makeDocumentRelPath(url) {
- var root = document.baseURI;
- var u = new URL(url, root);
- if (u.host === root.host && u.port === root.port &&
- u.protocol === root.protocol) {
- return makeRelPath(root.pathname, u.pathname);
- } else {
- return url;
- }
-}
-
-// make a relative path from source to target
-function makeRelPath(source, target) {
- var s = source.split('/');
- var t = target.split('/');
- while (s.length && s[0] === t[0]){
- s.shift();
- t.shift();
- }
- for (var i = 0, l = s.length - 1; i < l; i++) {
- t.unshift('..');
- }
- return t.join('/');
-}
-
-// exports
-scope.urlResolver = urlResolver;
-
-})(Platform);
-
-/*
- * 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(global) {
-
- var registrationsTable = new WeakMap();
-
- // We use setImmediate or postMessage for our future callback.
- var setImmediate = window.msSetImmediate;
-
- // Use post message to emulate setImmediate.
- if (!setImmediate) {
- var setImmediateQueue = [];
- var sentinel = String(Math.random());
- window.addEventListener('message', function(e) {
- if (e.data === sentinel) {
- var queue = setImmediateQueue;
- setImmediateQueue = [];
- queue.forEach(function(func) {
- func();
- });
- }
- });
- setImmediate = function(func) {
- setImmediateQueue.push(func);
- window.postMessage(sentinel, '*');
- };
- }
-
- // This is used to ensure that we never schedule 2 callas to setImmediate
- var isScheduled = false;
-
- // Keep track of observers that needs to be notified next time.
- var scheduledObservers = [];
-
- /**
- * Schedules |dispatchCallback| to be called in the future.
- * @param {MutationObserver} observer
- */
- function scheduleCallback(observer) {
- scheduledObservers.push(observer);
- if (!isScheduled) {
- isScheduled = true;
- setImmediate(dispatchCallbacks);
- }
- }
-
- function wrapIfNeeded(node) {
- return window.ShadowDOMPolyfill &&
- window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
- node;
- }
-
- function dispatchCallbacks() {
- // http://dom.spec.whatwg.org/#mutation-observers
-
- isScheduled = false; // Used to allow a new setImmediate call above.
-
- var observers = scheduledObservers;
- scheduledObservers = [];
- // Sort observers based on their creation UID (incremental).
- observers.sort(function(o1, o2) {
- return o1.uid_ - o2.uid_;
- });
-
- var anyNonEmpty = false;
- observers.forEach(function(observer) {
-
- // 2.1, 2.2
- var queue = observer.takeRecords();
- // 2.3. Remove all transient registered observers whose observer is mo.
- removeTransientObserversFor(observer);
-
- // 2.4
- if (queue.length) {
- observer.callback_(queue, observer);
- anyNonEmpty = true;
- }
- });
-
- // 3.
- if (anyNonEmpty)
- dispatchCallbacks();
- }
-
- function removeTransientObserversFor(observer) {
- observer.nodes_.forEach(function(node) {
- var registrations = registrationsTable.get(node);
- if (!registrations)
- return;
- registrations.forEach(function(registration) {
- if (registration.observer === observer)
- registration.removeTransientObservers();
- });
- });
- }
-
- /**
- * This function is used for the "For each registered observer observer (with
- * observer's options as options) in target's list of registered observers,
- * run these substeps:" and the "For each ancestor ancestor of target, and for
- * each registered observer observer (with options options) in ancestor's list
- * of registered observers, run these substeps:" part of the algorithms. The
- * |options.subtree| is checked to ensure that the callback is called
- * correctly.
- *
- * @param {Node} target
- * @param {function(MutationObserverInit):MutationRecord} callback
- */
- function forEachAncestorAndObserverEnqueueRecord(target, callback) {
- for (var node = target; node; node = node.parentNode) {
- var registrations = registrationsTable.get(node);
-
- if (registrations) {
- for (var j = 0; j < registrations.length; j++) {
- var registration = registrations[j];
- var options = registration.options;
-
- // Only target ignores subtree.
- if (node !== target && !options.subtree)
- continue;
-
- var record = callback(options);
- if (record)
- registration.enqueue(record);
- }
- }
- }
- }
-
- var uidCounter = 0;
-
- /**
- * The class that maps to the DOM MutationObserver interface.
- * @param {Function} callback.
- * @constructor
- */
- function JsMutationObserver(callback) {
- this.callback_ = callback;
- this.nodes_ = [];
- this.records_ = [];
- this.uid_ = ++uidCounter;
- }
-
- JsMutationObserver.prototype = {
- observe: function(target, options) {
- target = wrapIfNeeded(target);
-
- // 1.1
- if (!options.childList && !options.attributes && !options.characterData ||
-
- // 1.2
- options.attributeOldValue && !options.attributes ||
-
- // 1.3
- options.attributeFilter && options.attributeFilter.length &&
- !options.attributes ||
-
- // 1.4
- options.characterDataOldValue && !options.characterData) {
-
- throw new SyntaxError();
- }
-
- var registrations = registrationsTable.get(target);
- if (!registrations)
- registrationsTable.set(target, registrations = []);
-
- // 2
- // If target's list of registered observers already includes a registered
- // observer associated with the context object, replace that registered
- // observer's options with options.
- var registration;
- for (var i = 0; i < registrations.length; i++) {
- if (registrations[i].observer === this) {
- registration = registrations[i];
- registration.removeListeners();
- registration.options = options;
- break;
- }
- }
-
- // 3.
- // Otherwise, add a new registered observer to target's list of registered
- // observers with the context object as the observer and options as the
- // options, and add target to context object's list of nodes on which it
- // is registered.
- if (!registration) {
- registration = new Registration(this, target, options);
- registrations.push(registration);
- this.nodes_.push(target);
- }
-
- registration.addListeners();
- },
-
- disconnect: function() {
- this.nodes_.forEach(function(node) {
- var registrations = registrationsTable.get(node);
- for (var i = 0; i < registrations.length; i++) {
- var registration = registrations[i];
- if (registration.observer === this) {
- registration.removeListeners();
- registrations.splice(i, 1);
- // Each node can only have one registered observer associated with
- // this observer.
- break;
- }
- }
- }, this);
- this.records_ = [];
- },
-
- takeRecords: function() {
- var copyOfRecords = this.records_;
- this.records_ = [];
- return copyOfRecords;
- }
- };
-
- /**
- * @param {string} type
- * @param {Node} target
- * @constructor
- */
- function MutationRecord(type, target) {
- this.type = type;
- this.target = target;
- this.addedNodes = [];
- this.removedNodes = [];
- this.previousSibling = null;
- this.nextSibling = null;
- this.attributeName = null;
- this.attributeNamespace = null;
- this.oldValue = null;
- }
-
- function copyMutationRecord(original) {
- var record = new MutationRecord(original.type, original.target);
- record.addedNodes = original.addedNodes.slice();
- record.removedNodes = original.removedNodes.slice();
- record.previousSibling = original.previousSibling;
- record.nextSibling = original.nextSibling;
- record.attributeName = original.attributeName;
- record.attributeNamespace = original.attributeNamespace;
- record.oldValue = original.oldValue;
- return record;
- };
-
- // We keep track of the two (possibly one) records used in a single mutation.
- var currentRecord, recordWithOldValue;
-
- /**
- * Creates a record without |oldValue| and caches it as |currentRecord| for
- * later use.
- * @param {string} oldValue
- * @return {MutationRecord}
- */
- function getRecord(type, target) {
- return currentRecord = new MutationRecord(type, target);
- }
-
- /**
- * Gets or creates a record with |oldValue| based in the |currentRecord|
- * @param {string} oldValue
- * @return {MutationRecord}
- */
- function getRecordWithOldValue(oldValue) {
- if (recordWithOldValue)
- return recordWithOldValue;
- recordWithOldValue = copyMutationRecord(currentRecord);
- recordWithOldValue.oldValue = oldValue;
- return recordWithOldValue;
- }
-
- function clearRecords() {
- currentRecord = recordWithOldValue = undefined;
- }
-
- /**
- * @param {MutationRecord} record
- * @return {boolean} Whether the record represents a record from the current
- * mutation event.
- */
- function recordRepresentsCurrentMutation(record) {
- return record === recordWithOldValue || record === currentRecord;
- }
-
- /**
- * Selects which record, if any, to replace the last record in the queue.
- * This returns |null| if no record should be replaced.
- *
- * @param {MutationRecord} lastRecord
- * @param {MutationRecord} newRecord
- * @param {MutationRecord}
- */
- function selectRecord(lastRecord, newRecord) {
- if (lastRecord === newRecord)
- return lastRecord;
-
- // Check if the the record we are adding represents the same record. If
- // so, we keep the one with the oldValue in it.
- if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
- return recordWithOldValue;
-
- return null;
- }
-
- /**
- * Class used to represent a registered observer.
- * @param {MutationObserver} observer
- * @param {Node} target
- * @param {MutationObserverInit} options
- * @constructor
- */
- function Registration(observer, target, options) {
- this.observer = observer;
- this.target = target;
- this.options = options;
- this.transientObservedNodes = [];
- }
-
- Registration.prototype = {
- enqueue: function(record) {
- var records = this.observer.records_;
- var length = records.length;
-
- // There are cases where we replace the last record with the new record.
- // For example if the record represents the same mutation we need to use
- // the one with the oldValue. If we get same record (this can happen as we
- // walk up the tree) we ignore the new record.
- if (records.length > 0) {
- var lastRecord = records[length - 1];
- var recordToReplaceLast = selectRecord(lastRecord, record);
- if (recordToReplaceLast) {
- records[length - 1] = recordToReplaceLast;
- return;
- }
- } else {
- scheduleCallback(this.observer);
- }
-
- records[length] = record;
- },
-
- addListeners: function() {
- this.addListeners_(this.target);
- },
-
- addListeners_: function(node) {
- var options = this.options;
- if (options.attributes)
- node.addEventListener('DOMAttrModified', this, true);
-
- if (options.characterData)
- node.addEventListener('DOMCharacterDataModified', this, true);
-
- if (options.childList)
- node.addEventListener('DOMNodeInserted', this, true);
-
- if (options.childList || options.subtree)
- node.addEventListener('DOMNodeRemoved', this, true);
- },
-
- removeListeners: function() {
- this.removeListeners_(this.target);
- },
-
- removeListeners_: function(node) {
- var options = this.options;
- if (options.attributes)
- node.removeEventListener('DOMAttrModified', this, true);
-
- if (options.characterData)
- node.removeEventListener('DOMCharacterDataModified', this, true);
-
- if (options.childList)
- node.removeEventListener('DOMNodeInserted', this, true);
-
- if (options.childList || options.subtree)
- node.removeEventListener('DOMNodeRemoved', this, true);
- },
-
- /**
- * Adds a transient observer on node. The transient observer gets removed
- * next time we deliver the change records.
- * @param {Node} node
- */
- addTransientObserver: function(node) {
- // Don't add transient observers on the target itself. We already have all
- // the required listeners set up on the target.
- if (node === this.target)
- return;
-
- this.addListeners_(node);
- this.transientObservedNodes.push(node);
- var registrations = registrationsTable.get(node);
- if (!registrations)
- registrationsTable.set(node, registrations = []);
-
- // We know that registrations does not contain this because we already
- // checked if node === this.target.
- registrations.push(this);
- },
-
- removeTransientObservers: function() {
- var transientObservedNodes = this.transientObservedNodes;
- this.transientObservedNodes = [];
-
- transientObservedNodes.forEach(function(node) {
- // Transient observers are never added to the target.
- this.removeListeners_(node);
-
- var registrations = registrationsTable.get(node);
- for (var i = 0; i < registrations.length; i++) {
- if (registrations[i] === this) {
- registrations.splice(i, 1);
- // Each node can only have one registered observer associated with
- // this observer.
- break;
- }
- }
- }, this);
- },
-
- handleEvent: function(e) {
- // Stop propagation since we are managing the propagation manually.
- // This means that other mutation events on the page will not work
- // correctly but that is by design.
- e.stopImmediatePropagation();
-
- switch (e.type) {
- case 'DOMAttrModified':
- // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
-
- var name = e.attrName;
- var namespace = e.relatedNode.namespaceURI;
- var target = e.target;
-
- // 1.
- var record = new getRecord('attributes', target);
- record.attributeName = name;
- record.attributeNamespace = namespace;
-
- // 2.
- var oldValue =
- e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
-
- forEachAncestorAndObserverEnqueueRecord(target, function(options) {
- // 3.1, 4.2
- if (!options.attributes)
- return;
-
- // 3.2, 4.3
- if (options.attributeFilter && options.attributeFilter.length &&
- options.attributeFilter.indexOf(name) === -1 &&
- options.attributeFilter.indexOf(namespace) === -1) {
- return;
- }
- // 3.3, 4.4
- if (options.attributeOldValue)
- return getRecordWithOldValue(oldValue);
-
- // 3.4, 4.5
- return record;
- });
-
- break;
-
- case 'DOMCharacterDataModified':
- // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
- var target = e.target;
-
- // 1.
- var record = getRecord('characterData', target);
-
- // 2.
- var oldValue = e.prevValue;
-
-
- forEachAncestorAndObserverEnqueueRecord(target, function(options) {
- // 3.1, 4.2
- if (!options.characterData)
- return;
-
- // 3.2, 4.3
- if (options.characterDataOldValue)
- return getRecordWithOldValue(oldValue);
-
- // 3.3, 4.4
- return record;
- });
-
- break;
-
- case 'DOMNodeRemoved':
- this.addTransientObserver(e.target);
- // Fall through.
- case 'DOMNodeInserted':
- // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
- var target = e.relatedNode;
- var changedNode = e.target;
- var addedNodes, removedNodes;
- if (e.type === 'DOMNodeInserted') {
- addedNodes = [changedNode];
- removedNodes = [];
- } else {
-
- addedNodes = [];
- removedNodes = [changedNode];
- }
- var previousSibling = changedNode.previousSibling;
- var nextSibling = changedNode.nextSibling;
-
- // 1.
- var record = getRecord('childList', target);
- record.addedNodes = addedNodes;
- record.removedNodes = removedNodes;
- record.previousSibling = previousSibling;
- record.nextSibling = nextSibling;
-
- forEachAncestorAndObserverEnqueueRecord(target, function(options) {
- // 2.1, 3.2
- if (!options.childList)
- return;
-
- // 2.2, 3.3
- return record;
- });
-
- }
-
- clearRecords();
- }
- };
-
- global.JsMutationObserver = JsMutationObserver;
-
- if (!global.MutationObserver)
- global.MutationObserver = JsMutationObserver;
-
-
-})(this);
-
-/*
- * 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.
- */
-window.HTMLImports = window.HTMLImports || {flags:{}};
-/*
- * 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) {
-
- // imports
- var path = scope.path;
- var xhr = scope.xhr;
- var flags = scope.flags;
-
- // TODO(sorvell): this loader supports a dynamic list of urls
- // and an oncomplete callback that is called when the loader is done.
- // The polyfill currently does *not* need this dynamism or the onComplete
- // concept. Because of this, the loader could be simplified quite a bit.
- var Loader = function(onLoad, onComplete) {
- this.cache = {};
- this.onload = onLoad;
- this.oncomplete = onComplete;
- this.inflight = 0;
- this.pending = {};
- };
-
- Loader.prototype = {
- addNodes: function(nodes) {
- // number of transactions to complete
- this.inflight += nodes.length;
- // commence transactions
- for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
- this.require(n);
- }
- // anything to do?
- this.checkDone();
- },
- addNode: function(node) {
- // number of transactions to complete
- this.inflight++;
- // commence transactions
- this.require(node);
- // anything to do?
- this.checkDone();
- },
- require: function(elt) {
- var url = elt.src || elt.href;
- // ensure we have a standard url that can be used
- // reliably for deduping.
- // TODO(sjmiles): ad-hoc
- elt.__nodeUrl = url;
- // deduplication
- if (!this.dedupe(url, elt)) {
- // fetch this resource
- this.fetch(url, elt);
- }
- },
- dedupe: function(url, elt) {
- if (this.pending[url]) {
- // add to list of nodes waiting for inUrl
- this.pending[url].push(elt);
- // don't need fetch
- return true;
- }
- var resource;
- if (this.cache[url]) {
- this.onload(url, elt, this.cache[url]);
- // finished this transaction
- this.tail();
- // don't need fetch
- return true;
- }
- // first node waiting for inUrl
- this.pending[url] = [elt];
- // need fetch (not a dupe)
- return false;
- },
- fetch: function(url, elt) {
- flags.load && console.log('fetch', url, elt);
- if (url.match(/^data:/)) {
- // Handle Data URI Scheme
- var pieces = url.split(',');
- var header = pieces[0];
- var body = pieces[1];
- if(header.indexOf(';base64') > -1) {
- body = atob(body);
- } else {
- body = decodeURIComponent(body);
- }
- setTimeout(function() {
- this.receive(url, elt, null, body);
- }.bind(this), 0);
- } else {
- var receiveXhr = function(err, resource) {
- this.receive(url, elt, err, resource);
- }.bind(this);
- xhr.load(url, receiveXhr);
- // TODO(sorvell): blocked on)
- // https://code.google.com/p/chromium/issues/detail?id=257221
- // xhr'ing for a document makes scripts in imports runnable; otherwise
- // they are not; however, it requires that we have doctype=html in
- // the import which is unacceptable. This is only needed on Chrome
- // to avoid the bug above.
- /*
- if (isDocumentLink(elt)) {
- xhr.loadDocument(url, receiveXhr);
- } else {
- xhr.load(url, receiveXhr);
- }
- */
- }
- },
- receive: function(url, elt, err, resource) {
- this.cache[url] = resource;
- var $p = this.pending[url];
- for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) {
- //if (!err) {
- this.onload(url, p, resource);
- //}
- this.tail();
- }
- this.pending[url] = null;
- },
- tail: function() {
- --this.inflight;
- this.checkDone();
- },
- checkDone: function() {
- if (!this.inflight) {
- this.oncomplete();
- }
- }
- };
-
- xhr = xhr || {
- async: true,
- ok: function(request) {
- return (request.status >= 200 && request.status < 300)
- || (request.status === 304)
- || (request.status === 0);
- },
- load: function(url, next, nextContext) {
- var request = new XMLHttpRequest();
- if (scope.flags.debug || scope.flags.bust) {
- url += '?' + Math.random();
- }
- request.open('GET', url, xhr.async);
- request.addEventListener('readystatechange', function(e) {
- if (request.readyState === 4) {
- next.call(nextContext, !xhr.ok(request) && request,
- request.response || request.responseText, url);
- }
- });
- request.send();
- return request;
- },
- loadDocument: function(url, next, nextContext) {
- this.load(url, next, nextContext).responseType = 'document';
- }
- };
-
- // exports
- scope.xhr = xhr;
- scope.Loader = Loader;
-
-})(window.HTMLImports);
-
-/*
- * 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) {
-
-var IMPORT_LINK_TYPE = 'import';
-var flags = scope.flags;
-var isIe = /Trident/.test(navigator.userAgent);
-// TODO(sorvell): SD polyfill intrusion
-var mainDoc = window.ShadowDOMPolyfill ?
- window.ShadowDOMPolyfill.wrapIfNeeded(document) : document;
-
-// importParser
-// highlander object to manage parsing of imports
-// parses import related elements
-// and ensures proper parse order
-// parse order is enforced by crawling the tree and monitoring which elements
-// have been parsed; async parsing is also supported.
-
-// highlander object for parsing a document tree
-var importParser = {
- // parse selectors for main document elements
- documentSelectors: 'link[rel=' + IMPORT_LINK_TYPE + ']',
- // parse selectors for import document elements
- importsSelectors: [
- 'link[rel=' + IMPORT_LINK_TYPE + ']',
- 'link[rel=stylesheet]',
- 'style',
- 'script:not([type])',
- 'script[type="text/javascript"]'
- ].join(','),
- map: {
- link: 'parseLink',
- script: 'parseScript',
- style: 'parseStyle'
- },
- // try to parse the next import in the tree
- parseNext: function() {
- var next = this.nextToParse();
- if (next) {
- this.parse(next);
- }
- },
- parse: function(elt) {
- if (this.isParsed(elt)) {
- flags.parse && console.log('[%s] is already parsed', elt.localName);
- return;
- }
- var fn = this[this.map[elt.localName]];
- if (fn) {
- this.markParsing(elt);
- fn.call(this, elt);
- }
- },
- // only 1 element may be parsed at a time; parsing is async so, each
- // parsing implementation must inform the system that parsing is complete
- // via markParsingComplete.
- markParsing: function(elt) {
- flags.parse && console.log('parsing', elt);
- this.parsingElement = elt;
- },
- markParsingComplete: function(elt) {
- elt.__importParsed = true;
- if (elt.__importElement) {
- elt.__importElement.__importParsed = true;
- }
- this.parsingElement = null;
- flags.parse && console.log('completed', elt);
- this.parseNext();
- },
- parseImport: function(elt) {
- elt.import.__importParsed = true;
- // TODO(sorvell): consider if there's a better way to do this;
- // expose an imports parsing hook; this is needed, for example, by the
- // CustomElements polyfill.
- if (HTMLImports.__importsParsingHook) {
- HTMLImports.__importsParsingHook(elt);
- }
- // fire load event
- if (elt.__resource) {
- elt.dispatchEvent(new CustomEvent('load', {bubbles: false}));
- } else {
- elt.dispatchEvent(new CustomEvent('error', {bubbles: false}));
- }
- // TODO(sorvell): workaround for Safari addEventListener not working
- // for elements not in the main document.
- if (elt.__pending) {
- var fn;
- while (elt.__pending.length) {
- fn = elt.__pending.shift();
- if (fn) {
- fn({target: elt});
- }
- }
- }
- this.markParsingComplete(elt);
- },
- parseLink: function(linkElt) {
- if (nodeIsImport(linkElt)) {
- this.parseImport(linkElt);
- } else {
- // make href absolute
- linkElt.href = linkElt.href;
- this.parseGeneric(linkElt);
- }
- },
- parseStyle: function(elt) {
- // TODO(sorvell): style element load event can just not fire so clone styles
- var src = elt;
- elt = cloneStyle(elt);
- elt.__importElement = src;
- this.parseGeneric(elt);
- },
- parseGeneric: function(elt) {
- this.trackElement(elt);
- document.head.appendChild(elt);
- },
- // tracks when a loadable element has loaded
- trackElement: function(elt, callback) {
- var self = this;
- var done = function(e) {
- if (callback) {
- callback(e);
- }
- self.markParsingComplete(elt);
- };
- elt.addEventListener('load', done);
- elt.addEventListener('error', done);
-
- // NOTE: IE does not fire "load" event for styles that have already loaded
- // This is in violation of the spec, so we try our hardest to work around it
- if (isIe && elt.localName === 'style') {
- var fakeLoad = false;
- // If there's not @import in the textContent, assume it has loaded
- if (elt.textContent.indexOf('@import') == -1) {
- fakeLoad = true;
- // if we have a sheet, we have been parsed
- } else if (elt.sheet) {
- fakeLoad = true;
- var csr = elt.sheet.cssRules;
- var len = csr ? csr.length : 0;
- // search the rules for @import's
- for (var i = 0, r; (i < len) && (r = csr[i]); i++) {
- if (r.type === CSSRule.IMPORT_RULE) {
- // if every @import has resolved, fake the load
- fakeLoad = fakeLoad && Boolean(r.styleSheet);
- }
- }
- }
- // dispatch a fake load event and continue parsing
- if (fakeLoad) {
- elt.dispatchEvent(new CustomEvent('load', {bubbles: false}));
- }
- }
- },
- // NOTE: execute scripts by injecting them and watching for the load/error
- // event. Inline scripts are handled via dataURL's because browsers tend to
- // provide correct parsing errors in this case. If this has any compatibility
- // issues, we can switch to injecting the inline script with textContent.
- // Scripts with dataURL's do not appear to generate load events and therefore
- // we assume they execute synchronously.
- parseScript: function(scriptElt) {
- var script = document.createElement('script');
- script.__importElement = scriptElt;
- script.src = scriptElt.src ? scriptElt.src :
- generateScriptDataUrl(scriptElt);
- scope.currentScript = scriptElt;
- this.trackElement(script, function(e) {
- script.parentNode.removeChild(script);
- scope.currentScript = null;
- });
- document.head.appendChild(script);
- },
- // determine the next element in the tree which should be parsed
- nextToParse: function() {
- return !this.parsingElement && this.nextToParseInDoc(mainDoc);
- },
- nextToParseInDoc: function(doc, link) {
- var nodes = doc.querySelectorAll(this.parseSelectorsForNode(doc));
- for (var i=0, l=nodes.length, p=0, n; (i<l) && (n=nodes[i]); i++) {
- if (!this.isParsed(n)) {
- if (this.hasResource(n)) {
- return nodeIsImport(n) ? this.nextToParseInDoc(n.import, n) : n;
- } else {
- return;
- }
- }
- }
- // all nodes have been parsed, ready to parse import, if any
- return link;
- },
- // return the set of parse selectors relevant for this node.
- parseSelectorsForNode: function(node) {
- var doc = node.ownerDocument || node;
- return doc === mainDoc ? this.documentSelectors : this.importsSelectors;
- },
- isParsed: function(node) {
- return node.__importParsed;
- },
- hasResource: function(node) {
- if (nodeIsImport(node) && !node.import) {
- return false;
- }
- return true;
- }
-};
-
-function nodeIsImport(elt) {
- return (elt.localName === 'link') && (elt.rel === IMPORT_LINK_TYPE);
-}
-
-function generateScriptDataUrl(script) {
- var scriptContent = generateScriptContent(script), b64;
- try {
- b64 = btoa(scriptContent);
- } catch(e) {
- b64 = btoa(unescape(encodeURIComponent(scriptContent)));
- console.warn('Script contained non-latin characters that were forced ' +
- 'to latin. Some characters may be wrong.', script);
- }
- return 'data:text/javascript;base64,' + b64;
-}
-
-function generateScriptContent(script) {
- return script.textContent + generateSourceMapHint(script);
-}
-
-// calculate source map hint
-function generateSourceMapHint(script) {
- var moniker = script.__nodeUrl;
- if (!moniker) {
- moniker = script.ownerDocument.baseURI;
- // there could be more than one script this url
- var tag = '[' + Math.floor((Math.random()+1)*1000) + ']';
- // TODO(sjmiles): Polymer hack, should be pluggable if we need to allow
- // this sort of thing
- var matches = script.textContent.match(/Polymer\(['"]([^'"]*)/);
- tag = matches && matches[1] || tag;
- // tag the moniker
- moniker += '/' + tag + '.js';
- }
- return '\n//# sourceURL=' + moniker + '\n';
-}
-
-// style/stylesheet handling
-
-// clone style with proper path resolution for main document
-// NOTE: styles are the only elements that require direct path fixup.
-function cloneStyle(style) {
- var clone = style.ownerDocument.createElement('style');
- clone.textContent = style.textContent;
- path.resolveUrlsInStyle(clone);
- return clone;
-}
-
-// path fixup: style elements in imports must be made relative to the main
-// document. We fixup url's in url() and @import.
-var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
-var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
-
-var path = {
- resolveUrlsInStyle: function(style) {
- var doc = style.ownerDocument;
- var resolver = doc.createElement('a');
- style.textContent = this.resolveUrlsInCssText(style.textContent, resolver);
- return style;
- },
- resolveUrlsInCssText: function(cssText, urlObj) {
- var r = this.replaceUrls(cssText, urlObj, CSS_URL_REGEXP);
- r = this.replaceUrls(r, urlObj, CSS_IMPORT_REGEXP);
- return r;
- },
- replaceUrls: function(text, urlObj, regexp) {
- return text.replace(regexp, function(m, pre, url, post) {
- var urlPath = url.replace(/["']/g, '');
- urlObj.href = urlPath;
- urlPath = urlObj.href;
- return pre + '\'' + urlPath + '\'' + post;
- });
- }
-}
-
-// exports
-scope.parser = importParser;
-scope.path = path;
-scope.isIE = isIe;
-
-})(HTMLImports);
-
-/*
- * 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) {
-
-var hasNative = ('import' in document.createElement('link'));
-var useNative = hasNative;
-var flags = scope.flags;
-var IMPORT_LINK_TYPE = 'import';
-
-// TODO(sorvell): SD polyfill intrusion
-var mainDoc = window.ShadowDOMPolyfill ?
- ShadowDOMPolyfill.wrapIfNeeded(document) : document;
-
-if (!useNative) {
-
- // imports
- var xhr = scope.xhr;
- var Loader = scope.Loader;
- var parser = scope.parser;
-
- // importer
- // highlander object to manage loading of imports
-
- // for any document, importer:
- // - loads any linked import documents (with deduping)
-
- var importer = {
- documents: {},
- // nodes to load in the mian document
- documentPreloadSelectors: 'link[rel=' + IMPORT_LINK_TYPE + ']',
- // nodes to load in imports
- importsPreloadSelectors: [
- 'link[rel=' + IMPORT_LINK_TYPE + ']'
- ].join(','),
- loadNode: function(node) {
- importLoader.addNode(node);
- },
- // load all loadable elements within the parent element
- loadSubtree: function(parent) {
- var nodes = this.marshalNodes(parent);
- // add these nodes to loader's queue
- importLoader.addNodes(nodes);
- },
- marshalNodes: function(parent) {
- // all preloadable nodes in inDocument
- return parent.querySelectorAll(this.loadSelectorsForNode(parent));
- },
- // find the proper set of load selectors for a given node
- loadSelectorsForNode: function(node) {
- var doc = node.ownerDocument || node;
- return doc === mainDoc ? this.documentPreloadSelectors :
- this.importsPreloadSelectors;
- },
- loaded: function(url, elt, resource) {
- flags.load && console.log('loaded', url, elt);
- // store generic resource
- // TODO(sorvell): fails for nodes inside <template>.content
- // see https://code.google.com/p/chromium/issues/detail?id=249381.
- elt.__resource = resource;
- if (isDocumentLink(elt)) {
- var doc = this.documents[url];
- // if we've never seen a document at this url
- if (!doc) {
- // generate an HTMLDocument from data
- doc = makeDocument(resource, url);
- doc.__importLink = elt;
- // TODO(sorvell): we cannot use MO to detect parsed nodes because
- // SD polyfill does not report these as mutations.
- this.bootDocument(doc);
- // cache document
- this.documents[url] = doc;
- }
- // don't store import record until we're actually loaded
- // store document resource
- elt.import = doc;
- }
- parser.parseNext();
- },
- bootDocument: function(doc) {
- this.loadSubtree(doc);
- this.observe(doc);
- parser.parseNext();
- },
- loadedAll: function() {
- parser.parseNext();
- }
- };
-
- // loader singleton
- var importLoader = new Loader(importer.loaded.bind(importer),
- importer.loadedAll.bind(importer));
-
- function isDocumentLink(elt) {
- return isLinkRel(elt, IMPORT_LINK_TYPE);
- }
-
- function isLinkRel(elt, rel) {
- return elt.localName === 'link' && elt.getAttribute('rel') === rel;
- }
-
- function isScript(elt) {
- return elt.localName === 'script';
- }
-
- function makeDocument(resource, url) {
- // create a new HTML document
- var doc = resource;
- if (!(doc instanceof Document)) {
- doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE);
- }
- // cache the new document's source url
- doc._URL = url;
- // establish a relative path via <base>
- var base = doc.createElement('base');
- base.setAttribute('href', url);
- // add baseURI support to browsers (IE) that lack it.
- if (!doc.baseURI) {
- doc.baseURI = url;
- }
- // ensure UTF-8 charset
- var meta = doc.createElement('meta');
- meta.setAttribute('charset', 'utf-8');
-
- doc.head.appendChild(meta);
- doc.head.appendChild(base);
- // install HTML last as it may trigger CustomElement upgrades
- // TODO(sjmiles): problem wrt to template boostrapping below,
- // template bootstrapping must (?) come before element upgrade
- // but we cannot bootstrap templates until they are in a document
- // which is too late
- if (!(resource instanceof Document)) {
- // install html
- doc.body.innerHTML = resource;
- }
- // TODO(sorvell): ideally this code is not aware of Template polyfill,
- // but for now the polyfill needs help to bootstrap these templates
- if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
- HTMLTemplateElement.bootstrap(doc);
- }
- return doc;
- }
-} else {
- // do nothing if using native imports
- var importer = {};
-}
-
-// NOTE: We cannot polyfill document.currentScript because it's not possible
-// both to override and maintain the ability to capture the native value;
-// therefore we choose to expose _currentScript both when native imports
-// and the polyfill are in use.
-var currentScriptDescriptor = {
- get: function() {
- return HTMLImports.currentScript || document.currentScript;
- },
- configurable: true
-};
-
-Object.defineProperty(document, '_currentScript', currentScriptDescriptor);
-Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor);
-
-// Polyfill document.baseURI for browsers without it.
-if (!document.baseURI) {
- var baseURIDescriptor = {
- get: function() {
- return window.location.href;
- },
- configurable: true
- };
-
- Object.defineProperty(document, 'baseURI', baseURIDescriptor);
- Object.defineProperty(mainDoc, 'baseURI', baseURIDescriptor);
-}
-
-// call a callback when all HTMLImports in the document at call (or at least
-// document ready) time have loaded.
-// 1. ensure the document is in a ready state (has dom), then
-// 2. watch for loading of imports and call callback when done
-function whenImportsReady(callback, doc) {
- doc = doc || mainDoc;
- // if document is loading, wait and try again
- whenDocumentReady(function() {
- watchImportsLoad(callback, doc);
- }, doc);
-}
-
-// call the callback when the document is in a ready state (has dom)
-var requiredReadyState = HTMLImports.isIE ? 'complete' : 'interactive';
-var READY_EVENT = 'readystatechange';
-function isDocumentReady(doc) {
- return (doc.readyState === 'complete' ||
- doc.readyState === requiredReadyState);
-}
-
-// call <callback> when we ensure the document is in a ready state
-function whenDocumentReady(callback, doc) {
- if (!isDocumentReady(doc)) {
- var checkReady = function() {
- if (doc.readyState === 'complete' ||
- doc.readyState === requiredReadyState) {
- doc.removeEventListener(READY_EVENT, checkReady);
- whenDocumentReady(callback, doc);
- }
- }
- doc.addEventListener(READY_EVENT, checkReady);
- } else if (callback) {
- callback();
- }
-}
-
-// call <callback> when we ensure all imports have loaded
-function watchImportsLoad(callback, doc) {
- var imports = doc.querySelectorAll('link[rel=import]');
- var loaded = 0, l = imports.length;
- function checkDone(d) {
- if (loaded == l) {
- // go async to ensure parser isn't stuck on a script tag
- requestAnimationFrame(callback);
- }
- }
- function loadedImport(e) {
- loaded++;
- checkDone();
- }
- if (l) {
- for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
- if (isImportLoaded(imp)) {
- loadedImport.call(imp);
- } else {
- imp.addEventListener('load', loadedImport);
- imp.addEventListener('error', loadedImport);
- }
- }
- } else {
- checkDone();
- }
-}
-
-function isImportLoaded(link) {
- return useNative ? (link.import && (link.import.readyState !== 'loading')) :
- link.__importParsed;
-}
-
-// exports
-scope.hasNative = hasNative;
-scope.useNative = useNative;
-scope.importer = importer;
-scope.whenImportsReady = whenImportsReady;
-scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
-scope.isImportLoaded = isImportLoaded;
-scope.importLoader = importLoader;
-
-})(window.HTMLImports);
-
- /*
-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){
-
-var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
-var importSelector = 'link[rel=' + IMPORT_LINK_TYPE + ']';
-var importer = scope.importer;
-
-// we track mutations for addedNodes, looking for imports
-function handler(mutations) {
- for (var i=0, l=mutations.length, m; (i<l) && (m=mutations[i]); i++) {
- if (m.type === 'childList' && m.addedNodes.length) {
- addedNodes(m.addedNodes);
- }
- }
-}
-
-// find loadable elements and add them to the importer
-function addedNodes(nodes) {
- for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
- if (shouldLoadNode(n)) {
- importer.loadNode(n);
- }
- if (n.children && n.children.length) {
- addedNodes(n.children);
- }
- }
-}
-
-function shouldLoadNode(node) {
- return (node.nodeType === 1) && matches.call(node,
- importer.loadSelectorsForNode(node));
-}
-
-// x-plat matches
-var matches = HTMLElement.prototype.matches ||
- HTMLElement.prototype.matchesSelector ||
- HTMLElement.prototype.webkitMatchesSelector ||
- HTMLElement.prototype.mozMatchesSelector ||
- HTMLElement.prototype.msMatchesSelector;
-
-var observer = new MutationObserver(handler);
-
-// observe the given root for loadable elements
-function observe(root) {
- observer.observe(root, {childList: true, subtree: true});
-}
-
-// exports
-// TODO(sorvell): factor so can put on scope
-scope.observe = observe;
-importer.observe = observe;
-
-})(HTMLImports);
-
-/*
- * 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(){
-
-// bootstrap
-
-// IE shim for CustomEvent
-if (typeof window.CustomEvent !== 'function') {
- window.CustomEvent = function(inType, dictionary) {
- var e = document.createEvent('HTMLEvents');
- e.initEvent(inType,
- dictionary.bubbles === false ? false : true,
- dictionary.cancelable === false ? false : true,
- dictionary.detail);
- return e;
- };
-}
-
-// TODO(sorvell): SD polyfill intrusion
-var doc = window.ShadowDOMPolyfill ?
- window.ShadowDOMPolyfill.wrapIfNeeded(document) : document;
-
-// Fire the 'HTMLImportsLoaded' event when imports in document at load time
-// have loaded. This event is required to simulate the script blocking
-// behavior of native imports. A main document script that needs to be sure
-// imports have loaded should wait for this event.
-HTMLImports.whenImportsReady(function() {
- HTMLImports.ready = true;
- HTMLImports.readyTime = new Date().getTime();
- doc.dispatchEvent(
- new CustomEvent('HTMLImportsLoaded', {bubbles: true})
- );
-});
-
-
-// no need to bootstrap the polyfill when native imports is available.
-if (!HTMLImports.useNative) {
- function bootstrap() {
- HTMLImports.importer.bootDocument(doc);
- }
-
- // TODO(sorvell): SD polyfill does *not* generate mutations for nodes added
- // by the parser. For this reason, we must wait until the dom exists to
- // bootstrap.
- if (document.readyState === 'complete' ||
- (document.readyState === 'interactive' && !window.attachEvent)) {
- bootstrap();
- } else {
- document.addEventListener('DOMContentLoaded', bootstrap);
- }
-}
-
-})();
-
-/*
- * 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.
- */
-window.CustomElements = window.CustomElements || {flags:{}};
- /*
-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){
-
-var logFlags = window.logFlags || {};
-var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : 'none';
-
-// walk the subtree rooted at node, applying 'find(element, data)' function
-// to each element
-// if 'find' returns true for 'element', do not search element's subtree
-function findAll(node, find, data) {
- var e = node.firstElementChild;
- if (!e) {
- e = node.firstChild;
- while (e && e.nodeType !== Node.ELEMENT_NODE) {
- e = e.nextSibling;
- }
- }
- while (e) {
- if (find(e, data) !== true) {
- findAll(e, find, data);
- }
- e = e.nextElementSibling;
- }
- return null;
-}
-
-// walk all shadowRoots on a given node.
-function forRoots(node, cb) {
- var root = node.shadowRoot;
- while(root) {
- forSubtree(root, cb);
- root = root.olderShadowRoot;
- }
-}
-
-// walk the subtree rooted at node, including descent into shadow-roots,
-// applying 'cb' to each element
-function forSubtree(node, cb) {
- //logFlags.dom && node.childNodes && node.childNodes.length && console.group('subTree: ', node);
- findAll(node, function(e) {
- if (cb(e)) {
- return true;
- }
- forRoots(e, cb);
- });
- forRoots(node, cb);
- //logFlags.dom && node.childNodes && node.childNodes.length && console.groupEnd();
-}
-
-// manage lifecycle on added node
-function added(node) {
- if (upgrade(node)) {
- insertedNode(node);
- return true;
- }
- inserted(node);
-}
-
-// manage lifecycle on added node's subtree only
-function addedSubtree(node) {
- forSubtree(node, function(e) {
- if (added(e)) {
- return true;
- }
- });
-}
-
-// manage lifecycle on added node and it's subtree
-function addedNode(node) {
- return added(node) || addedSubtree(node);
-}
-
-// upgrade custom elements at node, if applicable
-function upgrade(node) {
- if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
- var type = node.getAttribute('is') || node.localName;
- var definition = scope.registry[type];
- if (definition) {
- logFlags.dom && console.group('upgrade:', node.localName);
- scope.upgrade(node);
- logFlags.dom && console.groupEnd();
- return true;
- }
- }
-}
-
-function insertedNode(node) {
- inserted(node);
- if (inDocument(node)) {
- forSubtree(node, function(e) {
- inserted(e);
- });
- }
-}
-
-// TODO(sorvell): on platforms without MutationObserver, mutations may not be
-// reliable and therefore attached/detached are not reliable.
-// To make these callbacks less likely to fail, we defer all inserts and removes
-// to give a chance for elements to be inserted into dom.
-// This ensures attachedCallback fires for elements that are created and
-// immediately added to dom.
-var hasPolyfillMutations = (!window.MutationObserver ||
- (window.MutationObserver === window.JsMutationObserver));
-scope.hasPolyfillMutations = hasPolyfillMutations;
-
-var isPendingMutations = false;
-var pendingMutations = [];
-function deferMutation(fn) {
- pendingMutations.push(fn);
- if (!isPendingMutations) {
- isPendingMutations = true;
- var async = (window.Platform && window.Platform.endOfMicrotask) ||
- setTimeout;
- async(takeMutations);
- }
-}
-
-function takeMutations() {
- isPendingMutations = false;
- var $p = pendingMutations;
- for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) {
- p();
- }
- pendingMutations = [];
-}
-
-function inserted(element) {
- if (hasPolyfillMutations) {
- deferMutation(function() {
- _inserted(element);
- });
- } else {
- _inserted(element);
- }
-}
-
-// TODO(sjmiles): if there are descents into trees that can never have inDocument(*) true, fix this
-function _inserted(element) {
- // TODO(sjmiles): it's possible we were inserted and removed in the space
- // of one microtask, in which case we won't be 'inDocument' here
- // But there are other cases where we are testing for inserted without
- // specific knowledge of mutations, and must test 'inDocument' to determine
- // whether to call inserted
- // If we can factor these cases into separate code paths we can have
- // better diagnostics.
- // TODO(sjmiles): when logging, do work on all custom elements so we can
- // track behavior even when callbacks not defined
- //console.log('inserted: ', element.localName);
- if (element.attachedCallback || element.detachedCallback || (element.__upgraded__ && logFlags.dom)) {
- logFlags.dom && console.group('inserted:', element.localName);
- if (inDocument(element)) {
- element.__inserted = (element.__inserted || 0) + 1;
- // if we are in a 'removed' state, bluntly adjust to an 'inserted' state
- if (element.__inserted < 1) {
- element.__inserted = 1;
- }
- // if we are 'over inserted', squelch the callback
- if (element.__inserted > 1) {
- logFlags.dom && console.warn('inserted:', element.localName,
- 'insert/remove count:', element.__inserted)
- } else if (element.attachedCallback) {
- logFlags.dom && console.log('inserted:', element.localName);
- element.attachedCallback();
- }
- }
- logFlags.dom && console.groupEnd();
- }
-}
-
-function removedNode(node) {
- removed(node);
- forSubtree(node, function(e) {
- removed(e);
- });
-}
-
-function removed(element) {
- if (hasPolyfillMutations) {
- deferMutation(function() {
- _removed(element);
- });
- } else {
- _removed(element);
- }
-}
-
-function _removed(element) {
- // TODO(sjmiles): temporary: do work on all custom elements so we can track
- // behavior even when callbacks not defined
- if (element.attachedCallback || element.detachedCallback || (element.__upgraded__ && logFlags.dom)) {
- logFlags.dom && console.group('removed:', element.localName);
- if (!inDocument(element)) {
- element.__inserted = (element.__inserted || 0) - 1;
- // if we are in a 'inserted' state, bluntly adjust to an 'removed' state
- if (element.__inserted > 0) {
- element.__inserted = 0;
- }
- // if we are 'over removed', squelch the callback
- if (element.__inserted < 0) {
- logFlags.dom && console.warn('removed:', element.localName,
- 'insert/remove count:', element.__inserted)
- } else if (element.detachedCallback) {
- element.detachedCallback();
- }
- }
- logFlags.dom && console.groupEnd();
- }
-}
-
-// SD polyfill intrustion due mainly to the fact that 'document'
-// is not entirely wrapped
-function wrapIfNeeded(node) {
- return window.ShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node)
- : node;
-}
-
-function inDocument(element) {
- var p = element;
- var doc = wrapIfNeeded(document);
- while (p) {
- if (p == doc) {
- return true;
- }
- p = p.parentNode || p.host;
- }
-}
-
-function watchShadow(node) {
- if (node.shadowRoot && !node.shadowRoot.__watched) {
- logFlags.dom && console.log('watching shadow-root for: ', node.localName);
- // watch all unwatched roots...
- var root = node.shadowRoot;
- while (root) {
- watchRoot(root);
- root = root.olderShadowRoot;
- }
- }
-}
-
-function watchRoot(root) {
- if (!root.__watched) {
- observe(root);
- root.__watched = true;
- }
-}
-
-function handler(mutations) {
- //
- if (logFlags.dom) {
- var mx = mutations[0];
- if (mx && mx.type === 'childList' && mx.addedNodes) {
- if (mx.addedNodes) {
- var d = mx.addedNodes[0];
- while (d && d !== document && !d.host) {
- d = d.parentNode;
- }
- var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || '';
- u = u.split('/?').shift().split('/').pop();
- }
- }
- console.group('mutations (%d) [%s]', mutations.length, u || '');
- }
- //
- mutations.forEach(function(mx) {
- //logFlags.dom && console.group('mutation');
- if (mx.type === 'childList') {
- forEach(mx.addedNodes, function(n) {
- //logFlags.dom && console.log(n.localName);
- if (!n.localName) {
- return;
- }
- // nodes added may need lifecycle management
- addedNode(n);
- });
- // removed nodes may need lifecycle management
- forEach(mx.removedNodes, function(n) {
- //logFlags.dom && console.log(n.localName);
- if (!n.localName) {
- return;
- }
- removedNode(n);
- });
- }
- //logFlags.dom && console.groupEnd();
- });
- logFlags.dom && console.groupEnd();
-};
-
-var observer = new MutationObserver(handler);
-
-function takeRecords() {
- // TODO(sjmiles): ask Raf why we have to call handler ourselves
- handler(observer.takeRecords());
- takeMutations();
-}
-
-var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
-
-function observe(inRoot) {
- observer.observe(inRoot, {childList: true, subtree: true});
-}
-
-function observeDocument(doc) {
- observe(doc);
-}
-
-function upgradeDocument(doc) {
- logFlags.dom && console.group('upgradeDocument: ', (doc.baseURI).split('/').pop());
- addedNode(doc);
- logFlags.dom && console.groupEnd();
-}
-
-function upgradeDocumentTree(doc) {
- doc = wrapIfNeeded(doc);
- //console.log('upgradeDocumentTree: ', (doc.baseURI).split('/').pop());
- // upgrade contained imported documents
- var imports = doc.querySelectorAll('link[rel=' + IMPORT_LINK_TYPE + ']');
- for (var i=0, l=imports.length, n; (i<l) && (n=imports[i]); i++) {
- if (n.import && n.import.__parsed) {
- upgradeDocumentTree(n.import);
- }
- }
- upgradeDocument(doc);
-}
-
-// exports
-scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
-scope.watchShadow = watchShadow;
-scope.upgradeDocumentTree = upgradeDocumentTree;
-scope.upgradeAll = addedNode;
-scope.upgradeSubtree = addedSubtree;
-scope.insertedNode = insertedNode;
-
-scope.observeDocument = observeDocument;
-scope.upgradeDocument = upgradeDocument;
-
-scope.takeRecords = takeRecords;
-
-})(window.CustomElements);
-
-/*
- * 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.
- */
-
-/**
- * Implements `document.register`
- * @module CustomElements
-*/
-
-/**
- * Polyfilled extensions to the `document` object.
- * @class Document
-*/
-
-(function(scope) {
-
-// imports
-
-if (!scope) {
- scope = window.CustomElements = {flags:{}};
-}
-var flags = scope.flags;
-
-// native document.registerElement?
-
-var hasNative = Boolean(document.registerElement);
-// TODO(sorvell): See https://github.com/Polymer/polymer/issues/399
-// we'll address this by defaulting to CE polyfill in the presence of the SD
-// polyfill. This will avoid spamming excess attached/detached callbacks.
-// If there is a compelling need to run CE native with SD polyfill,
-// we'll need to fix this issue.
-var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill;
-
-if (useNative) {
-
- // stub
- var nop = function() {};
-
- // exports
- scope.registry = {};
- scope.upgradeElement = nop;
-
- scope.watchShadow = nop;
- scope.upgrade = nop;
- scope.upgradeAll = nop;
- scope.upgradeSubtree = nop;
- scope.observeDocument = nop;
- scope.upgradeDocument = nop;
- scope.upgradeDocumentTree = nop;
- scope.takeRecords = nop;
- scope.reservedTagList = [];
-
-} else {
-
- /**
- * Registers a custom tag name with the document.
- *
- * When a registered element is created, a `readyCallback` method is called
- * in the scope of the element. The `readyCallback` method can be specified on
- * either `options.prototype` or `options.lifecycle` with the latter taking
- * precedence.
- *
- * @method register
- * @param {String} name The tag name to register. Must include a dash ('-'),
- * for example 'x-component'.
- * @param {Object} options
- * @param {String} [options.extends]
- * (_off spec_) Tag name of an element to extend (or blank for a new
- * element). This parameter is not part of the specification, but instead
- * is a hint for the polyfill because the extendee is difficult to infer.
- * Remember that the input prototype must chain to the extended element's
- * prototype (or HTMLElement.prototype) regardless of the value of
- * `extends`.
- * @param {Object} options.prototype The prototype to use for the new
- * element. The prototype must inherit from HTMLElement.
- * @param {Object} [options.lifecycle]
- * Callbacks that fire at important phases in the life of the custom
- * element.
- *
- * @example
- * FancyButton = document.registerElement("fancy-button", {
- * extends: 'button',
- * prototype: Object.create(HTMLButtonElement.prototype, {
- * readyCallback: {
- * value: function() {
- * console.log("a fancy-button was created",
- * }
- * }
- * })
- * });
- * @return {Function} Constructor for the newly registered type.
- */
- function register(name, options) {
- //console.warn('document.registerElement("' + name + '", ', options, ')');
- // construct a defintion out of options
- // TODO(sjmiles): probably should clone options instead of mutating it
- var definition = options || {};
- if (!name) {
- // TODO(sjmiles): replace with more appropriate error (EricB can probably
- // offer guidance)
- throw new Error('document.registerElement: first argument `name` must not be empty');
- }
- if (name.indexOf('-') < 0) {
- // TODO(sjmiles): replace with more appropriate error (EricB can probably
- // offer guidance)
- throw new Error('document.registerElement: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
- }
- // prevent registering reserved names
- if (isReservedTag(name)) {
- throw new Error('Failed to execute \'registerElement\' on \'Document\': Registration failed for type \'' + String(name) + '\'. The type name is invalid.');
- }
- // elements may only be registered once
- if (getRegisteredDefinition(name)) {
- throw new Error('DuplicateDefinitionError: a type with name \'' + String(name) + '\' is already registered');
- }
- // must have a prototype, default to an extension of HTMLElement
- // TODO(sjmiles): probably should throw if no prototype, check spec
- if (!definition.prototype) {
- // TODO(sjmiles): replace with more appropriate error (EricB can probably
- // offer guidance)
- throw new Error('Options missing required prototype property');
- }
- // record name
- definition.__name = name.toLowerCase();
- // ensure a lifecycle object so we don't have to null test it
- definition.lifecycle = definition.lifecycle || {};
- // build a list of ancestral custom elements (for native base detection)
- // TODO(sjmiles): we used to need to store this, but current code only
- // uses it in 'resolveTagName': it should probably be inlined
- definition.ancestry = ancestry(definition.extends);
- // extensions of native specializations of HTMLElement require localName
- // to remain native, and use secondary 'is' specifier for extension type
- resolveTagName(definition);
- // some platforms require modifications to the user-supplied prototype
- // chain
- resolvePrototypeChain(definition);
- // overrides to implement attributeChanged callback
- overrideAttributeApi(definition.prototype);
- // 7.1.5: Register the DEFINITION with DOCUMENT
- registerDefinition(definition.__name, definition);
- // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
- // 7.1.8. Return the output of the previous step.
- definition.ctor = generateConstructor(definition);
- definition.ctor.prototype = definition.prototype;
- // force our .constructor to be our actual constructor
- definition.prototype.constructor = definition.ctor;
- // if initial parsing is complete
- if (scope.ready) {
- // upgrade any pre-existing nodes of this type
- scope.upgradeDocumentTree(document);
- }
- return definition.ctor;
- }
-
- function isReservedTag(name) {
- for (var i = 0; i < reservedTagList.length; i++) {
- if (name === reservedTagList[i]) {
- return true;
- }
- }
- }
-
- var reservedTagList = [
- 'annotation-xml', 'color-profile', 'font-face', 'font-face-src',
- 'font-face-uri', 'font-face-format', 'font-face-name', 'missing-glyph'
- ];
-
- function ancestry(extnds) {
- var extendee = getRegisteredDefinition(extnds);
- if (extendee) {
- return ancestry(extendee.extends).concat([extendee]);
- }
- return [];
- }
-
- function resolveTagName(definition) {
- // if we are explicitly extending something, that thing is our
- // baseTag, unless it represents a custom component
- var baseTag = definition.extends;
- // if our ancestry includes custom components, we only have a
- // baseTag if one of them does
- for (var i=0, a; (a=definition.ancestry[i]); i++) {
- baseTag = a.is && a.tag;
- }
- // our tag is our baseTag, if it exists, and otherwise just our name
- definition.tag = baseTag || definition.__name;
- if (baseTag) {
- // if there is a base tag, use secondary 'is' specifier
- definition.is = definition.__name;
- }
- }
-
- function resolvePrototypeChain(definition) {
- // if we don't support __proto__ we need to locate the native level
- // prototype for precise mixing in
- if (!Object.__proto__) {
- // default prototype
- var nativePrototype = HTMLElement.prototype;
- // work out prototype when using type-extension
- if (definition.is) {
- var inst = document.createElement(definition.tag);
- nativePrototype = Object.getPrototypeOf(inst);
- }
- // ensure __proto__ reference is installed at each point on the prototype
- // chain.
- // NOTE: On platforms without __proto__, a mixin strategy is used instead
- // of prototype swizzling. In this case, this generated __proto__ provides
- // limited support for prototype traversal.
- var proto = definition.prototype, ancestor;
- while (proto && (proto !== nativePrototype)) {
- var ancestor = Object.getPrototypeOf(proto);
- proto.__proto__ = ancestor;
- proto = ancestor;
- }
- }
- // cache this in case of mixin
- definition.native = nativePrototype;
- }
-
- // SECTION 4
-
- function instantiate(definition) {
- // 4.a.1. Create a new object that implements PROTOTYPE
- // 4.a.2. Let ELEMENT by this new object
- //
- // the custom element instantiation algorithm must also ensure that the
- // output is a valid DOM element with the proper wrapper in place.
- //
- return upgrade(domCreateElement(definition.tag), definition);
- }
-
- function upgrade(element, definition) {
- // some definitions specify an 'is' attribute
- if (definition.is) {
- element.setAttribute('is', definition.is);
- }
- // remove 'unresolved' attr, which is a standin for :unresolved.
- element.removeAttribute('unresolved');
- // make 'element' implement definition.prototype
- implement(element, definition);
- // flag as upgraded
- element.__upgraded__ = true;
- // lifecycle management
- created(element);
- // attachedCallback fires in tree order, call before recursing
- scope.insertedNode(element);
- // there should never be a shadow root on element at this point
- scope.upgradeSubtree(element);
- // OUTPUT
- return element;
- }
-
- function implement(element, definition) {
- // prototype swizzling is best
- if (Object.__proto__) {
- element.__proto__ = definition.prototype;
- } else {
- // where above we can re-acquire inPrototype via
- // getPrototypeOf(Element), we cannot do so when
- // we use mixin, so we install a magic reference
- customMixin(element, definition.prototype, definition.native);
- element.__proto__ = definition.prototype;
- }
- }
-
- function customMixin(inTarget, inSrc, inNative) {
- // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of
- // any property. This set should be precalculated. We also need to
- // consider this for supporting 'super'.
- var used = {};
- // start with inSrc
- var p = inSrc;
- // The default is HTMLElement.prototype, so we add a test to avoid mixing in
- // native prototypes
- while (p !== inNative && p !== HTMLElement.prototype) {
- var keys = Object.getOwnPropertyNames(p);
- for (var i=0, k; k=keys[i]; i++) {
- if (!used[k]) {
- Object.defineProperty(inTarget, k,
- Object.getOwnPropertyDescriptor(p, k));
- used[k] = 1;
- }
- }
- p = Object.getPrototypeOf(p);
- }
- }
-
- function created(element) {
- // invoke createdCallback
- if (element.createdCallback) {
- element.createdCallback();
- }
- }
-
- // attribute watching
-
- function overrideAttributeApi(prototype) {
- // overrides to implement callbacks
- // TODO(sjmiles): should support access via .attributes NamedNodeMap
- // TODO(sjmiles): preserves user defined overrides, if any
- if (prototype.setAttribute._polyfilled) {
- return;
- }
- var setAttribute = prototype.setAttribute;
- prototype.setAttribute = function(name, value) {
- changeAttribute.call(this, name, value, setAttribute);
- }
- var removeAttribute = prototype.removeAttribute;
- prototype.removeAttribute = function(name) {
- changeAttribute.call(this, name, null, removeAttribute);
- }
- prototype.setAttribute._polyfilled = true;
- }
-
- // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/
- // index.html#dfn-attribute-changed-callback
- function changeAttribute(name, value, operation) {
- var oldValue = this.getAttribute(name);
- operation.apply(this, arguments);
- var newValue = this.getAttribute(name);
- if (this.attributeChangedCallback
- && (newValue !== oldValue)) {
- this.attributeChangedCallback(name, oldValue, newValue);
- }
- }
-
- // element registry (maps tag names to definitions)
-
- var registry = {};
-
- function getRegisteredDefinition(name) {
- if (name) {
- return registry[name.toLowerCase()];
- }
- }
-
- function registerDefinition(name, definition) {
- registry[name] = definition;
- }
-
- function generateConstructor(definition) {
- return function() {
- return instantiate(definition);
- };
- }
-
- var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
- function createElementNS(namespace, tag, typeExtension) {
- // NOTE: we do not support non-HTML elements,
- // just call createElementNS for non HTML Elements
- if (namespace === HTML_NAMESPACE) {
- return createElement(tag, typeExtension);
- } else {
- return domCreateElementNS(namespace, tag);
- }
- }
-
- function createElement(tag, typeExtension) {
- // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
- // error check it, or perhaps there should only ever be one argument
- var definition = getRegisteredDefinition(typeExtension || tag);
- if (definition) {
- if (tag == definition.tag && typeExtension == definition.is) {
- return new definition.ctor();
- }
- // Handle empty string for type extension.
- if (!typeExtension && !definition.is) {
- return new definition.ctor();
- }
- }
-
- if (typeExtension) {
- var element = createElement(tag);
- element.setAttribute('is', typeExtension);
- return element;
- }
- var element = domCreateElement(tag);
- // Custom tags should be HTMLElements even if not upgraded.
- if (tag.indexOf('-') >= 0) {
- implement(element, HTMLElement);
- }
- return element;
- }
-
- function upgradeElement(element) {
- if (!element.__upgraded__ && (element.nodeType === Node.ELEMENT_NODE)) {
- var is = element.getAttribute('is');
- var definition = getRegisteredDefinition(is || element.localName);
- if (definition) {
- if (is && definition.tag == element.localName) {
- return upgrade(element, definition);
- } else if (!is && !definition.extends) {
- return upgrade(element, definition);
- }
- }
- }
- }
-
- function cloneNode(deep) {
- // call original clone
- var n = domCloneNode.call(this, deep);
- // upgrade the element and subtree
- scope.upgradeAll(n);
- // return the clone
- return n;
- }
- // capture native createElement before we override it
-
- var domCreateElement = document.createElement.bind(document);
- var domCreateElementNS = document.createElementNS.bind(document);
-
- // capture native cloneNode before we override it
-
- var domCloneNode = Node.prototype.cloneNode;
-
- // exports
-
- document.registerElement = register;
- document.createElement = createElement; // override
- document.createElementNS = createElementNS; // override
- Node.prototype.cloneNode = cloneNode; // override
-
- scope.registry = registry;
-
- /**
- * Upgrade an element to a custom element. Upgrading an element
- * causes the custom prototype to be applied, an `is` attribute
- * to be attached (as needed), and invocation of the `readyCallback`.
- * `upgrade` does nothing if the element is already upgraded, or
- * if it matches no registered custom tag name.
- *
- * @method ugprade
- * @param {Element} element The element to upgrade.
- * @return {Element} The upgraded element.
- */
- scope.upgrade = upgradeElement;
-}
-
-// Create a custom 'instanceof'. This is necessary when CustomElements
-// are implemented via a mixin strategy, as for example on IE10.
-var isInstance;
-if (!Object.__proto__ && !useNative) {
- isInstance = function(obj, ctor) {
- var p = obj;
- while (p) {
- // NOTE: this is not technically correct since we're not checking if
- // an object is an instance of a constructor; however, this should
- // be good enough for the mixin strategy.
- if (p === ctor.prototype) {
- return true;
- }
- p = p.__proto__;
- }
- return false;
- }
-} else {
- isInstance = function(obj, base) {
- return obj instanceof base;
- }
-}
-
-// exports
-scope.instanceof = isInstance;
-scope.reservedTagList = reservedTagList;
-
-// bc
-document.register = document.registerElement;
-
-scope.hasNative = hasNative;
-scope.useNative = useNative;
-
-})(window.CustomElements);
-
-/*
- * 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) {
-
-// import
-
-var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
-
-// highlander object for parsing a document tree
-
-var parser = {
- selectors: [
- 'link[rel=' + IMPORT_LINK_TYPE + ']'
- ],
- map: {
- link: 'parseLink'
- },
- parse: function(inDocument) {
- if (!inDocument.__parsed) {
- // only parse once
- inDocument.__parsed = true;
- // all parsable elements in inDocument (depth-first pre-order traversal)
- var elts = inDocument.querySelectorAll(parser.selectors);
- // for each parsable node type, call the mapped parsing method
- forEach(elts, function(e) {
- parser[parser.map[e.localName]](e);
- });
- // upgrade all upgradeable static elements, anything dynamically
- // created should be caught by observer
- CustomElements.upgradeDocument(inDocument);
- // observe document for dom changes
- CustomElements.observeDocument(inDocument);
- }
- },
- parseLink: function(linkElt) {
- // imports
- if (isDocumentLink(linkElt)) {
- this.parseImport(linkElt);
- }
- },
- parseImport: function(linkElt) {
- if (linkElt.import) {
- parser.parse(linkElt.import);
- }
- }
-};
-
-function isDocumentLink(inElt) {
- return (inElt.localName === 'link'
- && inElt.getAttribute('rel') === IMPORT_LINK_TYPE);
-}
-
-var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
-
-// exports
-
-scope.parser = parser;
-scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
-
-})(window.CustomElements);
-/*
- * 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){
-
-// bootstrap parsing
-function bootstrap() {
- // parse document
- CustomElements.parser.parse(document);
- // one more pass before register is 'live'
- CustomElements.upgradeDocument(document);
- // choose async
- var async = window.Platform && Platform.endOfMicrotask ?
- Platform.endOfMicrotask :
- setTimeout;
- async(function() {
- // set internal 'ready' flag, now document.registerElement will trigger
- // synchronous upgrades
- CustomElements.ready = true;
- // capture blunt profiling data
- CustomElements.readyTime = Date.now();
- if (window.HTMLImports) {
- CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;
- }
- // notify the system that we are bootstrapped
- document.dispatchEvent(
- new CustomEvent('WebComponentsReady', {bubbles: true})
- );
-
- // install upgrade hook if HTMLImports are available
- if (window.HTMLImports) {
- HTMLImports.__importsParsingHook = function(elt) {
- CustomElements.parser.parse(elt.import);
- }
- }
- });
-}
-
-// CustomEvent shim for IE
-if (typeof window.CustomEvent !== 'function') {
- window.CustomEvent = function(inType) {
- var e = document.createEvent('HTMLEvents');
- e.initEvent(inType, true, true);
- return e;
- };
-}
-
-// When loading at readyState complete time (or via flag), boot custom elements
-// immediately.
-// If relevant, HTMLImports must already be loaded.
-if (document.readyState === 'complete' || scope.flags.eager) {
- bootstrap();
-// When loading at readyState interactive time, bootstrap only if HTMLImports
-// are not pending. Also avoid IE as the semantics of this state are unreliable.
-} else if (document.readyState === 'interactive' && !window.attachEvent &&
- (!window.HTMLImports || window.HTMLImports.ready)) {
- bootstrap();
-// When loading at other readyStates, wait for the appropriate DOM event to
-// bootstrap.
-} else {
- var loadEvent = window.HTMLImports && !HTMLImports.ready ?
- 'HTMLImportsLoaded' : 'DOMContentLoaded';
- window.addEventListener(loadEvent, bootstrap);
-}
-
-})(window.CustomElements);
-
-/*
- * 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() {
-
-if (window.ShadowDOMPolyfill) {
-
- // ensure wrapped inputs for these functions
- var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument',
- 'upgradeDocument'];
-
- // cache originals
- var original = {};
- fns.forEach(function(fn) {
- original[fn] = CustomElements[fn];
- });
-
- // override
- fns.forEach(function(fn) {
- CustomElements[fn] = function(inNode) {
- return original[fn](wrap(inNode));
- };
- });
-
-}
-
-})();
-
-/*
- * Copyright 2014 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) {
- var endOfMicrotask = scope.endOfMicrotask;
-
- // Generic url loader
- function Loader(regex) {
- this.regex = regex;
- }
- Loader.prototype = {
- // TODO(dfreedm): there may be a better factoring here
- // extract absolute urls from the text (full of relative urls)
- extractUrls: function(text, base) {
- var matches = [];
- var matched, u;
- while ((matched = this.regex.exec(text))) {
- u = new URL(matched[1], base);
- matches.push({matched: matched[0], url: u.href});
- }
- return matches;
- },
- // take a text blob, a root url, and a callback and load all the urls found within the text
- // returns a map of absolute url to text
- process: function(text, root, callback) {
- var matches = this.extractUrls(text, root);
- this.fetch(matches, {}, callback);
- },
- // build a mapping of url -> text from matches
- fetch: function(matches, map, callback) {
- var inflight = matches.length;
-
- // return early if there is no fetching to be done
- if (!inflight) {
- return callback(map);
- }
-
- var done = function() {
- if (--inflight === 0) {
- callback(map);
- }
- };
-
- // map url -> responseText
- var handleXhr = function(err, request) {
- var match = request.match;
- var key = match.url;
- // handle errors with an empty string
- if (err) {
- map[key] = '';
- return done();
- }
- var response = request.response || request.responseText;
- map[key] = response;
- this.fetch(this.extractUrls(response, key), map, done);
- };
-
- var m, req, url;
- for (var i = 0; i < inflight; i++) {
- m = matches[i];
- url = m.url;
- // if this url has already been requested, skip requesting it again
- if (map[url]) {
- // Async call to done to simplify the inflight logic
- endOfMicrotask(done);
- continue;
- }
- req = this.xhr(url, handleXhr, this);
- req.match = m;
- // tag the map with an XHR request to deduplicate at the same level
- map[url] = req;
- }
- },
- xhr: function(url, callback, scope) {
- var request = new XMLHttpRequest();
- request.open('GET', url, true);
- request.send();
- request.onload = function() {
- callback.call(scope, null, request);
- };
- request.onerror = function() {
- callback.call(scope, null, request);
- };
- return request;
- }
- };
-
- scope.Loader = Loader;
-})(window.Platform);
-
-/*
- * Copyright 2014 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) {
-
-var urlResolver = scope.urlResolver;
-var Loader = scope.Loader;
-
-function StyleResolver() {
- this.loader = new Loader(this.regex);
-}
-StyleResolver.prototype = {
- regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,
- // Recursively replace @imports with the text at that url
- resolve: function(text, url, callback) {
- var done = function(map) {
- callback(this.flatten(text, url, map));
- }.bind(this);
- this.loader.process(text, url, done);
- },
- // resolve the textContent of a style node
- resolveNode: function(style, callback) {
- var text = style.textContent;
- var url = style.ownerDocument.baseURI;
- var done = function(text) {
- style.textContent = text;
- callback(style);
- };
- this.resolve(text, url, done);
- },
- // flatten all the @imports to text
- flatten: function(text, base, map) {
- var matches = this.loader.extractUrls(text, base);
- var match, url, intermediate;
- for (var i = 0; i < matches.length; i++) {
- match = matches[i];
- url = match.url;
- // resolve any css text to be relative to the importer
- intermediate = urlResolver.resolveCssText(map[url], url);
- // flatten intermediate @imports
- intermediate = this.flatten(intermediate, url, map);
- text = text.replace(match.matched, intermediate);
- }
- return text;
- },
- loadStyles: function(styles, callback) {
- var loaded=0, l = styles.length;
- // called in the context of the style
- function loadedStyle(style) {
- loaded++;
- if (loaded === l && callback) {
- callback();
- }
- }
- for (var i=0, s; (i<l) && (s=styles[i]); i++) {
- this.resolveNode(s, loadedStyle);
- }
- }
-};
-
-var styleResolver = new StyleResolver();
-
-// exports
-scope.styleResolver = styleResolver;
-
-})(window.Platform);
-
-/*
- * 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) {
- scope = scope || {};
- scope.external = scope.external || {};
- var target = {
- shadow: function(inEl) {
- if (inEl) {
- return inEl.shadowRoot || inEl.webkitShadowRoot;
- }
- },
- canTarget: function(shadow) {
- return shadow && Boolean(shadow.elementFromPoint);
- },
- targetingShadow: function(inEl) {
- var s = this.shadow(inEl);
- if (this.canTarget(s)) {
- return s;
- }
- },
- olderShadow: function(shadow) {
- var os = shadow.olderShadowRoot;
- if (!os) {
- var se = shadow.querySelector('shadow');
- if (se) {
- os = se.olderShadowRoot;
- }
- }
- return os;
- },
- allShadows: function(element) {
- var shadows = [], s = this.shadow(element);
- while(s) {
- shadows.push(s);
- s = this.olderShadow(s);
- }
- return shadows;
- },
- searchRoot: function(inRoot, x, y) {
- if (inRoot) {
- var t = inRoot.elementFromPoint(x, y);
- var st, sr, os;
- // is element a shadow host?
- sr = this.targetingShadow(t);
- while (sr) {
- // find the the element inside the shadow root
- st = sr.elementFromPoint(x, y);
- if (!st) {
- // check for older shadows
- sr = this.olderShadow(sr);
- } else {
- // shadowed element may contain a shadow root
- var ssr = this.targetingShadow(st);
- return this.searchRoot(ssr, x, y) || st;
- }
- }
- // light dom element is the target
- return t;
- }
- },
- owner: function(element) {
- var s = element;
- // walk up until you hit the shadow root or document
- while (s.parentNode) {
- s = s.parentNode;
- }
- // the owner element is expected to be a Document or ShadowRoot
- if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGMENT_NODE) {
- s = document;
- }
- return s;
- },
- findTarget: function(inEvent) {
- var x = inEvent.clientX, y = inEvent.clientY;
- // if the listener is in the shadow root, it is much faster to start there
- var s = this.owner(inEvent.target);
- // if x, y is not in this root, fall back to document search
- if (!s.elementFromPoint(x, y)) {
- s = document;
- }
- return this.searchRoot(s, x, y);
- }
- };
- scope.targetFinding = target;
- scope.findTarget = target.findTarget.bind(target);
-
- window.PointerEventsPolyfill = scope;
-})(window.PointerEventsPolyfill);
-
-/*
- * 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() {
- function shadowSelector(v) {
- return 'body /shadow-deep/ ' + selector(v);
- }
- function selector(v) {
- return '[touch-action="' + v + '"]';
- }
- function rule(v) {
- return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + '; touch-action-delay: none; }';
- }
- var attrib2css = [
- 'none',
- 'auto',
- 'pan-x',
- 'pan-y',
- {
- rule: 'pan-x pan-y',
- selectors: [
- 'pan-x pan-y',
- 'pan-y pan-x'
- ]
- }
- ];
- var styles = '';
- // only install stylesheet if the browser has touch action support
- var head = document.head;
- var hasNativePE = window.PointerEvent || window.MSPointerEvent;
- // only add shadow selectors if shadowdom is supported
- var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoot;
-
- if (hasNativePE) {
- attrib2css.forEach(function(r) {
- if (String(r) === r) {
- styles += selector(r) + rule(r) + '\n';
- if (hasShadowRoot) {
- styles += shadowSelector(r) + rule(r) + '\n';
- }
- } else {
- styles += r.selectors.map(selector) + rule(r.rule) + '\n';
- if (hasShadowRoot) {
- styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n';
- }
- }
- });
-
- var el = document.createElement('style');
- el.textContent = styles;
- document.head.appendChild(el);
- }
-})();
-
-/*
- * 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.
- */
-
-/**
- * This is the constructor for new PointerEvents.
- *
- * New Pointer Events must be given a type, and an optional dictionary of
- * initialization properties.
- *
- * Due to certain platform requirements, events returned from the constructor
- * identify as MouseEvents.
- *
- * @constructor
- * @param {String} inType The type of the event to create.
- * @param {Object} [inDict] An optional dictionary of initial event properties.
- * @return {Event} A new PointerEvent of type `inType` and initialized with properties from `inDict`.
- */
-(function(scope) {
-
- var MOUSE_PROPS = [
- 'bubbles',
- 'cancelable',
- 'view',
- 'detail',
- 'screenX',
- 'screenY',
- 'clientX',
- 'clientY',
- 'ctrlKey',
- 'altKey',
- 'shiftKey',
- 'metaKey',
- 'button',
- 'relatedTarget',
- 'pageX',
- 'pageY'
- ];
-
- var MOUSE_DEFAULTS = [
- false,
- false,
- null,
- null,
- 0,
- 0,
- 0,
- 0,
- false,
- false,
- false,
- false,
- 0,
- null,
- 0,
- 0
- ];
-
- function PointerEvent(inType, inDict) {
- inDict = inDict || Object.create(null);
-
- var e = document.createEvent('Event');
- e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
-
- // define inherited MouseEvent properties
- for(var i = 0, p; i < MOUSE_PROPS.length; i++) {
- p = MOUSE_PROPS[i];
- e[p] = inDict[p] || MOUSE_DEFAULTS[i];
- }
- e.buttons = inDict.buttons || 0;
-
- // Spec requires that pointers without pressure specified use 0.5 for down
- // state and 0 for up state.
- var pressure = 0;
- if (inDict.pressure) {
- pressure = inDict.pressure;
- } else {
- pressure = e.buttons ? 0.5 : 0;
- }
-
- // add x/y properties aliased to clientX/Y
- e.x = e.clientX;
- e.y = e.clientY;
-
- // define the properties of the PointerEvent interface
- e.pointerId = inDict.pointerId || 0;
- e.width = inDict.width || 0;
- e.height = inDict.height || 0;
- e.pressure = pressure;
- e.tiltX = inDict.tiltX || 0;
- e.tiltY = inDict.tiltY || 0;
- e.pointerType = inDict.pointerType || '';
- e.hwTimestamp = inDict.hwTimestamp || 0;
- e.isPrimary = inDict.isPrimary || false;
- return e;
- }
-
- // attach to window
- if (!scope.PointerEvent) {
- scope.PointerEvent = PointerEvent;
- }
-})(window);
-
-/*
- * 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.
- */
-
-/**
- * This module implements an map of pointer states
- */
-(function(scope) {
- var USE_MAP = window.Map && window.Map.prototype.forEach;
- var POINTERS_FN = function(){ return this.size; };
- function PointerMap() {
- if (USE_MAP) {
- var m = new Map();
- m.pointers = POINTERS_FN;
- return m;
- } else {
- this.keys = [];
- this.values = [];
- }
- }
-
- PointerMap.prototype = {
- set: function(inId, inEvent) {
- var i = this.keys.indexOf(inId);
- if (i > -1) {
- this.values[i] = inEvent;
- } else {
- this.keys.push(inId);
- this.values.push(inEvent);
- }
- },
- has: function(inId) {
- return this.keys.indexOf(inId) > -1;
- },
- 'delete': function(inId) {
- var i = this.keys.indexOf(inId);
- if (i > -1) {
- this.keys.splice(i, 1);
- this.values.splice(i, 1);
- }
- },
- get: function(inId) {
- var i = this.keys.indexOf(inId);
- return this.values[i];
- },
- clear: function() {
- this.keys.length = 0;
- this.values.length = 0;
- },
- // return value, key, map
- forEach: function(callback, thisArg) {
- this.values.forEach(function(v, i) {
- callback.call(thisArg, v, this.keys[i], this);
- }, this);
- },
- pointers: function() {
- return this.keys.length;
- }
- };
-
- scope.PointerMap = PointerMap;
-})(window.PointerEventsPolyfill);
-
-/*
- * 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) {
- var CLONE_PROPS = [
- // MouseEvent
- 'bubbles',
- 'cancelable',
- 'view',
- 'detail',
- 'screenX',
- 'screenY',
- 'clientX',
- 'clientY',
- 'ctrlKey',
- 'altKey',
- 'shiftKey',
- 'metaKey',
- 'button',
- 'relatedTarget',
- // DOM Level 3
- 'buttons',
- // PointerEvent
- 'pointerId',
- 'width',
- 'height',
- 'pressure',
- 'tiltX',
- 'tiltY',
- 'pointerType',
- 'hwTimestamp',
- 'isPrimary',
- // event instance
- 'type',
- 'target',
- 'currentTarget',
- 'which',
- 'pageX',
- 'pageY'
- ];
-
- var CLONE_DEFAULTS = [
- // MouseEvent
- false,
- false,
- null,
- null,
- 0,
- 0,
- 0,
- 0,
- false,
- false,
- false,
- false,
- 0,
- null,
- // DOM Level 3
- 0,
- // PointerEvent
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- '',
- 0,
- false,
- // event instance
- '',
- null,
- null,
- 0,
- 0,
- 0
- ];
-
- var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined');
-
- /**
- * This module is for normalizing events. Mouse and Touch events will be
- * collected here, and fire PointerEvents that have the same semantics, no
- * matter the source.
- * Events fired:
- * - pointerdown: a pointing is added
- * - pointerup: a pointer is removed
- * - pointermove: a pointer is moved
- * - pointerover: a pointer crosses into an element
- * - pointerout: a pointer leaves an element
- * - pointercancel: a pointer will no longer generate events
- */
- var dispatcher = {
- pointermap: new scope.PointerMap(),
- eventMap: Object.create(null),
- captureInfo: Object.create(null),
- // Scope objects for native events.
- // This exists for ease of testing.
- eventSources: Object.create(null),
- eventSourceList: [],
- /**
- * Add a new event source that will generate pointer events.
- *
- * `inSource` must contain an array of event names named `events`, and
- * functions with the names specified in the `events` array.
- * @param {string} name A name for the event source
- * @param {Object} source A new source of platform events.
- */
- registerSource: function(name, source) {
- var s = source;
- var newEvents = s.events;
- if (newEvents) {
- newEvents.forEach(function(e) {
- if (s[e]) {
- this.eventMap[e] = s[e].bind(s);
- }
- }, this);
- this.eventSources[name] = s;
- this.eventSourceList.push(s);
- }
- },
- register: function(element) {
- var l = this.eventSourceList.length;
- for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
- // call eventsource register
- es.register.call(es, element);
- }
- },
- unregister: function(element) {
- var l = this.eventSourceList.length;
- for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
- // call eventsource register
- es.unregister.call(es, element);
- }
- },
- contains: scope.external.contains || function(container, contained) {
- return container.contains(contained);
- },
- // EVENTS
- down: function(inEvent) {
- inEvent.bubbles = true;
- this.fireEvent('pointerdown', inEvent);
- },
- move: function(inEvent) {
- inEvent.bubbles = true;
- this.fireEvent('pointermove', inEvent);
- },
- up: function(inEvent) {
- inEvent.bubbles = true;
- this.fireEvent('pointerup', inEvent);
- },
- enter: function(inEvent) {
- inEvent.bubbles = false;
- this.fireEvent('pointerenter', inEvent);
- },
- leave: function(inEvent) {
- inEvent.bubbles = false;
- this.fireEvent('pointerleave', inEvent);
- },
- over: function(inEvent) {
- inEvent.bubbles = true;
- this.fireEvent('pointerover', inEvent);
- },
- out: function(inEvent) {
- inEvent.bubbles = true;
- this.fireEvent('pointerout', inEvent);
- },
- cancel: function(inEvent) {
- inEvent.bubbles = true;
- this.fireEvent('pointercancel', inEvent);
- },
- leaveOut: function(event) {
- this.out(event);
- if (!this.contains(event.target, event.relatedTarget)) {
- this.leave(event);
- }
- },
- enterOver: function(event) {
- this.over(event);
- if (!this.contains(event.target, event.relatedTarget)) {
- this.enter(event);
- }
- },
- // LISTENER LOGIC
- eventHandler: function(inEvent) {
- // This is used to prevent multiple dispatch of pointerevents from
- // platform events. This can happen when two elements in different scopes
- // are set up to create pointer events, which is relevant to Shadow DOM.
- if (inEvent._handledByPE) {
- return;
- }
- var type = inEvent.type;
- var fn = this.eventMap && this.eventMap[type];
- if (fn) {
- fn(inEvent);
- }
- inEvent._handledByPE = true;
- },
- // set up event listeners
- listen: function(target, events) {
- events.forEach(function(e) {
- this.addEvent(target, e);
- }, this);
- },
- // remove event listeners
- unlisten: function(target, events) {
- events.forEach(function(e) {
- this.removeEvent(target, e);
- }, this);
- },
- addEvent: scope.external.addEvent || function(target, eventName) {
- target.addEventListener(eventName, this.boundHandler);
- },
- removeEvent: scope.external.removeEvent || function(target, eventName) {
- target.removeEventListener(eventName, this.boundHandler);
- },
- // EVENT CREATION AND TRACKING
- /**
- * Creates a new Event of type `inType`, based on the information in
- * `inEvent`.
- *
- * @param {string} inType A string representing the type of event to create
- * @param {Event} inEvent A platform event with a target
- * @return {Event} A PointerEvent of type `inType`
- */
- makeEvent: function(inType, inEvent) {
- // relatedTarget must be null if pointer is captured
- if (this.captureInfo[inEvent.pointerId]) {
- inEvent.relatedTarget = null;
- }
- var e = new PointerEvent(inType, inEvent);
- if (inEvent.preventDefault) {
- e.preventDefault = inEvent.preventDefault;
- }
- e._target = e._target || inEvent.target;
- return e;
- },
- // make and dispatch an event in one call
- fireEvent: function(inType, inEvent) {
- var e = this.makeEvent(inType, inEvent);
- return this.dispatchEvent(e);
- },
- /**
- * Returns a snapshot of inEvent, with writable properties.
- *
- * @param {Event} inEvent An event that contains properties to copy.
- * @return {Object} An object containing shallow copies of `inEvent`'s
- * properties.
- */
- cloneEvent: function(inEvent) {
- var eventCopy = Object.create(null), p;
- for (var i = 0; i < CLONE_PROPS.length; i++) {
- p = CLONE_PROPS[i];
- eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
- // Work around SVGInstanceElement shadow tree
- // Return the <use> element that is represented by the instance for Safari, Chrome, IE.
- // This is the behavior implemented by Firefox.
- if (HAS_SVG_INSTANCE && (p === 'target' || p === 'relatedTarget')) {
- if (eventCopy[p] instanceof SVGElementInstance) {
- eventCopy[p] = eventCopy[p].correspondingUseElement;
- }
- }
- }
- // keep the semantics of preventDefault
- if (inEvent.preventDefault) {
- eventCopy.preventDefault = function() {
- inEvent.preventDefault();
- };
- }
- return eventCopy;
- },
- getTarget: function(inEvent) {
- // if pointer capture is set, route all events for the specified pointerId
- // to the capture target
- return this.captureInfo[inEvent.pointerId] || inEvent._target;
- },
- setCapture: function(inPointerId, inTarget) {
- if (this.captureInfo[inPointerId]) {
- this.releaseCapture(inPointerId);
- }
- this.captureInfo[inPointerId] = inTarget;
- var e = document.createEvent('Event');
- e.initEvent('gotpointercapture', true, false);
- e.pointerId = inPointerId;
- this.implicitRelease = this.releaseCapture.bind(this, inPointerId);
- document.addEventListener('pointerup', this.implicitRelease);
- document.addEventListener('pointercancel', this.implicitRelease);
- e._target = inTarget;
- this.asyncDispatchEvent(e);
- },
- releaseCapture: function(inPointerId) {
- var t = this.captureInfo[inPointerId];
- if (t) {
- var e = document.createEvent('Event');
- e.initEvent('lostpointercapture', true, false);
- e.pointerId = inPointerId;
- this.captureInfo[inPointerId] = undefined;
- document.removeEventListener('pointerup', this.implicitRelease);
- document.removeEventListener('pointercancel', this.implicitRelease);
- e._target = t;
- this.asyncDispatchEvent(e);
- }
- },
- /**
- * Dispatches the event to its target.
- *
- * @param {Event} inEvent The event to be dispatched.
- * @return {Boolean} True if an event handler returns true, false otherwise.
- */
- dispatchEvent: scope.external.dispatchEvent || function(inEvent) {
- var t = this.getTarget(inEvent);
- if (t) {
- return t.dispatchEvent(inEvent);
- }
- },
- asyncDispatchEvent: function(inEvent) {
- requestAnimationFrame(this.dispatchEvent.bind(this, inEvent));
- }
- };
- dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
- scope.dispatcher = dispatcher;
- scope.register = dispatcher.register.bind(dispatcher);
- scope.unregister = dispatcher.unregister.bind(dispatcher);
-})(window.PointerEventsPolyfill);
-
-/*
- * 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.
- */
-
-/**
- * This module uses Mutation Observers to dynamically adjust which nodes will
- * generate Pointer Events.
- *
- * All nodes that wish to generate Pointer Events must have the attribute
- * `touch-action` set to `none`.
- */
-(function(scope) {
- var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
- var map = Array.prototype.map.call.bind(Array.prototype.map);
- var toArray = Array.prototype.slice.call.bind(Array.prototype.slice);
- var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
- var MO = window.MutationObserver || window.WebKitMutationObserver;
- var SELECTOR = '[touch-action]';
- var OBSERVER_INIT = {
- subtree: true,
- childList: true,
- attributes: true,
- attributeOldValue: true,
- attributeFilter: ['touch-action']
- };
-
- function Installer(add, remove, changed, binder) {
- this.addCallback = add.bind(binder);
- this.removeCallback = remove.bind(binder);
- this.changedCallback = changed.bind(binder);
- if (MO) {
- this.observer = new MO(this.mutationWatcher.bind(this));
- }
- }
-
- Installer.prototype = {
- watchSubtree: function(target) {
- // Only watch scopes that can target find, as these are top-level.
- // Otherwise we can see duplicate additions and removals that add noise.
- //
- // TODO(dfreedman): For some instances with ShadowDOMPolyfill, we can see
- // a removal without an insertion when a node is redistributed among
- // shadows. Since it all ends up correct in the document, watching only
- // the document will yield the correct mutations to watch.
- if (scope.targetFinding.canTarget(target)) {
- this.observer.observe(target, OBSERVER_INIT);
- }
- },
- enableOnSubtree: function(target) {
- this.watchSubtree(target);
- if (target === document && document.readyState !== 'complete') {
- this.installOnLoad();
- } else {
- this.installNewSubtree(target);
- }
- },
- installNewSubtree: function(target) {
- forEach(this.findElements(target), this.addElement, this);
- },
- findElements: function(target) {
- if (target.querySelectorAll) {
- return target.querySelectorAll(SELECTOR);
- }
- return [];
- },
- removeElement: function(el) {
- this.removeCallback(el);
- },
- addElement: function(el) {
- this.addCallback(el);
- },
- elementChanged: function(el, oldValue) {
- this.changedCallback(el, oldValue);
- },
- concatLists: function(accum, list) {
- return accum.concat(toArray(list));
- },
- // register all touch-action = none nodes on document load
- installOnLoad: function() {
- document.addEventListener('readystatechange', function() {
- if (document.readyState === 'complete') {
- this.installNewSubtree(document);
- }
- }.bind(this));
- },
- isElement: function(n) {
- return n.nodeType === Node.ELEMENT_NODE;
- },
- flattenMutationTree: function(inNodes) {
- // find children with touch-action
- var tree = map(inNodes, this.findElements, this);
- // make sure the added nodes are accounted for
- tree.push(filter(inNodes, this.isElement));
- // flatten the list
- return tree.reduce(this.concatLists, []);
- },
- mutationWatcher: function(mutations) {
- mutations.forEach(this.mutationHandler, this);
- },
- mutationHandler: function(m) {
- if (m.type === 'childList') {
- var added = this.flattenMutationTree(m.addedNodes);
- added.forEach(this.addElement, this);
- var removed = this.flattenMutationTree(m.removedNodes);
- removed.forEach(this.removeElement, this);
- } else if (m.type === 'attributes') {
- this.elementChanged(m.target, m.oldValue);
- }
- }
- };
-
- if (!MO) {
- Installer.prototype.watchSubtree = function(){
- console.warn('PointerEventsPolyfill: MutationObservers not found, touch-action will not be dynamically detected');
- };
- }
-
- scope.Installer = Installer;
-})(window.PointerEventsPolyfill);
-
-/*
- * 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) {
- var dispatcher = scope.dispatcher;
- var pointermap = dispatcher.pointermap;
- // radius around touchend that swallows mouse events
- var DEDUP_DIST = 25;
-
- var WHICH_TO_BUTTONS = [0, 1, 4, 2];
-
- var HAS_BUTTONS = false;
- try {
- HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1;
- } catch (e) {}
-
- // handler block for native mouse events
- var mouseEvents = {
- POINTER_ID: 1,
- POINTER_TYPE: 'mouse',
- events: [
- 'mousedown',
- 'mousemove',
- 'mouseup',
- 'mouseover',
- 'mouseout'
- ],
- register: function(target) {
- dispatcher.listen(target, this.events);
- },
- unregister: function(target) {
- dispatcher.unlisten(target, this.events);
- },
- lastTouches: [],
- // collide with the global mouse listener
- isEventSimulatedFromTouch: function(inEvent) {
- var lts = this.lastTouches;
- var x = inEvent.clientX, y = inEvent.clientY;
- for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
- // simulated mouse events will be swallowed near a primary touchend
- var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
- if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
- return true;
- }
- }
- },
- prepareEvent: function(inEvent) {
- var e = dispatcher.cloneEvent(inEvent);
- // forward mouse preventDefault
- var pd = e.preventDefault;
- e.preventDefault = function() {
- inEvent.preventDefault();
- pd();
- };
- e.pointerId = this.POINTER_ID;
- e.isPrimary = true;
- e.pointerType = this.POINTER_TYPE;
- if (!HAS_BUTTONS) {
- e.buttons = WHICH_TO_BUTTONS[e.which] || 0;
- }
- return e;
- },
- mousedown: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var p = pointermap.has(this.POINTER_ID);
- // TODO(dfreedman) workaround for some elements not sending mouseup
- // http://crbug/149091
- if (p) {
- this.cancel(inEvent);
- }
- var e = this.prepareEvent(inEvent);
- pointermap.set(this.POINTER_ID, inEvent);
- dispatcher.down(e);
- }
- },
- mousemove: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var e = this.prepareEvent(inEvent);
- dispatcher.move(e);
- }
- },
- mouseup: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var p = pointermap.get(this.POINTER_ID);
- if (p && p.button === inEvent.button) {
- var e = this.prepareEvent(inEvent);
- dispatcher.up(e);
- this.cleanupMouse();
- }
- }
- },
- mouseover: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var e = this.prepareEvent(inEvent);
- dispatcher.enterOver(e);
- }
- },
- mouseout: function(inEvent) {
- if (!this.isEventSimulatedFromTouch(inEvent)) {
- var e = this.prepareEvent(inEvent);
- dispatcher.leaveOut(e);
- }
- },
- cancel: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- dispatcher.cancel(e);
- this.cleanupMouse();
- },
- cleanupMouse: function() {
- pointermap['delete'](this.POINTER_ID);
- }
- };
-
- scope.mouseEvents = mouseEvents;
-})(window.PointerEventsPolyfill);
-
-/*
- * 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) {
- var dispatcher = scope.dispatcher;
- var captureInfo = dispatcher.captureInfo;
- var findTarget = scope.findTarget;
- var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding);
- var pointermap = dispatcher.pointermap;
- var touchMap = Array.prototype.map.call.bind(Array.prototype.map);
- // This should be long enough to ignore compat mouse events made by touch
- var DEDUP_TIMEOUT = 2500;
- var CLICK_COUNT_TIMEOUT = 200;
- var ATTRIB = 'touch-action';
- var INSTALLER;
- // The presence of touch event handlers blocks scrolling, and so we must be careful to
- // avoid adding handlers unnecessarily. Chrome plans to add a touch-action-delay property
- // (crbug.com/329559) to address this, and once we have that we can opt-in to a simpler
- // handler registration mechanism. Rather than try to predict how exactly to opt-in to
- // that we'll just leave this disabled until there is a build of Chrome to test.
- var HAS_TOUCH_ACTION_DELAY = false;
-
- // handler block for native touch events
- var touchEvents = {
- events: [
- 'touchstart',
- 'touchmove',
- 'touchend',
- 'touchcancel'
- ],
- register: function(target) {
- if (HAS_TOUCH_ACTION_DELAY) {
- dispatcher.listen(target, this.events);
- } else {
- INSTALLER.enableOnSubtree(target);
- }
- },
- unregister: function(target) {
- if (HAS_TOUCH_ACTION_DELAY) {
- dispatcher.unlisten(target, this.events);
- } else {
- // TODO(dfreedman): is it worth it to disconnect the MO?
- }
- },
- elementAdded: function(el) {
- var a = el.getAttribute(ATTRIB);
- var st = this.touchActionToScrollType(a);
- if (st) {
- el._scrollType = st;
- dispatcher.listen(el, this.events);
- // set touch-action on shadows as well
- allShadows(el).forEach(function(s) {
- s._scrollType = st;
- dispatcher.listen(s, this.events);
- }, this);
- }
- },
- elementRemoved: function(el) {
- el._scrollType = undefined;
- dispatcher.unlisten(el, this.events);
- // remove touch-action from shadow
- allShadows(el).forEach(function(s) {
- s._scrollType = undefined;
- dispatcher.unlisten(s, this.events);
- }, this);
- },
- elementChanged: function(el, oldValue) {
- var a = el.getAttribute(ATTRIB);
- var st = this.touchActionToScrollType(a);
- var oldSt = this.touchActionToScrollType(oldValue);
- // simply update scrollType if listeners are already established
- if (st && oldSt) {
- el._scrollType = st;
- allShadows(el).forEach(function(s) {
- s._scrollType = st;
- }, this);
- } else if (oldSt) {
- this.elementRemoved(el);
- } else if (st) {
- this.elementAdded(el);
- }
- },
- scrollTypes: {
- EMITTER: 'none',
- XSCROLLER: 'pan-x',
- YSCROLLER: 'pan-y',
- SCROLLER: /^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/
- },
- touchActionToScrollType: function(touchAction) {
- var t = touchAction;
- var st = this.scrollTypes;
- if (t === 'none') {
- return 'none';
- } else if (t === st.XSCROLLER) {
- return 'X';
- } else if (t === st.YSCROLLER) {
- return 'Y';
- } else if (st.SCROLLER.exec(t)) {
- return 'XY';
- }
- },
- POINTER_TYPE: 'touch',
- firstTouch: null,
- isPrimaryTouch: function(inTouch) {
- return this.firstTouch === inTouch.identifier;
- },
- setPrimaryTouch: function(inTouch) {
- // set primary touch if there no pointers, or the only pointer is the mouse
- if (pointermap.pointers() === 0 || (pointermap.pointers() === 1 && pointermap.has(1))) {
- this.firstTouch = inTouch.identifier;
- this.firstXY = {X: inTouch.clientX, Y: inTouch.clientY};
- this.scrolling = false;
- this.cancelResetClickCount();
- }
- },
- removePrimaryPointer: function(inPointer) {
- if (inPointer.isPrimary) {
- this.firstTouch = null;
- this.firstXY = null;
- this.resetClickCount();
- }
- },
- clickCount: 0,
- resetId: null,
- resetClickCount: function() {
- var fn = function() {
- this.clickCount = 0;
- this.resetId = null;
- }.bind(this);
- this.resetId = setTimeout(fn, CLICK_COUNT_TIMEOUT);
- },
- cancelResetClickCount: function() {
- if (this.resetId) {
- clearTimeout(this.resetId);
- }
- },
- typeToButtons: function(type) {
- var ret = 0;
- if (type === 'touchstart' || type === 'touchmove') {
- ret = 1;
- }
- return ret;
- },
- touchToPointer: function(inTouch) {
- var cte = this.currentTouchEvent;
- var e = dispatcher.cloneEvent(inTouch);
- // Spec specifies that pointerId 1 is reserved for Mouse.
- // Touch identifiers can start at 0.
- // Add 2 to the touch identifier for compatibility.
- var id = e.pointerId = inTouch.identifier + 2;
- e.target = captureInfo[id] || findTarget(e);
- e.bubbles = true;
- e.cancelable = true;
- e.detail = this.clickCount;
- e.button = 0;
- e.buttons = this.typeToButtons(cte.type);
- e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
- e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
- e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
- e.isPrimary = this.isPrimaryTouch(inTouch);
- e.pointerType = this.POINTER_TYPE;
- // forward touch preventDefaults
- var self = this;
- e.preventDefault = function() {
- self.scrolling = false;
- self.firstXY = null;
- cte.preventDefault();
- };
- return e;
- },
- processTouches: function(inEvent, inFunction) {
- var tl = inEvent.changedTouches;
- this.currentTouchEvent = inEvent;
- for (var i = 0, t; i < tl.length; i++) {
- t = tl[i];
- inFunction.call(this, this.touchToPointer(t));
- }
- },
- // For single axis scrollers, determines whether the element should emit
- // pointer events or behave as a scroller
- shouldScroll: function(inEvent) {
- if (this.firstXY) {
- var ret;
- var scrollAxis = inEvent.currentTarget._scrollType;
- if (scrollAxis === 'none') {
- // this element is a touch-action: none, should never scroll
- ret = false;
- } else if (scrollAxis === 'XY') {
- // this element should always scroll
- ret = true;
- } else {
- var t = inEvent.changedTouches[0];
- // check the intended scroll axis, and other axis
- var a = scrollAxis;
- var oa = scrollAxis === 'Y' ? 'X' : 'Y';
- var da = Math.abs(t['client' + a] - this.firstXY[a]);
- var doa = Math.abs(t['client' + oa] - this.firstXY[oa]);
- // if delta in the scroll axis > delta other axis, scroll instead of
- // making events
- ret = da >= doa;
- }
- this.firstXY = null;
- return ret;
- }
- },
- findTouch: function(inTL, inId) {
- for (var i = 0, l = inTL.length, t; i < l && (t = inTL[i]); i++) {
- if (t.identifier === inId) {
- return true;
- }
- }
- },
- // In some instances, a touchstart can happen without a touchend. This
- // leaves the pointermap in a broken state.
- // Therefore, on every touchstart, we remove the touches that did not fire a
- // touchend event.
- // To keep state globally consistent, we fire a
- // pointercancel for this "abandoned" touch
- vacuumTouches: function(inEvent) {
- var tl = inEvent.touches;
- // pointermap.pointers() should be < tl.length here, as the touchstart has not
- // been processed yet.
- if (pointermap.pointers() >= tl.length) {
- var d = [];
- pointermap.forEach(function(value, key) {
- // Never remove pointerId == 1, which is mouse.
- // Touch identifiers are 2 smaller than their pointerId, which is the
- // index in pointermap.
- if (key !== 1 && !this.findTouch(tl, key - 2)) {
- var p = value.out;
- d.push(p);
- }
- }, this);
- d.forEach(this.cancelOut, this);
- }
- },
- touchstart: function(inEvent) {
- this.vacuumTouches(inEvent);
- this.setPrimaryTouch(inEvent.changedTouches[0]);
- this.dedupSynthMouse(inEvent);
- if (!this.scrolling) {
- this.clickCount++;
- this.processTouches(inEvent, this.overDown);
- }
- },
- overDown: function(inPointer) {
- var p = pointermap.set(inPointer.pointerId, {
- target: inPointer.target,
- out: inPointer,
- outTarget: inPointer.target
- });
- dispatcher.over(inPointer);
- dispatcher.enter(inPointer);
- dispatcher.down(inPointer);
- },
- touchmove: function(inEvent) {
- if (!this.scrolling) {
- if (this.shouldScroll(inEvent)) {
- this.scrolling = true;
- this.touchcancel(inEvent);
- } else {
- inEvent.preventDefault();
- this.processTouches(inEvent, this.moveOverOut);
- }
- }
- },
- moveOverOut: function(inPointer) {
- var event = inPointer;
- var pointer = pointermap.get(event.pointerId);
- // a finger drifted off the screen, ignore it
- if (!pointer) {
- return;
- }
- var outEvent = pointer.out;
- var outTarget = pointer.outTarget;
- dispatcher.move(event);
- if (outEvent && outTarget !== event.target) {
- outEvent.relatedTarget = event.target;
- event.relatedTarget = outTarget;
- // recover from retargeting by shadow
- outEvent.target = outTarget;
- if (event.target) {
- dispatcher.leaveOut(outEvent);
- dispatcher.enterOver(event);
- } else {
- // clean up case when finger leaves the screen
- event.target = outTarget;
- event.relatedTarget = null;
- this.cancelOut(event);
- }
- }
- pointer.out = event;
- pointer.outTarget = event.target;
- },
- touchend: function(inEvent) {
- this.dedupSynthMouse(inEvent);
- this.processTouches(inEvent, this.upOut);
- },
- upOut: function(inPointer) {
- if (!this.scrolling) {
- dispatcher.up(inPointer);
- dispatcher.out(inPointer);
- dispatcher.leave(inPointer);
- }
- this.cleanUpPointer(inPointer);
- },
- touchcancel: function(inEvent) {
- this.processTouches(inEvent, this.cancelOut);
- },
- cancelOut: function(inPointer) {
- dispatcher.cancel(inPointer);
- dispatcher.out(inPointer);
- dispatcher.leave(inPointer);
- this.cleanUpPointer(inPointer);
- },
- cleanUpPointer: function(inPointer) {
- pointermap['delete'](inPointer.pointerId);
- this.removePrimaryPointer(inPointer);
- },
- // prevent synth mouse events from creating pointer events
- dedupSynthMouse: function(inEvent) {
- var lts = scope.mouseEvents.lastTouches;
- var t = inEvent.changedTouches[0];
- // only the primary finger will synth mouse events
- if (this.isPrimaryTouch(t)) {
- // remember x/y of last touch
- var lt = {x: t.clientX, y: t.clientY};
- lts.push(lt);
- var fn = (function(lts, lt){
- var i = lts.indexOf(lt);
- if (i > -1) {
- lts.splice(i, 1);
- }
- }).bind(null, lts, lt);
- setTimeout(fn, DEDUP_TIMEOUT);
- }
- }
- };
-
- if (!HAS_TOUCH_ACTION_DELAY) {
- INSTALLER = new scope.Installer(touchEvents.elementAdded, touchEvents.elementRemoved, touchEvents.elementChanged, touchEvents);
- }
-
- scope.touchEvents = touchEvents;
-})(window.PointerEventsPolyfill);
-
-/*
- * 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) {
- var dispatcher = scope.dispatcher;
- var pointermap = dispatcher.pointermap;
- var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE === 'number';
- var msEvents = {
- events: [
- 'MSPointerDown',
- 'MSPointerMove',
- 'MSPointerUp',
- 'MSPointerOut',
- 'MSPointerOver',
- 'MSPointerCancel',
- 'MSGotPointerCapture',
- 'MSLostPointerCapture'
- ],
- register: function(target) {
- dispatcher.listen(target, this.events);
- },
- unregister: function(target) {
- dispatcher.unlisten(target, this.events);
- },
- POINTER_TYPES: [
- '',
- 'unavailable',
- 'touch',
- 'pen',
- 'mouse'
- ],
- prepareEvent: function(inEvent) {
- var e = inEvent;
- if (HAS_BITMAP_TYPE) {
- e = dispatcher.cloneEvent(inEvent);
- e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
- }
- return e;
- },
- cleanup: function(id) {
- pointermap['delete'](id);
- },
- MSPointerDown: function(inEvent) {
- pointermap.set(inEvent.pointerId, inEvent);
- var e = this.prepareEvent(inEvent);
- dispatcher.down(e);
- },
- MSPointerMove: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- dispatcher.move(e);
- },
- MSPointerUp: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- dispatcher.up(e);
- this.cleanup(inEvent.pointerId);
- },
- MSPointerOut: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- dispatcher.leaveOut(e);
- },
- MSPointerOver: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- dispatcher.enterOver(e);
- },
- MSPointerCancel: function(inEvent) {
- var e = this.prepareEvent(inEvent);
- dispatcher.cancel(e);
- this.cleanup(inEvent.pointerId);
- },
- MSLostPointerCapture: function(inEvent) {
- var e = dispatcher.makeEvent('lostpointercapture', inEvent);
- dispatcher.dispatchEvent(e);
- },
- MSGotPointerCapture: function(inEvent) {
- var e = dispatcher.makeEvent('gotpointercapture', inEvent);
- dispatcher.dispatchEvent(e);
- }
- };
-
- scope.msEvents = msEvents;
-})(window.PointerEventsPolyfill);
-
-/*
- * 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.
- */
-
-/**
- * This module contains the handlers for native platform events.
- * From here, the dispatcher is called to create unified pointer events.
- * Included are touch events (v1), mouse events, and MSPointerEvents.
- */
-(function(scope) {
- var dispatcher = scope.dispatcher;
-
- // only activate if this platform does not have pointer events
- if (window.PointerEvent !== scope.PointerEvent) {
-
- if (window.navigator.msPointerEnabled) {
- var tp = window.navigator.msMaxTouchPoints;
- Object.defineProperty(window.navigator, 'maxTouchPoints', {
- value: tp,
- enumerable: true
- });
- dispatcher.registerSource('ms', scope.msEvents);
- } else {
- dispatcher.registerSource('mouse', scope.mouseEvents);
- if (window.ontouchstart !== undefined) {
- dispatcher.registerSource('touch', scope.touchEvents);
- }
- }
-
- dispatcher.register(document);
- }
-})(window.PointerEventsPolyfill);
-
-/*
- * 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) {
- var dispatcher = scope.dispatcher;
- var n = window.navigator;
- var s, r;
- function assertDown(id) {
- if (!dispatcher.pointermap.has(id)) {
- throw new Error('InvalidPointerId');
- }
- }
- if (n.msPointerEnabled) {
- s = function(pointerId) {
- assertDown(pointerId);
- this.msSetPointerCapture(pointerId);
- };
- r = function(pointerId) {
- assertDown(pointerId);
- this.msReleasePointerCapture(pointerId);
- };
- } else {
- s = function setPointerCapture(pointerId) {
- assertDown(pointerId);
- dispatcher.setCapture(pointerId, this);
- };
- r = function releasePointerCapture(pointerId) {
- assertDown(pointerId);
- dispatcher.releaseCapture(pointerId, this);
- };
- }
- if (window.Element && !Element.prototype.setPointerCapture) {
- Object.defineProperties(Element.prototype, {
- 'setPointerCapture': {
- value: s
- },
- 'releasePointerCapture': {
- value: r
- }
- });
- }
-})(window.PointerEventsPolyfill);
-
-/*
- * 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.
- */
-
-/**
- * PointerGestureEvent is the constructor for all PointerGesture events.
- *
- * @module PointerGestures
- * @class PointerGestureEvent
- * @extends UIEvent
- * @constructor
- * @param {String} inType Event type
- * @param {Object} [inDict] Dictionary of properties to initialize on the event
- */
-
-function PointerGestureEvent(inType, inDict) {
- var dict = inDict || {};
- var e = document.createEvent('Event');
- var props = {
- bubbles: Boolean(dict.bubbles) === dict.bubbles || true,
- cancelable: Boolean(dict.cancelable) === dict.cancelable || true
- };
-
- e.initEvent(inType, props.bubbles, props.cancelable);
-
- var keys = Object.keys(dict), k;
- for (var i = 0; i < keys.length; i++) {
- k = keys[i];
- e[k] = dict[k];
- }
-
- e.preventTap = this.preventTap;
-
- return e;
-}
-
-/**
- * Allows for any gesture to prevent the tap gesture.
- *
- * @method preventTap
- */
-PointerGestureEvent.prototype.preventTap = function() {
- this.tapPrevented = true;
-};
-
-
-/*
- * 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) {
- /**
- * This class contains the gesture recognizers that create the PointerGesture
- * events.
- *
- * @class PointerGestures
- * @static
- */
- scope = scope || {};
- scope.utils = {
- LCA: {
- // Determines the lowest node in the ancestor chain of a and b
- find: function(a, b) {
- if (a === b) {
- return a;
- }
- // fast case, a is a direct descendant of b or vice versa
- if (a.contains) {
- if (a.contains(b)) {
- return a;
- }
- if (b.contains(a)) {
- return b;
- }
- }
- var adepth = this.depth(a);
- var bdepth = this.depth(b);
- var d = adepth - bdepth;
- if (d > 0) {
- a = this.walk(a, d);
- } else {
- b = this.walk(b, -d);
- }
- while(a && b && a !== b) {
- a = this.walk(a, 1);
- b = this.walk(b, 1);
- }
- return a;
- },
- walk: function(n, u) {
- for (var i = 0; i < u; i++) {
- n = n.parentNode;
- }
- return n;
- },
- depth: function(n) {
- var d = 0;
- while(n) {
- d++;
- n = n.parentNode;
- }
- return d;
- }
- }
- };
- scope.findLCA = function(a, b) {
- return scope.utils.LCA.find(a, b);
- }
- window.PointerGestures = scope;
-})(window.PointerGestures);
-
-/*
- * 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.
- */
-
-/**
- * This module implements an map of pointer states
- */
-(function(scope) {
- var USE_MAP = window.Map && window.Map.prototype.forEach;
- var POINTERS_FN = function(){ return this.size; };
- function PointerMap() {
- if (USE_MAP) {
- var m = new Map();
- m.pointers = POINTERS_FN;
- return m;
- } else {
- this.keys = [];
- this.values = [];
- }
- }
-
- PointerMap.prototype = {
- set: function(inId, inEvent) {
- var i = this.keys.indexOf(inId);
- if (i > -1) {
- this.values[i] = inEvent;
- } else {
- this.keys.push(inId);
- this.values.push(inEvent);
- }
- },
- has: function(inId) {
- return this.keys.indexOf(inId) > -1;
- },
- 'delete': function(inId) {
- var i = this.keys.indexOf(inId);
- if (i > -1) {
- this.keys.splice(i, 1);
- this.values.splice(i, 1);
- }
- },
- get: function(inId) {
- var i = this.keys.indexOf(inId);
- return this.values[i];
- },
- clear: function() {
- this.keys.length = 0;
- this.values.length = 0;
- },
- // return value, key, map
- forEach: function(callback, thisArg) {
- this.values.forEach(function(v, i) {
- callback.call(thisArg, v, this.keys[i], this);
- }, this);
- },
- pointers: function() {
- return this.keys.length;
- }
- };
-
- scope.PointerMap = PointerMap;
-})(window.PointerGestures);
-
-/*
- * 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) {
- var CLONE_PROPS = [
- // MouseEvent
- 'bubbles',
- 'cancelable',
- 'view',
- 'detail',
- 'screenX',
- 'screenY',
- 'clientX',
- 'clientY',
- 'ctrlKey',
- 'altKey',
- 'shiftKey',
- 'metaKey',
- 'button',
- 'relatedTarget',
- // DOM Level 3
- 'buttons',
- // PointerEvent
- 'pointerId',
- 'width',
- 'height',
- 'pressure',
- 'tiltX',
- 'tiltY',
- 'pointerType',
- 'hwTimestamp',
- 'isPrimary',
- // event instance
- 'type',
- 'target',
- 'currentTarget',
- 'screenX',
- 'screenY',
- 'pageX',
- 'pageY',
- 'tapPrevented'
- ];
-
- var CLONE_DEFAULTS = [
- // MouseEvent
- false,
- false,
- null,
- null,
- 0,
- 0,
- 0,
- 0,
- false,
- false,
- false,
- false,
- 0,
- null,
- // DOM Level 3
- 0,
- // PointerEvent
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- '',
- 0,
- false,
- // event instance
- '',
- null,
- null,
- 0,
- 0,
- 0,
- 0
- ];
-
- var dispatcher = {
- handledEvents: new WeakMap(),
- targets: new WeakMap(),
- handlers: {},
- recognizers: {},
- events: {},
- // Add a new gesture recognizer to the event listeners.
- // Recognizer needs an `events` property.
- registerRecognizer: function(inName, inRecognizer) {
- var r = inRecognizer;
- this.recognizers[inName] = r;
- r.events.forEach(function(e) {
- if (r[e]) {
- this.events[e] = true;
- var f = r[e].bind(r);
- this.addHandler(e, f);
- }
- }, this);
- },
- addHandler: function(inEvent, inFn) {
- var e = inEvent;
- if (!this.handlers[e]) {
- this.handlers[e] = [];
- }
- this.handlers[e].push(inFn);
- },
- // add event listeners for inTarget
- registerTarget: function(inTarget) {
- this.listen(Object.keys(this.events), inTarget);
- },
- // remove event listeners for inTarget
- unregisterTarget: function(inTarget) {
- this.unlisten(Object.keys(this.events), inTarget);
- },
- // LISTENER LOGIC
- eventHandler: function(inEvent) {
- if (this.handledEvents.get(inEvent)) {
- return;
- }
- var type = inEvent.type, fns = this.handlers[type];
- if (fns) {
- this.makeQueue(fns, inEvent);
- }
- this.handledEvents.set(inEvent, true);
- },
- // queue event for async dispatch
- makeQueue: function(inHandlerFns, inEvent) {
- // must clone events to keep the (possibly shadowed) target correct for
- // async dispatching
- var e = this.cloneEvent(inEvent);
- requestAnimationFrame(this.runQueue.bind(this, inHandlerFns, e));
- },
- // Dispatch the queued events
- runQueue: function(inHandlers, inEvent) {
- this.currentPointerId = inEvent.pointerId;
- for (var i = 0, f, l = inHandlers.length; (i < l) && (f = inHandlers[i]); i++) {
- f(inEvent);
- }
- this.currentPointerId = 0;
- },
- // set up event listeners
- listen: function(inEvents, inTarget) {
- inEvents.forEach(function(e) {
- this.addEvent(e, this.boundHandler, false, inTarget);
- }, this);
- },
- // remove event listeners
- unlisten: function(inEvents) {
- inEvents.forEach(function(e) {
- this.removeEvent(e, this.boundHandler, false, inTarget);
- }, this);
- },
- addEvent: function(inEventName, inEventHandler, inCapture, inTarget) {
- inTarget.addEventListener(inEventName, inEventHandler, inCapture);
- },
- removeEvent: function(inEventName, inEventHandler, inCapture, inTarget) {
- inTarget.removeEventListener(inEventName, inEventHandler, inCapture);
- },
- // EVENT CREATION AND TRACKING
- // Creates a new Event of type `inType`, based on the information in
- // `inEvent`.
- makeEvent: function(inType, inDict) {
- return new PointerGestureEvent(inType, inDict);
- },
- /*
- * Returns a snapshot of inEvent, with writable properties.
- *
- * @method cloneEvent
- * @param {Event} inEvent An event that contains properties to copy.
- * @return {Object} An object containing shallow copies of `inEvent`'s
- * properties.
- */
- cloneEvent: function(inEvent) {
- var eventCopy = {}, p;
- for (var i = 0; i < CLONE_PROPS.length; i++) {
- p = CLONE_PROPS[i];
- eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
- }
- return eventCopy;
- },
- // Dispatches the event to its target.
- dispatchEvent: function(inEvent, inTarget) {
- var t = inTarget || this.targets.get(inEvent);
- if (t) {
- t.dispatchEvent(inEvent);
- if (inEvent.tapPrevented) {
- this.preventTap(this.currentPointerId);
- }
- }
- },
- asyncDispatchEvent: function(inEvent, inTarget) {
- requestAnimationFrame(this.dispatchEvent.bind(this, inEvent, inTarget));
- },
- preventTap: function(inPointerId) {
- var t = this.recognizers.tap;
- if (t){
- t.preventTap(inPointerId);
- }
- }
- };
- dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
- // recognizers call into the dispatcher and load later
- // solve the chicken and egg problem by having registerScopes module run last
- dispatcher.registerQueue = [];
- dispatcher.immediateRegister = false;
- scope.dispatcher = dispatcher;
- /**
- * Enable gesture events for a given scope, typically
- * [ShadowRoots](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#shadow-root-object).
- *
- * @for PointerGestures
- * @method register
- * @param {ShadowRoot} scope A top level scope to enable gesture
- * support on.
- */
- scope.register = function(inScope) {
- if (dispatcher.immediateRegister) {
- var pe = window.PointerEventsPolyfill;
- if (pe) {
- pe.register(inScope);
- }
- scope.dispatcher.registerTarget(inScope);
- } else {
- dispatcher.registerQueue.push(inScope);
- }
- };
- scope.register(document);
-})(window.PointerGestures);
-
-/*
- * 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.
- */
-
-/**
- * This event is fired when a pointer is held down for 200ms.
- *
- * @module PointerGestures
- * @submodule Events
- * @class hold
- */
-/**
- * Type of pointer that made the holding event.
- * @type String
- * @property pointerType
- */
-/**
- * Screen X axis position of the held pointer
- * @type Number
- * @property clientX
- */
-/**
- * Screen Y axis position of the held pointer
- * @type Number
- * @property clientY
- */
-/**
- * Type of pointer that made the holding event.
- * @type String
- * @property pointerType
- */
-/**
- * This event is fired every 200ms while a pointer is held down.
- *
- * @class holdpulse
- * @extends hold
- */
-/**
- * Milliseconds pointer has been held down.
- * @type Number
- * @property holdTime
- */
-/**
- * This event is fired when a held pointer is released or moved.
- *
- * @class released
- */
-
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var hold = {
- // wait at least HOLD_DELAY ms between hold and pulse events
- HOLD_DELAY: 200,
- // pointer can move WIGGLE_THRESHOLD pixels before not counting as a hold
- WIGGLE_THRESHOLD: 16,
- events: [
- 'pointerdown',
- 'pointermove',
- 'pointerup',
- 'pointercancel'
- ],
- heldPointer: null,
- holdJob: null,
- pulse: function() {
- var hold = Date.now() - this.heldPointer.timeStamp;
- var type = this.held ? 'holdpulse' : 'hold';
- this.fireHold(type, hold);
- this.held = true;
- },
- cancel: function() {
- clearInterval(this.holdJob);
- if (this.held) {
- this.fireHold('release');
- }
- this.held = false;
- this.heldPointer = null;
- this.target = null;
- this.holdJob = null;
- },
- pointerdown: function(inEvent) {
- if (inEvent.isPrimary && !this.heldPointer) {
- this.heldPointer = inEvent;
- this.target = inEvent.target;
- this.holdJob = setInterval(this.pulse.bind(this), this.HOLD_DELAY);
- }
- },
- pointerup: function(inEvent) {
- if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
- this.cancel();
- }
- },
- pointercancel: function(inEvent) {
- this.cancel();
- },
- pointermove: function(inEvent) {
- if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
- var x = inEvent.clientX - this.heldPointer.clientX;
- var y = inEvent.clientY - this.heldPointer.clientY;
- if ((x * x + y * y) > this.WIGGLE_THRESHOLD) {
- this.cancel();
- }
- }
- },
- fireHold: function(inType, inHoldTime) {
- var p = {
- pointerType: this.heldPointer.pointerType,
- clientX: this.heldPointer.clientX,
- clientY: this.heldPointer.clientY
- };
- if (inHoldTime) {
- p.holdTime = inHoldTime;
- }
- var e = dispatcher.makeEvent(inType, p);
- dispatcher.dispatchEvent(e, this.target);
- if (e.tapPrevented) {
- dispatcher.preventTap(this.heldPointer.pointerId);
- }
- }
- };
- dispatcher.registerRecognizer('hold', hold);
-})(window.PointerGestures);
-
-/*
- * 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.
- */
-
-/**
- * This event denotes the beginning of a series of tracking events.
- *
- * @module PointerGestures
- * @submodule Events
- * @class trackstart
- */
-/**
- * Pixels moved in the x direction since trackstart.
- * @type Number
- * @property dx
- */
-/**
- * Pixes moved in the y direction since trackstart.
- * @type Number
- * @property dy
- */
-/**
- * Pixels moved in the x direction since the last track.
- * @type Number
- * @property ddx
- */
-/**
- * Pixles moved in the y direction since the last track.
- * @type Number
- * @property ddy
- */
-/**
- * The clientX position of the track gesture.
- * @type Number
- * @property clientX
- */
-/**
- * The clientY position of the track gesture.
- * @type Number
- * @property clientY
- */
-/**
- * The pageX position of the track gesture.
- * @type Number
- * @property pageX
- */
-/**
- * The pageY position of the track gesture.
- * @type Number
- * @property pageY
- */
-/**
- * The screenX position of the track gesture.
- * @type Number
- * @property screenX
- */
-/**
- * The screenY position of the track gesture.
- * @type Number
- * @property screenY
- */
-/**
- * The last x axis direction of the pointer.
- * @type Number
- * @property xDirection
- */
-/**
- * The last y axis direction of the pointer.
- * @type Number
- * @property yDirection
- */
-/**
- * A shared object between all tracking events.
- * @type Object
- * @property trackInfo
- */
-/**
- * The element currently under the pointer.
- * @type Element
- * @property relatedTarget
- */
-/**
- * The type of pointer that make the track gesture.
- * @type String
- * @property pointerType
- */
-/**
- *
- * This event fires for all pointer movement being tracked.
- *
- * @class track
- * @extends trackstart
- */
-/**
- * This event fires when the pointer is no longer being tracked.
- *
- * @class trackend
- * @extends trackstart
- */
-
- (function(scope) {
- var dispatcher = scope.dispatcher;
- var pointermap = new scope.PointerMap();
- var track = {
- events: [
- 'pointerdown',
- 'pointermove',
- 'pointerup',
- 'pointercancel'
- ],
- WIGGLE_THRESHOLD: 4,
- clampDir: function(inDelta) {
- return inDelta > 0 ? 1 : -1;
- },
- calcPositionDelta: function(inA, inB) {
- var x = 0, y = 0;
- if (inA && inB) {
- x = inB.pageX - inA.pageX;
- y = inB.pageY - inA.pageY;
- }
- return {x: x, y: y};
- },
- fireTrack: function(inType, inEvent, inTrackingData) {
- var t = inTrackingData;
- var d = this.calcPositionDelta(t.downEvent, inEvent);
- var dd = this.calcPositionDelta(t.lastMoveEvent, inEvent);
- if (dd.x) {
- t.xDirection = this.clampDir(dd.x);
- }
- if (dd.y) {
- t.yDirection = this.clampDir(dd.y);
- }
- var trackData = {
- dx: d.x,
- dy: d.y,
- ddx: dd.x,
- ddy: dd.y,
- clientX: inEvent.clientX,
- clientY: inEvent.clientY,
- pageX: inEvent.pageX,
- pageY: inEvent.pageY,
- screenX: inEvent.screenX,
- screenY: inEvent.screenY,
- xDirection: t.xDirection,
- yDirection: t.yDirection,
- trackInfo: t.trackInfo,
- relatedTarget: inEvent.target,
- pointerType: inEvent.pointerType
- };
- var e = dispatcher.makeEvent(inType, trackData);
- t.lastMoveEvent = inEvent;
- dispatcher.dispatchEvent(e, t.downTarget);
- },
- pointerdown: function(inEvent) {
- if (inEvent.isPrimary && (inEvent.pointerType === 'mouse' ? inEvent.buttons === 1 : true)) {
- var p = {
- downEvent: inEvent,
- downTarget: inEvent.target,
- trackInfo: {},
- lastMoveEvent: null,
- xDirection: 0,
- yDirection: 0,
- tracking: false
- };
- pointermap.set(inEvent.pointerId, p);
- }
- },
- pointermove: function(inEvent) {
- var p = pointermap.get(inEvent.pointerId);
- if (p) {
- if (!p.tracking) {
- var d = this.calcPositionDelta(p.downEvent, inEvent);
- var move = d.x * d.x + d.y * d.y;
- // start tracking only if finger moves more than WIGGLE_THRESHOLD
- if (move > this.WIGGLE_THRESHOLD) {
- p.tracking = true;
- this.fireTrack('trackstart', p.downEvent, p);
- this.fireTrack('track', inEvent, p);
- }
- } else {
- this.fireTrack('track', inEvent, p);
- }
- }
- },
- pointerup: function(inEvent) {
- var p = pointermap.get(inEvent.pointerId);
- if (p) {
- if (p.tracking) {
- this.fireTrack('trackend', inEvent, p);
- }
- pointermap.delete(inEvent.pointerId);
- }
- },
- pointercancel: function(inEvent) {
- this.pointerup(inEvent);
- }
- };
- dispatcher.registerRecognizer('track', track);
- })(window.PointerGestures);
-
-/*
- * 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.
- */
-
-/**
- * This event denotes a rapid down/move/up sequence from a pointer.
- *
- * The event is sent to the first element the pointer went down on.
- *
- * @module PointerGestures
- * @submodule Events
- * @class flick
- */
-/**
- * Signed velocity of the flick in the x direction.
- * @property xVelocity
- * @type Number
- */
-/**
- * Signed velocity of the flick in the y direction.
- * @type Number
- * @property yVelocity
- */
-/**
- * Unsigned total velocity of the flick.
- * @type Number
- * @property velocity
- */
-/**
- * Angle of the flick in degrees, with 0 along the
- * positive x axis.
- * @type Number
- * @property angle
- */
-/**
- * Axis with the greatest absolute velocity. Denoted
- * with 'x' or 'y'.
- * @type String
- * @property majorAxis
- */
-/**
- * Type of the pointer that made the flick.
- * @type String
- * @property pointerType
- */
-
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var flick = {
- // TODO(dfreedman): value should be low enough for low speed flicks, but
- // high enough to remove accidental flicks
- MIN_VELOCITY: 0.5 /* px/ms */,
- MAX_QUEUE: 4,
- moveQueue: [],
- target: null,
- pointerId: null,
- events: [
- 'pointerdown',
- 'pointermove',
- 'pointerup',
- 'pointercancel'
- ],
- pointerdown: function(inEvent) {
- if (inEvent.isPrimary && !this.pointerId) {
- this.pointerId = inEvent.pointerId;
- this.target = inEvent.target;
- this.addMove(inEvent);
- }
- },
- pointermove: function(inEvent) {
- if (inEvent.pointerId === this.pointerId) {
- this.addMove(inEvent);
- }
- },
- pointerup: function(inEvent) {
- if (inEvent.pointerId === this.pointerId) {
- this.fireFlick(inEvent);
- }
- this.cleanup();
- },
- pointercancel: function(inEvent) {
- this.cleanup();
- },
- cleanup: function() {
- this.moveQueue = [];
- this.target = null;
- this.pointerId = null;
- },
- addMove: function(inEvent) {
- if (this.moveQueue.length >= this.MAX_QUEUE) {
- this.moveQueue.shift();
- }
- this.moveQueue.push(inEvent);
- },
- fireFlick: function(inEvent) {
- var e = inEvent;
- var l = this.moveQueue.length;
- var dt, dx, dy, tx, ty, tv, x = 0, y = 0, v = 0;
- // flick based off the fastest segment of movement
- for (var i = 0, m; i < l && (m = this.moveQueue[i]); i++) {
- dt = e.timeStamp - m.timeStamp;
- dx = e.clientX - m.clientX, dy = e.clientY - m.clientY;
- tx = dx / dt, ty = dy / dt, tv = Math.sqrt(tx * tx + ty * ty);
- if (tv > v) {
- x = tx, y = ty, v = tv;
- }
- }
- var ma = Math.abs(x) > Math.abs(y) ? 'x' : 'y';
- var a = this.calcAngle(x, y);
- if (Math.abs(v) >= this.MIN_VELOCITY) {
- var ev = dispatcher.makeEvent('flick', {
- xVelocity: x,
- yVelocity: y,
- velocity: v,
- angle: a,
- majorAxis: ma,
- pointerType: inEvent.pointerType
- });
- dispatcher.dispatchEvent(ev, this.target);
- }
- },
- calcAngle: function(inX, inY) {
- return (Math.atan2(inY, inX) * 180 / Math.PI);
- }
- };
- dispatcher.registerRecognizer('flick', flick);
-})(window.PointerGestures);
-
-/*
- * 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.
- */
-
-/*
- * Basic strategy: find the farthest apart points, use as diameter of circle
- * react to size change and rotation of the chord
- */
-
-/**
- * @module PointerGestures
- * @submodule Events
- * @class pinch
- */
-/**
- * Scale of the pinch zoom gesture
- * @property scale
- * @type Number
- */
-/**
- * Center X position of pointers causing pinch
- * @property centerX
- * @type Number
- */
-/**
- * Center Y position of pointers causing pinch
- * @property centerY
- * @type Number
- */
-
-/**
- * @module PointerGestures
- * @submodule Events
- * @class rotate
- */
-/**
- * Angle (in degrees) of rotation. Measured from starting positions of pointers.
- * @property angle
- * @type Number
- */
-/**
- * Center X position of pointers causing rotation
- * @property centerX
- * @type Number
- */
-/**
- * Center Y position of pointers causing rotation
- * @property centerY
- * @type Number
- */
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var pointermap = new scope.PointerMap();
- var RAD_TO_DEG = 180 / Math.PI;
- var pinch = {
- events: [
- 'pointerdown',
- 'pointermove',
- 'pointerup',
- 'pointercancel'
- ],
- reference: {},
- pointerdown: function(ev) {
- pointermap.set(ev.pointerId, ev);
- if (pointermap.pointers() == 2) {
- var points = this.calcChord();
- var angle = this.calcAngle(points);
- this.reference = {
- angle: angle,
- diameter: points.diameter,
- target: scope.findLCA(points.a.target, points.b.target)
- };
- }
- },
- pointerup: function(ev) {
- pointermap.delete(ev.pointerId);
- },
- pointermove: function(ev) {
- if (pointermap.has(ev.pointerId)) {
- pointermap.set(ev.pointerId, ev);
- if (pointermap.pointers() > 1) {
- this.calcPinchRotate();
- }
- }
- },
- pointercancel: function(ev) {
- this.pointerup(ev);
- },
- dispatchPinch: function(diameter, points) {
- var zoom = diameter / this.reference.diameter;
- var ev = dispatcher.makeEvent('pinch', {
- scale: zoom,
- centerX: points.center.x,
- centerY: points.center.y
- });
- dispatcher.dispatchEvent(ev, this.reference.target);
- },
- dispatchRotate: function(angle, points) {
- var diff = Math.round((angle - this.reference.angle) % 360);
- var ev = dispatcher.makeEvent('rotate', {
- angle: diff,
- centerX: points.center.x,
- centerY: points.center.y
- });
- dispatcher.dispatchEvent(ev, this.reference.target);
- },
- calcPinchRotate: function() {
- var points = this.calcChord();
- var diameter = points.diameter;
- var angle = this.calcAngle(points);
- if (diameter != this.reference.diameter) {
- this.dispatchPinch(diameter, points);
- }
- if (angle != this.reference.angle) {
- this.dispatchRotate(angle, points);
- }
- },
- calcChord: function() {
- var pointers = [];
- pointermap.forEach(function(p) {
- pointers.push(p);
- });
- var dist = 0;
- // start with at least two pointers
- var points = {a: pointers[0], b: pointers[1]};
- var x, y, d;
- for (var i = 0; i < pointers.length; i++) {
- var a = pointers[i];
- for (var j = i + 1; j < pointers.length; j++) {
- var b = pointers[j];
- x = Math.abs(a.clientX - b.clientX);
- y = Math.abs(a.clientY - b.clientY);
- d = x + y;
- if (d > dist) {
- dist = d;
- points = {a: a, b: b};
- }
- }
- }
- x = Math.abs(points.a.clientX + points.b.clientX) / 2;
- y = Math.abs(points.a.clientY + points.b.clientY) / 2;
- points.center = { x: x, y: y };
- points.diameter = dist;
- return points;
- },
- calcAngle: function(points) {
- var x = points.a.clientX - points.b.clientX;
- var y = points.a.clientY - points.b.clientY;
- return (360 + Math.atan2(y, x) * RAD_TO_DEG) % 360;
- },
- };
- dispatcher.registerRecognizer('pinch', pinch);
-})(window.PointerGestures);
-
-/*
- * 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.
- */
-
-/**
- * This event is fired when a pointer quickly goes down and up, and is used to
- * denote activation.
- *
- * Any gesture event can prevent the tap event from being created by calling
- * `event.preventTap`.
- *
- * Any pointer event can prevent the tap by setting the `tapPrevented` property
- * on itself.
- *
- * @module PointerGestures
- * @submodule Events
- * @class tap
- */
-/**
- * X axis position of the tap.
- * @property x
- * @type Number
- */
-/**
- * Y axis position of the tap.
- * @property y
- * @type Number
- */
-/**
- * Type of the pointer that made the tap.
- * @property pointerType
- * @type String
- */
-(function(scope) {
- var dispatcher = scope.dispatcher;
- var pointermap = new scope.PointerMap();
- var tap = {
- events: [
- 'pointerdown',
- 'pointermove',
- 'pointerup',
- 'pointercancel',
- 'keyup'
- ],
- pointerdown: function(inEvent) {
- if (inEvent.isPrimary && !inEvent.tapPrevented) {
- pointermap.set(inEvent.pointerId, {
- target: inEvent.target,
- buttons: inEvent.buttons,
- x: inEvent.clientX,
- y: inEvent.clientY
- });
- }
- },
- pointermove: function(inEvent) {
- if (inEvent.isPrimary) {
- var start = pointermap.get(inEvent.pointerId);
- if (start) {
- if (inEvent.tapPrevented) {
- pointermap.delete(inEvent.pointerId);
- }
- }
- }
- },
- shouldTap: function(e, downState) {
- if (!e.tapPrevented) {
- if (e.pointerType === 'mouse') {
- // only allow left click to tap for mouse
- return downState.buttons === 1;
- } else {
- return true;
- }
- }
- },
- pointerup: function(inEvent) {
- var start = pointermap.get(inEvent.pointerId);
- if (start && this.shouldTap(inEvent, start)) {
- var t = scope.findLCA(start.target, inEvent.target);
- if (t) {
- var e = dispatcher.makeEvent('tap', {
- x: inEvent.clientX,
- y: inEvent.clientY,
- detail: inEvent.detail,
- pointerType: inEvent.pointerType
- });
- dispatcher.dispatchEvent(e, t);
- }
- }
- pointermap.delete(inEvent.pointerId);
- },
- pointercancel: function(inEvent) {
- pointermap.delete(inEvent.pointerId);
- },
- keyup: function(inEvent) {
- var code = inEvent.keyCode;
- // 32 == spacebar
- if (code === 32) {
- var t = inEvent.target;
- if (!(t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement)) {
- dispatcher.dispatchEvent(dispatcher.makeEvent('tap', {
- x: 0,
- y: 0,
- detail: 0,
- pointerType: 'unavailable'
- }), t);
- }
- }
- },
- preventTap: function(inPointerId) {
- pointermap.delete(inPointerId);
- }
- };
- dispatcher.registerRecognizer('tap', tap);
-})(window.PointerGestures);
-
-/*
- * Copyright 2014 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.
- */
-
-/**
- * Because recognizers are loaded after dispatcher, we have to wait to register
- * scopes until after all the recognizers.
- */
-(function(scope) {
- var dispatcher = scope.dispatcher;
- function registerScopes() {
- dispatcher.immediateRegister = true;
- var rq = dispatcher.registerQueue;
- rq.forEach(scope.register);
- rq.length = 0;
- }
- if (document.readyState === 'complete') {
- registerScopes();
- } else {
- // register scopes after a steadystate is reached
- // less MutationObserver churn
- document.addEventListener('readystatechange', function() {
- if (document.readyState === 'complete') {
- registerScopes();
- }
- });
- }
-})(window.PointerGestures);
-
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-// Code distributed by Google as part of the polymer project is also
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-
-(function(global) {
- 'use strict';
-
- var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
-
- function getTreeScope(node) {
- while (node.parentNode) {
- node = node.parentNode;
- }
-
- return typeof node.getElementById === 'function' ? node : null;
- }
-
- Node.prototype.bind = function(name, observable) {
- console.error('Unhandled binding to Node: ', this, name, observable);
- };
-
- function updateBindings(node, name, binding) {
- var bindings = node.bindings_;
- if (!bindings)
- bindings = node.bindings_ = {};
-
- if (bindings[name])
- binding[name].close();
-
- return bindings[name] = binding;
- }
-
- function returnBinding(node, name, binding) {
- return binding;
- }
-
- function sanitizeValue(value) {
- return value == null ? '' : value;
- }
-
- function updateText(node, value) {
- node.data = sanitizeValue(value);
- }
-
- function textBinding(node) {
- return function(value) {
- return updateText(node, value);
- };
- }
-
- var maybeUpdateBindings = returnBinding;
-
- Object.defineProperty(Platform, 'enableBindingsReflection', {
- get: function() {
- return maybeUpdateBindings === updateBindings;
- },
- set: function(enable) {
- maybeUpdateBindings = enable ? updateBindings : returnBinding;
- return enable;
- },
- configurable: true
- });
-
- Text.prototype.bind = function(name, value, oneTime) {
- if (name !== 'textContent')
- return Node.prototype.bind.call(this, name, value, oneTime);
-
- if (oneTime)
- return updateText(this, value);
-
- var observable = value;
- updateText(this, observable.open(textBinding(this)));
- return maybeUpdateBindings(this, name, observable);
- }
-
- function updateAttribute(el, name, conditional, value) {
- if (conditional) {
- if (value)
- el.setAttribute(name, '');
- else
- el.removeAttribute(name);
- return;
- }
-
- el.setAttribute(name, sanitizeValue(value));
- }
-
- function attributeBinding(el, name, conditional) {
- return function(value) {
- updateAttribute(el, name, conditional, value);
- };
- }
-
- Element.prototype.bind = function(name, value, oneTime) {
- var conditional = name[name.length - 1] == '?';
- if (conditional) {
- this.removeAttribute(name);
- name = name.slice(0, -1);
- }
-
- if (oneTime)
- return updateAttribute(this, name, conditional, value);
-
-
- var observable = value;
- updateAttribute(this, name, conditional,
- observable.open(attributeBinding(this, name, conditional)));
-
- return maybeUpdateBindings(this, name, observable);
- };
-
- var checkboxEventType;
- (function() {
- // Attempt to feature-detect which event (change or click) is fired first
- // for checkboxes.
- var div = document.createElement('div');
- var checkbox = div.appendChild(document.createElement('input'));
- checkbox.setAttribute('type', 'checkbox');
- var first;
- var count = 0;
- checkbox.addEventListener('click', function(e) {
- count++;
- first = first || 'click';
- });
- checkbox.addEventListener('change', function() {
- count++;
- first = first || 'change';
- });
-
- var event = document.createEvent('MouseEvent');
- event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
- false, false, false, 0, null);
- checkbox.dispatchEvent(event);
- // WebKit/Blink don't fire the change event if the element is outside the
- // document, so assume 'change' for that case.
- checkboxEventType = count == 1 ? 'change' : first;
- })();
-
- function getEventForInputType(element) {
- switch (element.type) {
- case 'checkbox':
- return checkboxEventType;
- case 'radio':
- case 'select-multiple':
- case 'select-one':
- return 'change';
- case 'range':
- if (/Trident|MSIE/.test(navigator.userAgent))
- return 'change';
- default:
- return 'input';
- }
- }
-
- function updateInput(input, property, value, santizeFn) {
- input[property] = (santizeFn || sanitizeValue)(value);
- }
-
- function inputBinding(input, property, santizeFn) {
- return function(value) {
- return updateInput(input, property, value, santizeFn);
- }
- }
-
- function noop() {}
-
- function bindInputEvent(input, property, observable, postEventFn) {
- var eventType = getEventForInputType(input);
-
- function eventHandler() {
- observable.setValue(input[property]);
- observable.discardChanges();
- (postEventFn || noop)(input);
- Platform.performMicrotaskCheckpoint();
- }
- input.addEventListener(eventType, eventHandler);
-
- return {
- close: function() {
- input.removeEventListener(eventType, eventHandler);
- observable.close();
- },
-
- observable_: observable
- }
- }
-
- function booleanSanitize(value) {
- return Boolean(value);
- }
-
- // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
- // Returns an array containing all radio buttons other than |element| that
- // have the same |name|, either in the form that |element| belongs to or,
- // if no form, in the document tree to which |element| belongs.
- //
- // This implementation is based upon the HTML spec definition of a
- // "radio button group":
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
- //
- function getAssociatedRadioButtons(element) {
- if (element.form) {
- return filter(element.form.elements, function(el) {
- return el != element &&
- el.tagName == 'INPUT' &&
- el.type == 'radio' &&
- el.name == element.name;
- });
- } else {
- var treeScope = getTreeScope(element);
- if (!treeScope)
- return [];
- var radios = treeScope.querySelectorAll(
- 'input[type="radio"][name="' + element.name + '"]');
- return filter(radios, function(el) {
- return el != element && !el.form;
- });
- }
- }
-
- function checkedPostEvent(input) {
- // Only the radio button that is getting checked gets an event. We
- // therefore find all the associated radio buttons and update their
- // check binding manually.
- if (input.tagName === 'INPUT' &&
- input.type === 'radio') {
- getAssociatedRadioButtons(input).forEach(function(radio) {
- var checkedBinding = radio.bindings_.checked;
- if (checkedBinding) {
- // Set the value directly to avoid an infinite call stack.
- checkedBinding.observable_.setValue(false);
- }
- });
- }
- }
-
- HTMLInputElement.prototype.bind = function(name, value, oneTime) {
- if (name !== 'value' && name !== 'checked')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute(name);
- var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue;
- var postEventFn = name == 'checked' ? checkedPostEvent : noop;
-
- if (oneTime)
- return updateInput(this, name, value, sanitizeFn);
-
-
- var observable = value;
- var binding = bindInputEvent(this, name, observable, postEventFn);
- updateInput(this, name,
- observable.open(inputBinding(this, name, sanitizeFn)),
- sanitizeFn);
-
- // Checkboxes may need to update bindings of other checkboxes.
- return updateBindings(this, name, binding);
- }
-
- HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
- if (name !== 'value')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute('value');
-
- if (oneTime)
- return updateInput(this, 'value', value);
-
- var observable = value;
- var binding = bindInputEvent(this, 'value', observable);
- updateInput(this, 'value',
- observable.open(inputBinding(this, 'value', sanitizeValue)));
- return maybeUpdateBindings(this, name, binding);
- }
-
- function updateOption(option, value) {
- var parentNode = option.parentNode;;
- var select;
- var selectBinding;
- var oldValue;
- if (parentNode instanceof HTMLSelectElement &&
- parentNode.bindings_ &&
- parentNode.bindings_.value) {
- select = parentNode;
- selectBinding = select.bindings_.value;
- oldValue = select.value;
- }
-
- option.value = sanitizeValue(value);
-
- if (select && select.value != oldValue) {
- selectBinding.observable_.setValue(select.value);
- selectBinding.observable_.discardChanges();
- Platform.performMicrotaskCheckpoint();
- }
- }
-
- function optionBinding(option) {
- return function(value) {
- updateOption(option, value);
- }
- }
-
- HTMLOptionElement.prototype.bind = function(name, value, oneTime) {
- if (name !== 'value')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute('value');
-
- if (oneTime)
- return updateOption(this, value);
-
- var observable = value;
- var binding = bindInputEvent(this, 'value', observable);
- updateOption(this, observable.open(optionBinding(this)));
- return maybeUpdateBindings(this, name, binding);
- }
-
- HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
- if (name === 'selectedindex')
- name = 'selectedIndex';
-
- if (name !== 'selectedIndex' && name !== 'value')
- return HTMLElement.prototype.bind.call(this, name, value, oneTime);
-
- this.removeAttribute(name);
-
- if (oneTime)
- return updateInput(this, name, value);
-
- var observable = value;
- var binding = bindInputEvent(this, name, observable);
- updateInput(this, name,
- observable.open(inputBinding(this, name)));
-
- // Option update events may need to access select bindings.
- return updateBindings(this, name, binding);
- }
-})(this);
-
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-// Code distributed by Google as part of the polymer project is also
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-
-(function(global) {
- 'use strict';
-
- function assert(v) {
- if (!v)
- throw new Error('Assertion failed');
- }
-
- var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
-
- function getFragmentRoot(node) {
- var p;
- while (p = node.parentNode) {
- node = p;
- }
-
- return node;
- }
-
- function searchRefId(node, id) {
- if (!id)
- return;
-
- var ref;
- var selector = '#' + id;
- while (!ref) {
- node = getFragmentRoot(node);
-
- if (node.protoContent_)
- ref = node.protoContent_.querySelector(selector);
- else if (node.getElementById)
- ref = node.getElementById(id);
-
- if (ref || !node.templateCreator_)
- break
-
- node = node.templateCreator_;
- }
-
- return ref;
- }
-
- function getInstanceRoot(node) {
- while (node.parentNode) {
- node = node.parentNode;
- }
- return node.templateCreator_ ? node : null;
- }
-
- var Map;
- if (global.Map && typeof global.Map.prototype.forEach === 'function') {
- Map = global.Map;
- } else {
- Map = function() {
- this.keys = [];
- this.values = [];
- };
-
- Map.prototype = {
- set: function(key, value) {
- var index = this.keys.indexOf(key);
- if (index < 0) {
- this.keys.push(key);
- this.values.push(value);
- } else {
- this.values[index] = value;
- }
- },
-
- get: function(key) {
- var index = this.keys.indexOf(key);
- if (index < 0)
- return;
-
- return this.values[index];
- },
-
- delete: function(key, value) {
- var index = this.keys.indexOf(key);
- if (index < 0)
- return false;
-
- this.keys.splice(index, 1);
- this.values.splice(index, 1);
- return true;
- },
-
- forEach: function(f, opt_this) {
- for (var i = 0; i < this.keys.length; i++)
- f.call(opt_this || this, this.values[i], this.keys[i], this);
- }
- };
- }
-
- // JScript does not have __proto__. We wrap all object literals with
- // createObject which uses Object.create, Object.defineProperty and
- // Object.getOwnPropertyDescriptor to create a new object that does the exact
- // same thing. The main downside to this solution is that we have to extract
- // all those property descriptors for IE.
- var createObject = ('__proto__' in {}) ?
- function(obj) { return obj; } :
- function(obj) {
- var proto = obj.__proto__;
- if (!proto)
- return obj;
- var newObject = Object.create(proto);
- Object.getOwnPropertyNames(obj).forEach(function(name) {
- Object.defineProperty(newObject, name,
- Object.getOwnPropertyDescriptor(obj, name));
- });
- return newObject;
- };
-
- // IE does not support have Document.prototype.contains.
- if (typeof document.contains != 'function') {
- Document.prototype.contains = function(node) {
- if (node === this || node.parentNode === this)
- return true;
- return this.documentElement.contains(node);
- }
- }
-
- var BIND = 'bind';
- var REPEAT = 'repeat';
- var IF = 'if';
-
- var templateAttributeDirectives = {
- 'template': true,
- 'repeat': true,
- 'bind': true,
- 'ref': true
- };
-
- var semanticTemplateElements = {
- 'THEAD': true,
- 'TBODY': true,
- 'TFOOT': true,
- 'TH': true,
- 'TR': true,
- 'TD': true,
- 'COLGROUP': true,
- 'COL': true,
- 'CAPTION': true,
- 'OPTION': true,
- 'OPTGROUP': true
- };
-
- var hasTemplateElement = typeof HTMLTemplateElement !== 'undefined';
- if (hasTemplateElement) {
- // TODO(rafaelw): Remove when fix for
- // https://codereview.chromium.org/164803002/
- // makes it to Chrome release.
- (function() {
- var t = document.createElement('template');
- var d = t.content.ownerDocument;
- var html = d.appendChild(d.createElement('html'));
- var head = html.appendChild(d.createElement('head'));
- var base = d.createElement('base');
- base.href = document.baseURI;
- head.appendChild(base);
- })();
- }
-
- var allTemplatesSelectors = 'template, ' +
- Object.keys(semanticTemplateElements).map(function(tagName) {
- return tagName.toLowerCase() + '[template]';
- }).join(', ');
-
- function isSVGTemplate(el) {
- return el.tagName == 'template' &&
- el.namespaceURI == 'http://www.w3.org/2000/svg';
- }
-
- function isHTMLTemplate(el) {
- return el.tagName == 'TEMPLATE' &&
- el.namespaceURI == 'http://www.w3.org/1999/xhtml';
- }
-
- function isAttributeTemplate(el) {
- return Boolean(semanticTemplateElements[el.tagName] &&
- el.hasAttribute('template'));
- }
-
- function isTemplate(el) {
- if (el.isTemplate_ === undefined)
- el.isTemplate_ = el.tagName == 'TEMPLATE' || isAttributeTemplate(el);
-
- return el.isTemplate_;
- }
-
- // FIXME: Observe templates being added/removed from documents
- // FIXME: Expose imperative API to decorate and observe templates in
- // "disconnected tress" (e.g. ShadowRoot)
- document.addEventListener('DOMContentLoaded', function(e) {
- bootstrapTemplatesRecursivelyFrom(document);
- // FIXME: Is this needed? Seems like it shouldn't be.
- Platform.performMicrotaskCheckpoint();
- }, false);
-
- function forAllTemplatesFrom(node, fn) {
- var subTemplates = node.querySelectorAll(allTemplatesSelectors);
-
- if (isTemplate(node))
- fn(node)
- forEach(subTemplates, fn);
- }
-
- function bootstrapTemplatesRecursivelyFrom(node) {
- function bootstrap(template) {
- if (!HTMLTemplateElement.decorate(template))
- bootstrapTemplatesRecursivelyFrom(template.content);
- }
-
- forAllTemplatesFrom(node, bootstrap);
- }
-
- if (!hasTemplateElement) {
- /**
- * This represents a <template> element.
- * @constructor
- * @extends {HTMLElement}
- */
- global.HTMLTemplateElement = function() {
- throw TypeError('Illegal constructor');
- };
- }
-
- var hasProto = '__proto__' in {};
-
- function mixin(to, from) {
- Object.getOwnPropertyNames(from).forEach(function(name) {
- Object.defineProperty(to, name,
- Object.getOwnPropertyDescriptor(from, name));
- });
- }
-
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- function getOrCreateTemplateContentsOwner(template) {
- var doc = template.ownerDocument
- if (!doc.defaultView)
- return doc;
- var d = doc.templateContentsOwner_;
- 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);
- }
- doc.templateContentsOwner_ = d;
- }
- return d;
- }
-
- function getTemplateStagingDocument(template) {
- if (!template.stagingDocument_) {
- var owner = template.ownerDocument;
- if (!owner.stagingDocument_) {
- owner.stagingDocument_ = owner.implementation.createHTMLDocument('');
-
- // TODO(rafaelw): Remove when fix for
- // https://codereview.chromium.org/164803002/
- // makes it to Chrome release.
- var base = owner.stagingDocument_.createElement('base');
- base.href = document.baseURI;
- owner.stagingDocument_.head.appendChild(base);
-
- owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_;
- }
-
- template.stagingDocument_ = owner.stagingDocument_;
- }
-
- return template.stagingDocument_;
- }
-
- // For non-template browsers, the parser will disallow <template> in certain
- // locations, so we allow "attribute templates" which combine the template
- // element with the top-level container node of the content, e.g.
- //
- // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr>
- //
- // becomes
- //
- // <template repeat="{{ foo }}">
- // + #document-fragment
- // + <tr class="bar">
- // + <td>Bar</td>
- //
- function extractTemplateFromAttributeTemplate(el) {
- var template = el.ownerDocument.createElement('template');
- el.parentNode.insertBefore(template, el);
-
- var attribs = el.attributes;
- var count = attribs.length;
- while (count-- > 0) {
- var attrib = attribs[count];
- if (templateAttributeDirectives[attrib.name]) {
- if (attrib.name !== 'template')
- template.setAttribute(attrib.name, attrib.value);
- el.removeAttribute(attrib.name);
- }
- }
-
- return template;
- }
-
- function extractTemplateFromSVGTemplate(el) {
- var template = el.ownerDocument.createElement('template');
- el.parentNode.insertBefore(template, el);
-
- var attribs = el.attributes;
- var count = attribs.length;
- while (count-- > 0) {
- var attrib = attribs[count];
- template.setAttribute(attrib.name, attrib.value);
- el.removeAttribute(attrib.name);
- }
-
- el.parentNode.removeChild(el);
- return template;
- }
-
- function liftNonNativeTemplateChildrenIntoContent(template, el, useRoot) {
- var content = template.content;
- if (useRoot) {
- content.appendChild(el);
- return;
- }
-
- var child;
- while (child = el.firstChild) {
- content.appendChild(child);
- }
- }
-
- var templateObserver;
- if (typeof MutationObserver == 'function') {
- templateObserver = new MutationObserver(function(records) {
- for (var i = 0; i < records.length; i++) {
- records[i].target.refChanged_();
- }
- });
- }
-
- /**
- * Ensures proper API and content model for template elements.
- * @param {HTMLTemplateElement} opt_instanceRef The template element which
- * |el| template element will return as the value of its ref(), and whose
- * content will be used as source when createInstance() is invoked.
- */
- HTMLTemplateElement.decorate = function(el, opt_instanceRef) {
- if (el.templateIsDecorated_)
- return false;
-
- var templateElement = el;
- templateElement.templateIsDecorated_ = true;
-
- var isNativeHTMLTemplate = isHTMLTemplate(templateElement) &&
- hasTemplateElement;
- var bootstrapContents = isNativeHTMLTemplate;
- var liftContents = !isNativeHTMLTemplate;
- var liftRoot = false;
-
- if (!isNativeHTMLTemplate) {
- if (isAttributeTemplate(templateElement)) {
- assert(!opt_instanceRef);
- templateElement = extractTemplateFromAttributeTemplate(el);
- templateElement.templateIsDecorated_ = true;
- isNativeHTMLTemplate = hasTemplateElement;
- liftRoot = true;
- } else if (isSVGTemplate(templateElement)) {
- templateElement = extractTemplateFromSVGTemplate(el);
- templateElement.templateIsDecorated_ = true;
- isNativeHTMLTemplate = hasTemplateElement;
- }
- }
-
- if (!isNativeHTMLTemplate) {
- fixTemplateElementPrototype(templateElement);
- var doc = getOrCreateTemplateContentsOwner(templateElement);
- templateElement.content_ = doc.createDocumentFragment();
- }
-
- if (opt_instanceRef) {
- // template is contained within an instance, its direct content must be
- // empty
- templateElement.instanceRef_ = opt_instanceRef;
- } else if (liftContents) {
- liftNonNativeTemplateChildrenIntoContent(templateElement,
- el,
- liftRoot);
- } else if (bootstrapContents) {
- bootstrapTemplatesRecursivelyFrom(templateElement.content);
- }
-
- return true;
- };
-
- // TODO(rafaelw): This used to decorate recursively all templates from a given
- // node. This happens by default on 'DOMContentLoaded', but may be needed
- // in subtrees not descendent from document (e.g. ShadowRoot).
- // Review whether this is the right public API.
- HTMLTemplateElement.bootstrap = bootstrapTemplatesRecursivelyFrom;
-
- var htmlElement = global.HTMLUnknownElement || HTMLElement;
-
- var contentDescriptor = {
- get: function() {
- return this.content_;
- },
- enumerable: true,
- configurable: true
- };
-
- if (!hasTemplateElement) {
- // Gecko is more picky with the prototype than WebKit. Make sure to use the
- // same prototype as created in the constructor.
- HTMLTemplateElement.prototype = Object.create(htmlElement.prototype);
-
- Object.defineProperty(HTMLTemplateElement.prototype, 'content',
- contentDescriptor);
- }
-
- function fixTemplateElementPrototype(el) {
- if (hasProto)
- el.__proto__ = HTMLTemplateElement.prototype;
- else
- mixin(el, HTMLTemplateElement.prototype);
- }
-
- function ensureSetModelScheduled(template) {
- if (!template.setModelFn_) {
- template.setModelFn_ = function() {
- template.setModelFnScheduled_ = false;
- var map = getBindings(template,
- template.delegate_ && template.delegate_.prepareBinding);
- processBindings(template, map, template.model_);
- };
- }
-
- if (!template.setModelFnScheduled_) {
- template.setModelFnScheduled_ = true;
- Observer.runEOM_(template.setModelFn_);
- }
- }
-
- mixin(HTMLTemplateElement.prototype, {
- bind: function(name, value, oneTime) {
- if (name != 'ref')
- return Element.prototype.bind.call(this, name, value, oneTime);
-
- var self = this;
- var ref = oneTime ? value : value.open(function(ref) {
- self.setAttribute('ref', ref);
- self.refChanged_();
- });
-
- this.setAttribute('ref', ref);
- this.refChanged_();
- if (oneTime)
- return;
-
- if (!this.bindings_) {
- this.bindings_ = { ref: value };
- } else {
- this.bindings_.ref = value;
- }
-
- return value;
- },
-
- processBindingDirectives_: function(directives) {
- if (this.iterator_)
- this.iterator_.closeDeps();
-
- if (!directives.if && !directives.bind && !directives.repeat) {
- if (this.iterator_) {
- this.iterator_.close();
- this.iterator_ = undefined;
- }
-
- return;
- }
-
- if (!this.iterator_) {
- this.iterator_ = new TemplateIterator(this);
- }
-
- this.iterator_.updateDependencies(directives, this.model_);
-
- if (templateObserver) {
- templateObserver.observe(this, { attributes: true,
- attributeFilter: ['ref'] });
- }
-
- return this.iterator_;
- },
-
- createInstance: function(model, bindingDelegate, delegate_) {
- if (bindingDelegate)
- delegate_ = this.newDelegate_(bindingDelegate);
-
- if (!this.refContent_)
- this.refContent_ = this.ref_.content;
- var content = this.refContent_;
- if (content.firstChild === null)
- return emptyInstance;
-
- var map = this.bindingMap_;
- if (!map || map.content !== content) {
- // TODO(rafaelw): Setup a MutationObserver on content to detect
- // when the instanceMap is invalid.
- map = createInstanceBindingMap(content,
- delegate_ && delegate_.prepareBinding) || [];
- map.content = content;
- this.bindingMap_ = map;
- }
-
- var stagingDocument = getTemplateStagingDocument(this);
- var instance = stagingDocument.createDocumentFragment();
- instance.templateCreator_ = this;
- instance.protoContent_ = content;
- instance.bindings_ = [];
- instance.terminator_ = null;
- var instanceRecord = instance.templateInstance_ = {
- firstNode: null,
- lastNode: null,
- model: model
- };
-
- var i = 0;
- var collectTerminator = false;
- for (var child = content.firstChild; child; child = child.nextSibling) {
- // The terminator of the instance is the clone of the last child of the
- // content. If the last child is an active template, it may produce
- // instances as a result of production, so simply collecting the last
- // child of the instance after it has finished producing may be wrong.
- if (child.nextSibling === null)
- collectTerminator = true;
-
- var clone = cloneAndBindInstance(child, instance, stagingDocument,
- map.children[i++],
- model,
- delegate_,
- instance.bindings_);
- clone.templateInstance_ = instanceRecord;
- if (collectTerminator)
- instance.terminator_ = clone;
- }
-
- instanceRecord.firstNode = instance.firstChild;
- instanceRecord.lastNode = instance.lastChild;
- instance.templateCreator_ = undefined;
- instance.protoContent_ = undefined;
- return instance;
- },
-
- get model() {
- return this.model_;
- },
-
- set model(model) {
- this.model_ = model;
- ensureSetModelScheduled(this);
- },
-
- get bindingDelegate() {
- return this.delegate_ && this.delegate_.raw;
- },
-
- refChanged_: function() {
- if (!this.iterator_ || this.refContent_ === this.ref_.content)
- return;
-
- this.refContent_ = undefined;
- this.iterator_.valueChanged();
- this.iterator_.updateIteratedValue();
- },
-
- clear: function() {
- this.model_ = undefined;
- this.delegate_ = undefined;
- if (this.bindings_ && this.bindings_.ref)
- this.bindings_.ref.close()
- this.refContent_ = undefined;
- if (!this.iterator_)
- return;
- this.iterator_.valueChanged();
- this.iterator_.close()
- this.iterator_ = undefined;
- },
-
- setDelegate_: function(delegate) {
- this.delegate_ = delegate;
- this.bindingMap_ = undefined;
- if (this.iterator_) {
- this.iterator_.instancePositionChangedFn_ = undefined;
- this.iterator_.instanceModelFn_ = undefined;
- }
- },
-
- newDelegate_: function(bindingDelegate) {
- if (!bindingDelegate)
- return {};
-
- function delegateFn(name) {
- var fn = bindingDelegate && bindingDelegate[name];
- if (typeof fn != 'function')
- return;
-
- return function() {
- return fn.apply(bindingDelegate, arguments);
- };
- }
-
- return {
- raw: bindingDelegate,
- prepareBinding: delegateFn('prepareBinding'),
- prepareInstanceModel: delegateFn('prepareInstanceModel'),
- prepareInstancePositionChanged:
- delegateFn('prepareInstancePositionChanged')
- };
- },
-
- // TODO(rafaelw): Assigning .bindingDelegate always succeeds. It may
- // make sense to issue a warning or even throw if the template is already
- // "activated", since this would be a strange thing to do.
- set bindingDelegate(bindingDelegate) {
- if (this.delegate_) {
- throw Error('Template must be cleared before a new bindingDelegate ' +
- 'can be assigned');
- }
-
- this.setDelegate_(this.newDelegate_(bindingDelegate));
- },
-
- get ref_() {
- var ref = searchRefId(this, this.getAttribute('ref'));
- if (!ref)
- ref = this.instanceRef_;
-
- if (!ref)
- return this;
-
- var nextRef = ref.ref_;
- return nextRef ? nextRef : ref;
- }
- });
-
- // Returns
- // a) undefined if there are no mustaches.
- // b) [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one mustache.
- function parseMustaches(s, name, node, prepareBindingFn) {
- if (!s || !s.length)
- return;
-
- var tokens;
- var length = s.length;
- var startIndex = 0, lastIndex = 0, endIndex = 0;
- var onlyOneTime = true;
- while (lastIndex < length) {
- var startIndex = s.indexOf('{{', lastIndex);
- var oneTimeStart = s.indexOf('[[', lastIndex);
- var oneTime = false;
- var terminator = '}}';
-
- if (oneTimeStart >= 0 &&
- (startIndex < 0 || oneTimeStart < startIndex)) {
- startIndex = oneTimeStart;
- oneTime = true;
- terminator = ']]';
- }
-
- endIndex = startIndex < 0 ? -1 : s.indexOf(terminator, startIndex + 2);
-
- if (endIndex < 0) {
- if (!tokens)
- return;
-
- tokens.push(s.slice(lastIndex)); // TEXT
- break;
- }
-
- tokens = tokens || [];
- tokens.push(s.slice(lastIndex, startIndex)); // TEXT
- var pathString = s.slice(startIndex + 2, endIndex).trim();
- tokens.push(oneTime); // ONE_TIME?
- onlyOneTime = onlyOneTime && oneTime;
- var delegateFn = prepareBindingFn &&
- prepareBindingFn(pathString, name, node);
- // Don't try to parse the expression if there's a prepareBinding function
- if (delegateFn == null) {
- tokens.push(Path.get(pathString)); // PATH
- } else {
- tokens.push(null);
- }
- tokens.push(delegateFn); // DELEGATE_FN
- lastIndex = endIndex + 2;
- }
-
- if (lastIndex === length)
- tokens.push(''); // TEXT
-
- tokens.hasOnePath = tokens.length === 5;
- tokens.isSimplePath = tokens.hasOnePath &&
- tokens[0] == '' &&
- tokens[4] == '';
- tokens.onlyOneTime = onlyOneTime;
-
- tokens.combinator = function(values) {
- var newValue = tokens[0];
-
- for (var i = 1; i < tokens.length; i += 4) {
- var value = tokens.hasOnePath ? values : values[(i - 1) / 4];
- if (value !== undefined)
- newValue += value;
- newValue += tokens[i + 3];
- }
-
- return newValue;
- }
-
- return tokens;
- };
-
- function processOneTimeBinding(name, tokens, node, model) {
- if (tokens.hasOnePath) {
- var delegateFn = tokens[3];
- var value = delegateFn ? delegateFn(model, node, true) :
- tokens[2].getValueFrom(model);
- return tokens.isSimplePath ? value : tokens.combinator(value);
- }
-
- var values = [];
- for (var i = 1; i < tokens.length; i += 4) {
- var delegateFn = tokens[i + 2];
- values[(i - 1) / 4] = delegateFn ? delegateFn(model, node) :
- tokens[i + 1].getValueFrom(model);
- }
-
- return tokens.combinator(values);
- }
-
- function processSinglePathBinding(name, tokens, node, model) {
- var delegateFn = tokens[3];
- var observer = delegateFn ? delegateFn(model, node, false) :
- new PathObserver(model, tokens[2]);
-
- return tokens.isSimplePath ? observer :
- new ObserverTransform(observer, tokens.combinator);
- }
-
- function processBinding(name, tokens, node, model) {
- if (tokens.onlyOneTime)
- return processOneTimeBinding(name, tokens, node, model);
-
- if (tokens.hasOnePath)
- return processSinglePathBinding(name, tokens, node, model);
-
- var observer = new CompoundObserver();
-
- for (var i = 1; i < tokens.length; i += 4) {
- var oneTime = tokens[i];
- var delegateFn = tokens[i + 2];
-
- if (delegateFn) {
- var value = delegateFn(model, node, oneTime);
- if (oneTime)
- observer.addPath(value)
- else
- observer.addObserver(value);
- continue;
- }
-
- var path = tokens[i + 1];
- if (oneTime)
- observer.addPath(path.getValueFrom(model))
- else
- observer.addPath(model, path);
- }
-
- return new ObserverTransform(observer, tokens.combinator);
- }
-
- function processBindings(node, bindings, model, instanceBindings) {
- for (var i = 0; i < bindings.length; i += 2) {
- var name = bindings[i]
- var tokens = bindings[i + 1];
- var value = processBinding(name, tokens, node, model);
- var binding = node.bind(name, value, tokens.onlyOneTime);
- if (binding && instanceBindings)
- instanceBindings.push(binding);
- }
-
- if (!bindings.isTemplate)
- return;
-
- node.model_ = model;
- var iter = node.processBindingDirectives_(bindings);
- if (instanceBindings && iter)
- instanceBindings.push(iter);
- }
-
- function parseWithDefault(el, name, prepareBindingFn) {
- var v = el.getAttribute(name);
- return parseMustaches(v == '' ? '{{}}' : v, name, el, prepareBindingFn);
- }
-
- function parseAttributeBindings(element, prepareBindingFn) {
- assert(element);
-
- var bindings = [];
- var ifFound = false;
- var bindFound = false;
-
- for (var i = 0; i < element.attributes.length; i++) {
- var attr = element.attributes[i];
- var name = attr.name;
- var value = attr.value;
-
- // Allow bindings expressed in attributes to be prefixed with underbars.
- // We do this to allow correct semantics for browsers that don't implement
- // <template> where certain attributes might trigger side-effects -- and
- // for IE which sanitizes certain attributes, disallowing mustache
- // replacements in their text.
- while (name[0] === '_') {
- name = name.substring(1);
- }
-
- if (isTemplate(element) &&
- (name === IF || name === BIND || name === REPEAT)) {
- continue;
- }
-
- var tokens = parseMustaches(value, name, element,
- prepareBindingFn);
- if (!tokens)
- continue;
-
- bindings.push(name, tokens);
- }
-
- if (isTemplate(element)) {
- bindings.isTemplate = true;
- bindings.if = parseWithDefault(element, IF, prepareBindingFn);
- bindings.bind = parseWithDefault(element, BIND, prepareBindingFn);
- bindings.repeat = parseWithDefault(element, REPEAT, prepareBindingFn);
-
- if (bindings.if && !bindings.bind && !bindings.repeat)
- bindings.bind = parseMustaches('{{}}', BIND, element, prepareBindingFn);
- }
-
- return bindings;
- }
-
- function getBindings(node, prepareBindingFn) {
- if (node.nodeType === Node.ELEMENT_NODE)
- return parseAttributeBindings(node, prepareBindingFn);
-
- if (node.nodeType === Node.TEXT_NODE) {
- var tokens = parseMustaches(node.data, 'textContent', node,
- prepareBindingFn);
- if (tokens)
- return ['textContent', tokens];
- }
-
- return [];
- }
-
- function cloneAndBindInstance(node, parent, stagingDocument, bindings, model,
- delegate,
- instanceBindings,
- instanceRecord) {
- var clone = parent.appendChild(stagingDocument.importNode(node, false));
-
- var i = 0;
- for (var child = node.firstChild; child; child = child.nextSibling) {
- cloneAndBindInstance(child, clone, stagingDocument,
- bindings.children[i++],
- model,
- delegate,
- instanceBindings);
- }
-
- if (bindings.isTemplate) {
- HTMLTemplateElement.decorate(clone, node);
- if (delegate)
- clone.setDelegate_(delegate);
- }
-
- processBindings(clone, bindings, model, instanceBindings);
- return clone;
- }
-
- function createInstanceBindingMap(node, prepareBindingFn) {
- var map = getBindings(node, prepareBindingFn);
- map.children = {};
- var index = 0;
- for (var child = node.firstChild; child; child = child.nextSibling) {
- map.children[index++] = createInstanceBindingMap(child, prepareBindingFn);
- }
-
- return map;
- }
-
- Object.defineProperty(Node.prototype, 'templateInstance', {
- get: function() {
- var instance = this.templateInstance_;
- return instance ? instance :
- (this.parentNode ? this.parentNode.templateInstance : undefined);
- }
- });
-
- var emptyInstance = document.createDocumentFragment();
- emptyInstance.bindings_ = [];
- emptyInstance.terminator_ = null;
-
- function TemplateIterator(templateElement) {
- this.closed = false;
- this.templateElement_ = templateElement;
- this.instances = [];
- this.deps = undefined;
- this.iteratedValue = [];
- this.presentValue = undefined;
- this.arrayObserver = undefined;
- }
-
- TemplateIterator.prototype = {
- closeDeps: function() {
- var deps = this.deps;
- if (deps) {
- if (deps.ifOneTime === false)
- deps.ifValue.close();
- if (deps.oneTime === false)
- deps.value.close();
- }
- },
-
- updateDependencies: function(directives, model) {
- this.closeDeps();
-
- var deps = this.deps = {};
- var template = this.templateElement_;
-
- if (directives.if) {
- deps.hasIf = true;
- deps.ifOneTime = directives.if.onlyOneTime;
- deps.ifValue = processBinding(IF, directives.if, template, model);
-
- // oneTime if & predicate is false. nothing else to do.
- if (deps.ifOneTime && !deps.ifValue) {
- this.updateIteratedValue();
- return;
- }
-
- if (!deps.ifOneTime)
- deps.ifValue.open(this.updateIteratedValue, this);
- }
-
- if (directives.repeat) {
- deps.repeat = true;
- deps.oneTime = directives.repeat.onlyOneTime;
- deps.value = processBinding(REPEAT, directives.repeat, template, model);
- } else {
- deps.repeat = false;
- deps.oneTime = directives.bind.onlyOneTime;
- deps.value = processBinding(BIND, directives.bind, template, model);
- }
-
- if (!deps.oneTime)
- deps.value.open(this.updateIteratedValue, this);
-
- this.updateIteratedValue();
- },
-
- updateIteratedValue: function() {
- if (this.deps.hasIf) {
- var ifValue = this.deps.ifValue;
- if (!this.deps.ifOneTime)
- ifValue = ifValue.discardChanges();
- if (!ifValue) {
- this.valueChanged();
- return;
- }
- }
-
- var value = this.deps.value;
- if (!this.deps.oneTime)
- value = value.discardChanges();
- if (!this.deps.repeat)
- value = [value];
- var observe = this.deps.repeat &&
- !this.deps.oneTime &&
- Array.isArray(value);
- this.valueChanged(value, observe);
- },
-
- valueChanged: function(value, observeValue) {
- if (!Array.isArray(value))
- value = [];
-
- if (value === this.iteratedValue)
- return;
-
- this.unobserve();
- this.presentValue = value;
- if (observeValue) {
- this.arrayObserver = new ArrayObserver(this.presentValue);
- this.arrayObserver.open(this.handleSplices, this);
- }
-
- this.handleSplices(ArrayObserver.calculateSplices(this.presentValue,
- this.iteratedValue));
- },
-
- getLastInstanceNode: function(index) {
- if (index == -1)
- return this.templateElement_;
- var instance = this.instances[index];
- var terminator = instance.terminator_;
- if (!terminator)
- return this.getLastInstanceNode(index - 1);
-
- if (terminator.nodeType !== Node.ELEMENT_NODE ||
- this.templateElement_ === terminator) {
- return terminator;
- }
-
- var subtemplateIterator = terminator.iterator_;
- if (!subtemplateIterator)
- return terminator;
-
- return subtemplateIterator.getLastTemplateNode();
- },
-
- getLastTemplateNode: function() {
- return this.getLastInstanceNode(this.instances.length - 1);
- },
-
- insertInstanceAt: function(index, fragment) {
- var previousInstanceLast = this.getLastInstanceNode(index - 1);
- var parent = this.templateElement_.parentNode;
- this.instances.splice(index, 0, fragment);
-
- parent.insertBefore(fragment, previousInstanceLast.nextSibling);
- },
-
- extractInstanceAt: function(index) {
- var previousInstanceLast = this.getLastInstanceNode(index - 1);
- var lastNode = this.getLastInstanceNode(index);
- var parent = this.templateElement_.parentNode;
- var instance = this.instances.splice(index, 1)[0];
-
- while (lastNode !== previousInstanceLast) {
- var node = previousInstanceLast.nextSibling;
- if (node == lastNode)
- lastNode = previousInstanceLast;
-
- instance.appendChild(parent.removeChild(node));
- }
-
- return instance;
- },
-
- getDelegateFn: function(fn) {
- fn = fn && fn(this.templateElement_);
- return typeof fn === 'function' ? fn : null;
- },
-
- handleSplices: function(splices) {
- if (this.closed || !splices.length)
- return;
-
- var template = this.templateElement_;
-
- if (!template.parentNode) {
- this.close();
- return;
- }
-
- ArrayObserver.applySplices(this.iteratedValue, this.presentValue,
- splices);
-
- var delegate = template.delegate_;
- if (this.instanceModelFn_ === undefined) {
- this.instanceModelFn_ =
- this.getDelegateFn(delegate && delegate.prepareInstanceModel);
- }
-
- if (this.instancePositionChangedFn_ === undefined) {
- this.instancePositionChangedFn_ =
- this.getDelegateFn(delegate &&
- delegate.prepareInstancePositionChanged);
- }
-
- // Instance Removals
- var instanceCache = new Map;
- var removeDelta = 0;
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- var removed = splice.removed;
- for (var j = 0; j < removed.length; j++) {
- var model = removed[j];
- var instance = this.extractInstanceAt(splice.index + removeDelta);
- if (instance !== emptyInstance) {
- instanceCache.set(model, instance);
- }
- }
-
- removeDelta -= splice.addedCount;
- }
-
- // Instance Insertions
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- var addIndex = splice.index;
- for (; addIndex < splice.index + splice.addedCount; addIndex++) {
- var model = this.iteratedValue[addIndex];
- var instance = instanceCache.get(model);
- if (instance) {
- instanceCache.delete(model);
- } else {
- if (this.instanceModelFn_) {
- model = this.instanceModelFn_(model);
- }
-
- if (model === undefined) {
- instance = emptyInstance;
- } else {
- instance = template.createInstance(model, undefined, delegate);
- }
- }
-
- this.insertInstanceAt(addIndex, instance);
- }
- }
-
- instanceCache.forEach(function(instance) {
- this.closeInstanceBindings(instance);
- }, this);
-
- if (this.instancePositionChangedFn_)
- this.reportInstancesMoved(splices);
- },
-
- reportInstanceMoved: function(index) {
- var instance = this.instances[index];
- if (instance === emptyInstance)
- return;
-
- this.instancePositionChangedFn_(instance.templateInstance_, index);
- },
-
- reportInstancesMoved: function(splices) {
- var index = 0;
- var offset = 0;
- for (var i = 0; i < splices.length; i++) {
- var splice = splices[i];
- if (offset != 0) {
- while (index < splice.index) {
- this.reportInstanceMoved(index);
- index++;
- }
- } else {
- index = splice.index;
- }
-
- while (index < splice.index + splice.addedCount) {
- this.reportInstanceMoved(index);
- index++;
- }
-
- offset += splice.addedCount - splice.removed.length;
- }
-
- if (offset == 0)
- return;
-
- var length = this.instances.length;
- while (index < length) {
- this.reportInstanceMoved(index);
- index++;
- }
- },
-
- closeInstanceBindings: function(instance) {
- var bindings = instance.bindings_;
- for (var i = 0; i < bindings.length; i++) {
- bindings[i].close();
- }
- },
-
- unobserve: function() {
- if (!this.arrayObserver)
- return;
-
- this.arrayObserver.close();
- this.arrayObserver = undefined;
- },
-
- close: function() {
- if (this.closed)
- return;
- this.unobserve();
- for (var i = 0; i < this.instances.length; i++) {
- this.closeInstanceBindings(this.instances[i]);
- }
-
- this.instances.length = 0;
- this.closeDeps();
- this.templateElement_.iterator_ = undefined;
- this.closed = true;
- }
- };
-
- // Polyfill-specific API.
- HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom;
-})(this);
-
-/*
- Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
- Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
- Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
- Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
- Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
- Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
- Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
- Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
- Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-(function (global) {
- 'use strict';
-
- var Token,
- TokenName,
- Syntax,
- Messages,
- source,
- index,
- length,
- delegate,
- lookahead,
- state;
-
- Token = {
- BooleanLiteral: 1,
- EOF: 2,
- Identifier: 3,
- Keyword: 4,
- NullLiteral: 5,
- NumericLiteral: 6,
- Punctuator: 7,
- StringLiteral: 8
- };
-
- TokenName = {};
- TokenName[Token.BooleanLiteral] = 'Boolean';
- TokenName[Token.EOF] = '<end>';
- TokenName[Token.Identifier] = 'Identifier';
- TokenName[Token.Keyword] = 'Keyword';
- TokenName[Token.NullLiteral] = 'Null';
- TokenName[Token.NumericLiteral] = 'Numeric';
- TokenName[Token.Punctuator] = 'Punctuator';
- TokenName[Token.StringLiteral] = 'String';
-
- Syntax = {
- ArrayExpression: 'ArrayExpression',
- BinaryExpression: 'BinaryExpression',
- CallExpression: 'CallExpression',
- ConditionalExpression: 'ConditionalExpression',
- EmptyStatement: 'EmptyStatement',
- ExpressionStatement: 'ExpressionStatement',
- Identifier: 'Identifier',
- Literal: 'Literal',
- LabeledStatement: 'LabeledStatement',
- LogicalExpression: 'LogicalExpression',
- MemberExpression: 'MemberExpression',
- ObjectExpression: 'ObjectExpression',
- Program: 'Program',
- Property: 'Property',
- ThisExpression: 'ThisExpression',
- UnaryExpression: 'UnaryExpression'
- };
-
- // Error messages should be identical to V8.
- Messages = {
- UnexpectedToken: 'Unexpected token %0',
- UnknownLabel: 'Undefined label \'%0\'',
- Redeclaration: '%0 \'%1\' has already been declared'
- };
-
- // Ensure the condition is true, otherwise throw an error.
- // This is only to have a better contract semantic, i.e. another safety net
- // to catch a logic error. The condition shall be fulfilled in normal case.
- // Do NOT use this to enforce a certain condition on any user input.
-
- function assert(condition, message) {
- if (!condition) {
- throw new Error('ASSERT: ' + message);
- }
- }
-
- function isDecimalDigit(ch) {
- return (ch >= 48 && ch <= 57); // 0..9
- }
-
-
- // 7.2 White Space
-
- function isWhiteSpace(ch) {
- return (ch === 32) || // space
- (ch === 9) || // tab
- (ch === 0xB) ||
- (ch === 0xC) ||
- (ch === 0xA0) ||
- (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0);
- }
-
- // 7.3 Line Terminators
-
- function isLineTerminator(ch) {
- return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
- }
-
- // 7.6 Identifier Names and Identifiers
-
- function isIdentifierStart(ch) {
- return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
- (ch >= 65 && ch <= 90) || // A..Z
- (ch >= 97 && ch <= 122); // a..z
- }
-
- function isIdentifierPart(ch) {
- return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
- (ch >= 65 && ch <= 90) || // A..Z
- (ch >= 97 && ch <= 122) || // a..z
- (ch >= 48 && ch <= 57); // 0..9
- }
-
- // 7.6.1.1 Keywords
-
- function isKeyword(id) {
- return (id === 'this')
- }
-
- // 7.4 Comments
-
- function skipWhitespace() {
- while (index < length && isWhiteSpace(source.charCodeAt(index))) {
- ++index;
- }
- }
-
- function getIdentifier() {
- var start, ch;
-
- start = index++;
- while (index < length) {
- ch = source.charCodeAt(index);
- if (isIdentifierPart(ch)) {
- ++index;
- } else {
- break;
- }
- }
-
- return source.slice(start, index);
- }
-
- function scanIdentifier() {
- var start, id, type;
-
- start = index;
-
- id = getIdentifier();
-
- // There is no keyword or literal with only one character.
- // Thus, it must be an identifier.
- if (id.length === 1) {
- type = Token.Identifier;
- } else if (isKeyword(id)) {
- type = Token.Keyword;
- } else if (id === 'null') {
- type = Token.NullLiteral;
- } else if (id === 'true' || id === 'false') {
- type = Token.BooleanLiteral;
- } else {
- type = Token.Identifier;
- }
-
- return {
- type: type,
- value: id,
- range: [start, index]
- };
- }
-
-
- // 7.7 Punctuators
-
- function scanPunctuator() {
- var start = index,
- code = source.charCodeAt(index),
- code2,
- ch1 = source[index],
- ch2;
-
- switch (code) {
-
- // Check for most common single-character punctuators.
- case 46: // . dot
- case 40: // ( open bracket
- case 41: // ) close bracket
- case 59: // ; semicolon
- case 44: // , comma
- case 123: // { open curly brace
- case 125: // } close curly brace
- case 91: // [
- case 93: // ]
- case 58: // :
- case 63: // ?
- ++index;
- return {
- type: Token.Punctuator,
- value: String.fromCharCode(code),
- range: [start, index]
- };
-
- default:
- code2 = source.charCodeAt(index + 1);
-
- // '=' (char #61) marks an assignment or comparison operator.
- if (code2 === 61) {
- switch (code) {
- case 37: // %
- case 38: // &
- case 42: // *:
- case 43: // +
- case 45: // -
- case 47: // /
- case 60: // <
- case 62: // >
- case 124: // |
- index += 2;
- return {
- type: Token.Punctuator,
- value: String.fromCharCode(code) + String.fromCharCode(code2),
- range: [start, index]
- };
-
- case 33: // !
- case 61: // =
- index += 2;
-
- // !== and ===
- if (source.charCodeAt(index) === 61) {
- ++index;
- }
- return {
- type: Token.Punctuator,
- value: source.slice(start, index),
- range: [start, index]
- };
- default:
- break;
- }
- }
- break;
- }
-
- // Peek more characters.
-
- ch2 = source[index + 1];
-
- // Other 2-character punctuators: && ||
-
- if (ch1 === ch2 && ('&|'.indexOf(ch1) >= 0)) {
- index += 2;
- return {
- type: Token.Punctuator,
- value: ch1 + ch2,
- range: [start, index]
- };
- }
-
- if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
- ++index;
- return {
- type: Token.Punctuator,
- value: ch1,
- range: [start, index]
- };
- }
-
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
-
- // 7.8.3 Numeric Literals
- function scanNumericLiteral() {
- var number, start, ch;
-
- ch = source[index];
- assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
- 'Numeric literal must start with a decimal digit or a decimal point');
-
- start = index;
- number = '';
- if (ch !== '.') {
- number = source[index++];
- ch = source[index];
-
- // Hex number starts with '0x'.
- // Octal number starts with '0'.
- if (number === '0') {
- // decimal number starts with '0' such as '09' is illegal.
- if (ch && isDecimalDigit(ch.charCodeAt(0))) {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
- }
-
- while (isDecimalDigit(source.charCodeAt(index))) {
- number += source[index++];
- }
- ch = source[index];
- }
-
- if (ch === '.') {
- number += source[index++];
- while (isDecimalDigit(source.charCodeAt(index))) {
- number += source[index++];
- }
- ch = source[index];
- }
-
- if (ch === 'e' || ch === 'E') {
- number += source[index++];
-
- ch = source[index];
- if (ch === '+' || ch === '-') {
- number += source[index++];
- }
- if (isDecimalDigit(source.charCodeAt(index))) {
- while (isDecimalDigit(source.charCodeAt(index))) {
- number += source[index++];
- }
- } else {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
- }
-
- if (isIdentifierStart(source.charCodeAt(index))) {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
-
- return {
- type: Token.NumericLiteral,
- value: parseFloat(number),
- range: [start, index]
- };
- }
-
- // 7.8.4 String Literals
-
- function scanStringLiteral() {
- var str = '', quote, start, ch, octal = false;
-
- quote = source[index];
- assert((quote === '\'' || quote === '"'),
- 'String literal must starts with a quote');
-
- start = index;
- ++index;
-
- while (index < length) {
- ch = source[index++];
-
- if (ch === quote) {
- quote = '';
- break;
- } else if (ch === '\\') {
- ch = source[index++];
- if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
- switch (ch) {
- case 'n':
- str += '\n';
- break;
- case 'r':
- str += '\r';
- break;
- case 't':
- str += '\t';
- break;
- case 'b':
- str += '\b';
- break;
- case 'f':
- str += '\f';
- break;
- case 'v':
- str += '\x0B';
- break;
-
- default:
- str += ch;
- break;
- }
- } else {
- if (ch === '\r' && source[index] === '\n') {
- ++index;
- }
- }
- } else if (isLineTerminator(ch.charCodeAt(0))) {
- break;
- } else {
- str += ch;
- }
- }
-
- if (quote !== '') {
- throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
- }
-
- return {
- type: Token.StringLiteral,
- value: str,
- octal: octal,
- range: [start, index]
- };
- }
-
- function isIdentifierName(token) {
- return token.type === Token.Identifier ||
- token.type === Token.Keyword ||
- token.type === Token.BooleanLiteral ||
- token.type === Token.NullLiteral;
- }
-
- function advance() {
- var ch;
-
- skipWhitespace();
-
- if (index >= length) {
- return {
- type: Token.EOF,
- range: [index, index]
- };
- }
-
- ch = source.charCodeAt(index);
-
- // Very common: ( and ) and ;
- if (ch === 40 || ch === 41 || ch === 58) {
- return scanPunctuator();
- }
-
- // String literal starts with single quote (#39) or double quote (#34).
- if (ch === 39 || ch === 34) {
- return scanStringLiteral();
- }
-
- if (isIdentifierStart(ch)) {
- return scanIdentifier();
- }
-
- // Dot (.) char #46 can also start a floating-point number, hence the need
- // to check the next character.
- if (ch === 46) {
- if (isDecimalDigit(source.charCodeAt(index + 1))) {
- return scanNumericLiteral();
- }
- return scanPunctuator();
- }
-
- if (isDecimalDigit(ch)) {
- return scanNumericLiteral();
- }
-
- return scanPunctuator();
- }
-
- function lex() {
- var token;
-
- token = lookahead;
- index = token.range[1];
-
- lookahead = advance();
-
- index = token.range[1];
-
- return token;
- }
-
- function peek() {
- var pos;
-
- pos = index;
- lookahead = advance();
- index = pos;
- }
-
- // Throw an exception
-
- function throwError(token, messageFormat) {
- var error,
- args = Array.prototype.slice.call(arguments, 2),
- msg = messageFormat.replace(
- /%(\d)/g,
- function (whole, index) {
- assert(index < args.length, 'Message reference must be in range');
- return args[index];
- }
- );
-
- error = new Error(msg);
- error.index = index;
- error.description = msg;
- throw error;
- }
-
- // Throw an exception because of the token.
-
- function throwUnexpected(token) {
- throwError(token, Messages.UnexpectedToken, token.value);
- }
-
- // Expect the next token to match the specified punctuator.
- // If not, an exception will be thrown.
-
- function expect(value) {
- var token = lex();
- if (token.type !== Token.Punctuator || token.value !== value) {
- throwUnexpected(token);
- }
- }
-
- // Return true if the next token matches the specified punctuator.
-
- function match(value) {
- return lookahead.type === Token.Punctuator && lookahead.value === value;
- }
-
- // Return true if the next token matches the specified keyword
-
- function matchKeyword(keyword) {
- return lookahead.type === Token.Keyword && lookahead.value === keyword;
- }
-
- function consumeSemicolon() {
- // Catch the very common case first: immediately a semicolon (char #59).
- if (source.charCodeAt(index) === 59) {
- lex();
- return;
- }
-
- skipWhitespace();
-
- if (match(';')) {
- lex();
- return;
- }
-
- if (lookahead.type !== Token.EOF && !match('}')) {
- throwUnexpected(lookahead);
- }
- }
-
- // 11.1.4 Array Initialiser
-
- function parseArrayInitialiser() {
- var elements = [];
-
- expect('[');
-
- while (!match(']')) {
- if (match(',')) {
- lex();
- elements.push(null);
- } else {
- elements.push(parseExpression());
-
- if (!match(']')) {
- expect(',');
- }
- }
- }
-
- expect(']');
-
- return delegate.createArrayExpression(elements);
- }
-
- // 11.1.5 Object Initialiser
-
- function parseObjectPropertyKey() {
- var token;
-
- skipWhitespace();
- token = lex();
-
- // Note: This function is called only from parseObjectProperty(), where
- // EOF and Punctuator tokens are already filtered out.
- if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
- return delegate.createLiteral(token);
- }
-
- return delegate.createIdentifier(token.value);
- }
-
- function parseObjectProperty() {
- var token, key;
-
- token = lookahead;
- skipWhitespace();
-
- if (token.type === Token.EOF || token.type === Token.Punctuator) {
- throwUnexpected(token);
- }
-
- key = parseObjectPropertyKey();
- expect(':');
- return delegate.createProperty('init', key, parseExpression());
- }
-
- function parseObjectInitialiser() {
- var properties = [];
-
- expect('{');
-
- while (!match('}')) {
- properties.push(parseObjectProperty());
-
- if (!match('}')) {
- expect(',');
- }
- }
-
- expect('}');
-
- return delegate.createObjectExpression(properties);
- }
-
- // 11.1.6 The Grouping Operator
-
- function parseGroupExpression() {
- var expr;
-
- expect('(');
-
- expr = parseExpression();
-
- expect(')');
-
- return expr;
- }
-
-
- // 11.1 Primary Expressions
-
- function parsePrimaryExpression() {
- var type, token, expr;
-
- if (match('(')) {
- return parseGroupExpression();
- }
-
- type = lookahead.type;
-
- if (type === Token.Identifier) {
- expr = delegate.createIdentifier(lex().value);
- } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
- expr = delegate.createLiteral(lex());
- } else if (type === Token.Keyword) {
- if (matchKeyword('this')) {
- lex();
- expr = delegate.createThisExpression();
- }
- } else if (type === Token.BooleanLiteral) {
- token = lex();
- token.value = (token.value === 'true');
- expr = delegate.createLiteral(token);
- } else if (type === Token.NullLiteral) {
- token = lex();
- token.value = null;
- expr = delegate.createLiteral(token);
- } else if (match('[')) {
- expr = parseArrayInitialiser();
- } else if (match('{')) {
- expr = parseObjectInitialiser();
- }
-
- if (expr) {
- return expr;
- }
-
- throwUnexpected(lex());
- }
-
- // 11.2 Left-Hand-Side Expressions
-
- function parseArguments() {
- var args = [];
-
- expect('(');
-
- if (!match(')')) {
- while (index < length) {
- args.push(parseExpression());
- if (match(')')) {
- break;
- }
- expect(',');
- }
- }
-
- expect(')');
-
- return args;
- }
-
- function parseNonComputedProperty() {
- var token;
-
- token = lex();
-
- if (!isIdentifierName(token)) {
- throwUnexpected(token);
- }
-
- return delegate.createIdentifier(token.value);
- }
-
- function parseNonComputedMember() {
- expect('.');
-
- return parseNonComputedProperty();
- }
-
- function parseComputedMember() {
- var expr;
-
- expect('[');
-
- expr = parseExpression();
-
- expect(']');
-
- return expr;
- }
-
- function parseLeftHandSideExpression() {
- var expr, property;
-
- expr = parsePrimaryExpression();
-
- while (match('.') || match('[')) {
- if (match('[')) {
- property = parseComputedMember();
- expr = delegate.createMemberExpression('[', expr, property);
- } else {
- property = parseNonComputedMember();
- expr = delegate.createMemberExpression('.', expr, property);
- }
- }
-
- return expr;
- }
-
- // 11.3 Postfix Expressions
-
- var parsePostfixExpression = parseLeftHandSideExpression;
-
- // 11.4 Unary Operators
-
- function parseUnaryExpression() {
- var token, expr;
-
- if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
- expr = parsePostfixExpression();
- } else if (match('+') || match('-') || match('!')) {
- token = lex();
- expr = parseUnaryExpression();
- expr = delegate.createUnaryExpression(token.value, expr);
- } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
- throwError({}, Messages.UnexpectedToken);
- } else {
- expr = parsePostfixExpression();
- }
-
- return expr;
- }
-
- function binaryPrecedence(token) {
- var prec = 0;
-
- if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
- return 0;
- }
-
- switch (token.value) {
- case '||':
- prec = 1;
- break;
-
- case '&&':
- prec = 2;
- break;
-
- case '==':
- case '!=':
- case '===':
- case '!==':
- prec = 6;
- break;
-
- case '<':
- case '>':
- case '<=':
- case '>=':
- case 'instanceof':
- prec = 7;
- break;
-
- case 'in':
- prec = 7;
- break;
-
- case '+':
- case '-':
- prec = 9;
- break;
-
- case '*':
- case '/':
- case '%':
- prec = 11;
- break;
-
- default:
- break;
- }
-
- return prec;
- }
-
- // 11.5 Multiplicative Operators
- // 11.6 Additive Operators
- // 11.7 Bitwise Shift Operators
- // 11.8 Relational Operators
- // 11.9 Equality Operators
- // 11.10 Binary Bitwise Operators
- // 11.11 Binary Logical Operators
-
- function parseBinaryExpression() {
- var expr, token, prec, stack, right, operator, left, i;
-
- left = parseUnaryExpression();
-
- token = lookahead;
- prec = binaryPrecedence(token);
- if (prec === 0) {
- return left;
- }
- token.prec = prec;
- lex();
-
- right = parseUnaryExpression();
-
- stack = [left, token, right];
-
- while ((prec = binaryPrecedence(lookahead)) > 0) {
-
- // Reduce: make a binary expression from the three topmost entries.
- while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
- right = stack.pop();
- operator = stack.pop().value;
- left = stack.pop();
- expr = delegate.createBinaryExpression(operator, left, right);
- stack.push(expr);
- }
-
- // Shift.
- token = lex();
- token.prec = prec;
- stack.push(token);
- expr = parseUnaryExpression();
- stack.push(expr);
- }
-
- // Final reduce to clean-up the stack.
- i = stack.length - 1;
- expr = stack[i];
- while (i > 1) {
- expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
- i -= 2;
- }
-
- return expr;
- }
-
-
- // 11.12 Conditional Operator
-
- function parseConditionalExpression() {
- var expr, consequent, alternate;
-
- expr = parseBinaryExpression();
-
- if (match('?')) {
- lex();
- consequent = parseConditionalExpression();
- expect(':');
- alternate = parseConditionalExpression();
-
- expr = delegate.createConditionalExpression(expr, consequent, alternate);
- }
-
- return expr;
- }
-
- // Simplification since we do not support AssignmentExpression.
- var parseExpression = parseConditionalExpression;
-
- // Polymer Syntax extensions
-
- // Filter ::
- // Identifier
- // Identifier "(" ")"
- // Identifier "(" FilterArguments ")"
-
- function parseFilter() {
- var identifier, args;
-
- identifier = lex();
-
- if (identifier.type !== Token.Identifier) {
- throwUnexpected(identifier);
- }
-
- args = match('(') ? parseArguments() : [];
-
- return delegate.createFilter(identifier.value, args);
- }
-
- // Filters ::
- // "|" Filter
- // Filters "|" Filter
-
- function parseFilters() {
- while (match('|')) {
- lex();
- parseFilter();
- }
- }
-
- // TopLevel ::
- // LabelledExpressions
- // AsExpression
- // InExpression
- // FilterExpression
-
- // AsExpression ::
- // FilterExpression as Identifier
-
- // InExpression ::
- // Identifier, Identifier in FilterExpression
- // Identifier in FilterExpression
-
- // FilterExpression ::
- // Expression
- // Expression Filters
-
- function parseTopLevel() {
- skipWhitespace();
- peek();
-
- var expr = parseExpression();
- if (expr) {
- if (lookahead.value === ',' || lookahead.value == 'in' &&
- expr.type === Syntax.Identifier) {
- parseInExpression(expr);
- } else {
- parseFilters();
- if (lookahead.value === 'as') {
- parseAsExpression(expr);
- } else {
- delegate.createTopLevel(expr);
- }
- }
- }
-
- if (lookahead.type !== Token.EOF) {
- throwUnexpected(lookahead);
- }
- }
-
- function parseAsExpression(expr) {
- lex(); // as
- var identifier = lex().value;
- delegate.createAsExpression(expr, identifier);
- }
-
- function parseInExpression(identifier) {
- var indexName;
- if (lookahead.value === ',') {
- lex();
- if (lookahead.type !== Token.Identifier)
- throwUnexpected(lookahead);
- indexName = lex().value;
- }
-
- lex(); // in
- var expr = parseExpression();
- parseFilters();
- delegate.createInExpression(identifier.name, indexName, expr);
- }
-
- function parse(code, inDelegate) {
- delegate = inDelegate;
- source = code;
- index = 0;
- length = source.length;
- lookahead = null;
- state = {
- labelSet: {}
- };
-
- return parseTopLevel();
- }
-
- global.esprima = {
- parse: parse
- };
-})(this);
-
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-// Code distributed by Google as part of the polymer project is also
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-
-(function (global) {
- 'use strict';
-
- // JScript does not have __proto__. We wrap all object literals with
- // createObject which uses Object.create, Object.defineProperty and
- // Object.getOwnPropertyDescriptor to create a new object that does the exact
- // same thing. The main downside to this solution is that we have to extract
- // all those property descriptors for IE.
- var createObject = ('__proto__' in {}) ?
- function(obj) { return obj; } :
- function(obj) {
- var proto = obj.__proto__;
- if (!proto)
- return obj;
- var newObject = Object.create(proto);
- Object.getOwnPropertyNames(obj).forEach(function(name) {
- Object.defineProperty(newObject, name,
- Object.getOwnPropertyDescriptor(obj, name));
- });
- return newObject;
- };
-
- function prepareBinding(expressionText, name, node, filterRegistry) {
- var expression;
- try {
- expression = getExpression(expressionText);
- if (expression.scopeIdent &&
- (node.nodeType !== Node.ELEMENT_NODE ||
- node.tagName !== 'TEMPLATE' ||
- (name !== 'bind' && name !== 'repeat'))) {
- throw Error('as and in can only be used within <template bind/repeat>');
- }
- } catch (ex) {
- console.error('Invalid expression syntax: ' + expressionText, ex);
- return;
- }
-
- return function(model, node, oneTime) {
- var binding = expression.getBinding(model, filterRegistry, oneTime);
- if (expression.scopeIdent && binding) {
- node.polymerExpressionScopeIdent_ = expression.scopeIdent;
- if (expression.indexIdent)
- node.polymerExpressionIndexIdent_ = expression.indexIdent;
- }
-
- return binding;
- }
- }
-
- // TODO(rafaelw): Implement simple LRU.
- var expressionParseCache = Object.create(null);
-
- function getExpression(expressionText) {
- var expression = expressionParseCache[expressionText];
- if (!expression) {
- var delegate = new ASTDelegate();
- esprima.parse(expressionText, delegate);
- expression = new Expression(delegate);
- expressionParseCache[expressionText] = expression;
- }
- return expression;
- }
-
- function Literal(value) {
- this.value = value;
- this.valueFn_ = undefined;
- }
-
- Literal.prototype = {
- valueFn: function() {
- if (!this.valueFn_) {
- var value = this.value;
- this.valueFn_ = function() {
- return value;
- }
- }
-
- return this.valueFn_;
- }
- }
-
- function IdentPath(name) {
- this.name = name;
- this.path = Path.get(name);
- }
-
- IdentPath.prototype = {
- valueFn: function() {
- if (!this.valueFn_) {
- var name = this.name;
- var path = this.path;
- this.valueFn_ = function(model, observer) {
- if (observer)
- observer.addPath(model, path);
-
- return path.getValueFrom(model);
- }
- }
-
- return this.valueFn_;
- },
-
- setValue: function(model, newValue) {
- if (this.path.length == 1);
- model = findScope(model, this.path[0]);
-
- return this.path.setValueFrom(model, newValue);
- }
- };
-
- function MemberExpression(object, property, accessor) {
- // convert literal computed property access where literal value is a value
- // path to ident dot-access.
- if (accessor == '[' &&
- property instanceof Literal &&
- Path.get(property.value).valid) {
- accessor = '.';
- property = new IdentPath(property.value);
- }
-
- this.dynamicDeps = typeof object == 'function' || object.dynamic;
-
- this.dynamic = typeof property == 'function' ||
- property.dynamic ||
- accessor == '[';
-
- this.simplePath =
- !this.dynamic &&
- !this.dynamicDeps &&
- property instanceof IdentPath &&
- (object instanceof MemberExpression || object instanceof IdentPath);
-
- this.object = this.simplePath ? object : getFn(object);
- this.property = accessor == '.' ? property : getFn(property);
- }
-
- MemberExpression.prototype = {
- get fullPath() {
- if (!this.fullPath_) {
- var last = this.object instanceof IdentPath ?
- this.object.name : this.object.fullPath;
- this.fullPath_ = Path.get(last + '.' + this.property.name);
- }
-
- return this.fullPath_;
- },
-
- valueFn: function() {
- if (!this.valueFn_) {
- var object = this.object;
-
- if (this.simplePath) {
- var path = this.fullPath;
-
- this.valueFn_ = function(model, observer) {
- if (observer)
- observer.addPath(model, path);
-
- return path.getValueFrom(model);
- };
- } else if (this.property instanceof IdentPath) {
- var path = Path.get(this.property.name);
-
- this.valueFn_ = function(model, observer) {
- var context = object(model, observer);
-
- if (observer)
- observer.addPath(context, path);
-
- return path.getValueFrom(context);
- }
- } else {
- // Computed property.
- var property = this.property;
-
- this.valueFn_ = function(model, observer) {
- var context = object(model, observer);
- var propName = property(model, observer);
- if (observer)
- observer.addPath(context, propName);
-
- return context ? context[propName] : undefined;
- };
- }
- }
- return this.valueFn_;
- },
-
- setValue: function(model, newValue) {
- if (this.simplePath) {
- this.fullPath.setValueFrom(model, newValue);
- return newValue;
- }
-
- var object = this.object(model);
- var propName = this.property instanceof IdentPath ? this.property.name :
- this.property(model);
- return object[propName] = newValue;
- }
- };
-
- function Filter(name, args) {
- this.name = name;
- this.args = [];
- for (var i = 0; i < args.length; i++) {
- this.args[i] = getFn(args[i]);
- }
- }
-
- Filter.prototype = {
- transform: function(value, toModelDirection, filterRegistry, model,
- observer) {
- var fn = filterRegistry[this.name];
- var context = model;
- if (fn) {
- context = undefined;
- } else {
- fn = context[this.name];
- if (!fn) {
- console.error('Cannot find filter: ' + this.name);
- return;
- }
- }
-
- // If toModelDirection is falsey, then the "normal" (dom-bound) direction
- // is used. Otherwise, it looks for a 'toModel' property function on the
- // object.
- if (toModelDirection) {
- fn = fn.toModel;
- } else if (typeof fn.toDOM == 'function') {
- fn = fn.toDOM;
- }
-
- if (typeof fn != 'function') {
- console.error('No ' + (toModelDirection ? 'toModel' : 'toDOM') +
- ' found on' + this.name);
- return;
- }
-
- var args = [value];
- for (var i = 0; i < this.args.length; i++) {
- args[i + 1] = getFn(this.args[i])(model, observer);
- }
-
- return fn.apply(context, args);
- }
- };
-
- function notImplemented() { throw Error('Not Implemented'); }
-
- var unaryOperators = {
- '+': function(v) { return +v; },
- '-': function(v) { return -v; },
- '!': function(v) { return !v; }
- };
-
- var binaryOperators = {
- '+': function(l, r) { return l+r; },
- '-': function(l, r) { return l-r; },
- '*': function(l, r) { return l*r; },
- '/': function(l, r) { return l/r; },
- '%': function(l, r) { return l%r; },
- '<': function(l, r) { return l<r; },
- '>': function(l, r) { return l>r; },
- '<=': function(l, r) { return l<=r; },
- '>=': function(l, r) { return l>=r; },
- '==': function(l, r) { return l==r; },
- '!=': function(l, r) { return l!=r; },
- '===': function(l, r) { return l===r; },
- '!==': function(l, r) { return l!==r; },
- '&&': function(l, r) { return l&&r; },
- '||': function(l, r) { return l||r; },
- };
-
- function getFn(arg) {
- return typeof arg == 'function' ? arg : arg.valueFn();
- }
-
- function ASTDelegate() {
- this.expression = null;
- this.filters = [];
- this.deps = {};
- this.currentPath = undefined;
- this.scopeIdent = undefined;
- this.indexIdent = undefined;
- this.dynamicDeps = false;
- }
-
- ASTDelegate.prototype = {
- createUnaryExpression: function(op, argument) {
- if (!unaryOperators[op])
- throw Error('Disallowed operator: ' + op);
-
- argument = getFn(argument);
-
- return function(model, observer) {
- return unaryOperators[op](argument(model, observer));
- };
- },
-
- createBinaryExpression: function(op, left, right) {
- if (!binaryOperators[op])
- throw Error('Disallowed operator: ' + op);
-
- left = getFn(left);
- right = getFn(right);
-
- return function(model, observer) {
- return binaryOperators[op](left(model, observer),
- right(model, observer));
- };
- },
-
- createConditionalExpression: function(test, consequent, alternate) {
- test = getFn(test);
- consequent = getFn(consequent);
- alternate = getFn(alternate);
-
- return function(model, observer) {
- return test(model, observer) ?
- consequent(model, observer) : alternate(model, observer);
- }
- },
-
- createIdentifier: function(name) {
- var ident = new IdentPath(name);
- ident.type = 'Identifier';
- return ident;
- },
-
- createMemberExpression: function(accessor, object, property) {
- var ex = new MemberExpression(object, property, accessor);
- if (ex.dynamicDeps)
- this.dynamicDeps = true;
- return ex;
- },
-
- createLiteral: function(token) {
- return new Literal(token.value);
- },
-
- createArrayExpression: function(elements) {
- for (var i = 0; i < elements.length; i++)
- elements[i] = getFn(elements[i]);
-
- return function(model, observer) {
- var arr = []
- for (var i = 0; i < elements.length; i++)
- arr.push(elements[i](model, observer));
- return arr;
- }
- },
-
- createProperty: function(kind, key, value) {
- return {
- key: key instanceof IdentPath ? key.name : key.value,
- value: value
- };
- },
-
- createObjectExpression: function(properties) {
- for (var i = 0; i < properties.length; i++)
- properties[i].value = getFn(properties[i].value);
-
- return function(model, observer) {
- var obj = {};
- for (var i = 0; i < properties.length; i++)
- obj[properties[i].key] = properties[i].value(model, observer);
- return obj;
- }
- },
-
- createFilter: function(name, args) {
- this.filters.push(new Filter(name, args));
- },
-
- createAsExpression: function(expression, scopeIdent) {
- this.expression = expression;
- this.scopeIdent = scopeIdent;
- },
-
- createInExpression: function(scopeIdent, indexIdent, expression) {
- this.expression = expression;
- this.scopeIdent = scopeIdent;
- this.indexIdent = indexIdent;
- },
-
- createTopLevel: function(expression) {
- this.expression = expression;
- },
-
- createThisExpression: notImplemented
- }
-
- function ConstantObservable(value) {
- this.value_ = value;
- }
-
- ConstantObservable.prototype = {
- open: function() { return this.value_; },
- discardChanges: function() { return this.value_; },
- deliver: function() {},
- close: function() {},
- }
-
- function Expression(delegate) {
- this.scopeIdent = delegate.scopeIdent;
- this.indexIdent = delegate.indexIdent;
-
- if (!delegate.expression)
- throw Error('No expression found.');
-
- this.expression = delegate.expression;
- getFn(this.expression); // forces enumeration of path dependencies
-
- this.filters = delegate.filters;
- this.dynamicDeps = delegate.dynamicDeps;
- }
-
- Expression.prototype = {
- getBinding: function(model, filterRegistry, oneTime) {
- if (oneTime)
- return this.getValue(model, undefined, filterRegistry);
-
- var observer = new CompoundObserver();
- // captures deps.
- var firstValue = this.getValue(model, observer, filterRegistry);
- var firstTime = true;
- var self = this;
-
- function valueFn() {
- // deps cannot have changed on first value retrieval.
- if (firstTime) {
- firstTime = false;
- return firstValue;
- }
-
- if (self.dynamicDeps)
- observer.startReset();
-
- var value = self.getValue(model,
- self.dynamicDeps ? observer : undefined,
- filterRegistry);
- if (self.dynamicDeps)
- observer.finishReset();
-
- return value;
- }
-
- function setValueFn(newValue) {
- self.setValue(model, newValue, filterRegistry);
- return newValue;
- }
-
- return new ObserverTransform(observer, valueFn, setValueFn, true);
- },
-
- getValue: function(model, observer, filterRegistry) {
- var value = getFn(this.expression)(model, observer);
- for (var i = 0; i < this.filters.length; i++) {
- value = this.filters[i].transform(value, false, filterRegistry, model,
- observer);
- }
-
- return value;
- },
-
- setValue: function(model, newValue, filterRegistry) {
- var count = this.filters ? this.filters.length : 0;
- while (count-- > 0) {
- newValue = this.filters[count].transform(newValue, true, filterRegistry,
- model);
- }
-
- if (this.expression.setValue)
- return this.expression.setValue(model, newValue);
- }
- }
-
- /**
- * Converts a style property name to a css property name. For example:
- * "WebkitUserSelect" to "-webkit-user-select"
- */
- function convertStylePropertyName(name) {
- return String(name).replace(/[A-Z]/g, function(c) {
- return '-' + c.toLowerCase();
- });
- }
-
- function isEventHandler(name) {
- return name[0] === 'o' &&
- name[1] === 'n' &&
- name[2] === '-';
- }
-
- var mixedCaseEventTypes = {};
- [
- 'webkitAnimationStart',
- 'webkitAnimationEnd',
- 'webkitTransitionEnd',
- 'DOMFocusOut',
- 'DOMFocusIn',
- 'DOMMouseScroll'
- ].forEach(function(e) {
- mixedCaseEventTypes[e.toLowerCase()] = e;
- });
-
- var parentScopeName = '@' + Math.random().toString(36).slice(2);
-
- // Single ident paths must bind directly to the appropriate scope object.
- // I.e. Pushed values in two-bindings need to be assigned to the actual model
- // object.
- function findScope(model, prop) {
- while (model[parentScopeName] &&
- !Object.prototype.hasOwnProperty.call(model, prop)) {
- model = model[parentScopeName];
- }
-
- return model;
- }
-
- function resolveEventReceiver(model, path, node) {
- if (path.length == 0)
- return undefined;
-
- if (path.length == 1)
- return findScope(model, path[0]);
-
- for (var i = 0; model != null && i < path.length - 1; i++) {
- model = model[path[i]];
- }
-
- return model;
- }
-
- function prepareEventBinding(path, name, polymerExpressions) {
- var eventType = name.substring(3);
- eventType = mixedCaseEventTypes[eventType] || eventType;
-
- return function(model, node, oneTime) {
- var fn, receiver, handler;
- if (typeof polymerExpressions.resolveEventHandler == 'function') {
- handler = function(e) {
- fn = fn || polymerExpressions.resolveEventHandler(model, path, node);
- fn(e, e.detail, e.currentTarget);
-
- if (Platform && typeof Platform.flush == 'function')
- Platform.flush();
- };
- } else {
- handler = function(e) {
- fn = fn || path.getValueFrom(model);
- receiver = receiver || resolveEventReceiver(model, path, node);
-
- fn.apply(receiver, [e, e.detail, e.currentTarget]);
-
- if (Platform && typeof Platform.flush == 'function')
- Platform.flush();
- };
- }
-
- node.addEventListener(eventType, handler);
-
- if (oneTime)
- return;
-
- function bindingValue() {
- return '{{ ' + path + ' }}';
- }
-
- return {
- open: bindingValue,
- discardChanges: bindingValue,
- close: function() {
- node.removeEventListener(eventType, handler);
- }
- };
- }
- }
-
- function isLiteralExpression(pathString) {
- switch (pathString) {
- case '':
- return false;
-
- case 'false':
- case 'null':
- case 'true':
- return true;
- }
-
- if (!isNaN(Number(pathString)))
- return true;
-
- return false;
- };
-
- function PolymerExpressions() {}
-
- PolymerExpressions.prototype = {
- // "built-in" filters
- styleObject: function(value) {
- var parts = [];
- for (var key in value) {
- parts.push(convertStylePropertyName(key) + ': ' + value[key]);
- }
- return parts.join('; ');
- },
-
- tokenList: function(value) {
- var tokens = [];
- for (var key in value) {
- if (value[key])
- tokens.push(key);
- }
- return tokens.join(' ');
- },
-
- // binding delegate API
- prepareInstancePositionChanged: function(template) {
- var indexIdent = template.polymerExpressionIndexIdent_;
- if (!indexIdent)
- return;
-
- return function(templateInstance, index) {
- templateInstance.model[indexIdent] = index;
- };
- },
-
- prepareBinding: function(pathString, name, node) {
- var path = Path.get(pathString);
- if (isEventHandler(name)) {
- if (!path.valid) {
- console.error('on-* bindings must be simple path expressions');
- return;
- }
-
- return prepareEventBinding(path, name, this);
- }
-
- if (!isLiteralExpression(pathString) && path.valid) {
- if (path.length == 1) {
- return function(model, node, oneTime) {
- if (oneTime)
- return path.getValueFrom(model);
-
- var scope = findScope(model, path[0]);
- return new PathObserver(scope, path);
- };
- }
- return; // bail out early if pathString is simple path.
- }
-
- return prepareBinding(pathString, name, node, this);
- },
-
- prepareInstanceModel: function(template) {
- var scopeName = template.polymerExpressionScopeIdent_;
- if (!scopeName)
- return;
-
- var parentScope = template.templateInstance ?
- template.templateInstance.model :
- template.model;
-
- var indexName = template.polymerExpressionIndexIdent_;
-
- return function(model) {
- var scope = Object.create(parentScope);
- scope[scopeName] = model;
- scope[indexName] = undefined;
- scope[parentScopeName] = parentScope;
- return scope;
- };
- }
- };
-
- global.PolymerExpressions = PolymerExpressions;
- if (global.exposeGetExpression)
- global.getExpression_ = getExpression;
-
- global.PolymerExpressions.prepareEventBinding = prepareEventBinding;
-})(this);
-
-/*
- * 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) {
-
-// inject style sheet
-var style = document.createElement('style');
-style.textContent = 'template {display: none !important;} /* injected by platform.js */';
-var head = document.querySelector('head');
-head.insertBefore(style, head.firstChild);
-
-// flush (with logging)
-var flushing;
-function flush() {
- if (!flushing) {
- flushing = true;
- scope.endOfMicrotask(function() {
- flushing = false;
- logFlags.data && console.group('Platform.flush()');
- scope.performMicrotaskCheckpoint();
- logFlags.data && console.groupEnd();
- });
- }
-};
-
-// polling dirty checker
-// flush periodically if platform does not have object observe.
-if (!Observer.hasObjectObserve) {
- var FLUSH_POLL_INTERVAL = 125;
- window.addEventListener('WebComponentsReady', function() {
- flush();
- scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL);
- });
-} else {
- // make flush a no-op when we have Object.observe
- flush = function() {};
-}
-
-if (window.CustomElements && !CustomElements.useNative) {
- var originalImportNode = Document.prototype.importNode;
- Document.prototype.importNode = function(node, deep) {
- var imported = originalImportNode.call(this, node, deep);
- CustomElements.upgradeAll(imported);
- return imported;
- }
-}
-
-// exports
-scope.flush = flush;
-
-})(window.Platform);
-
-
-//# sourceMappingURL=platform.concat.js.map

Powered by Google App Engine
This is Rietveld 408576698