| Index: pkg/web_components/lib/platform.concat.js
|
| diff --git a/pkg/web_components/lib/platform.concat.js b/pkg/web_components/lib/platform.concat.js
|
| index 9fa19b5c3d0c77a98d5e5a12c59c39c79628b508..6fa2b7b4f1830554045bbb76fead092f966584bc 100644
|
| --- a/pkg/web_components/lib/platform.concat.js
|
| +++ b/pkg/web_components/lib/platform.concat.js
|
| @@ -52,6 +52,12 @@ if (typeof WeakMap === 'undefined') {
|
| (function(global) {
|
| 'use strict';
|
|
|
| + var PROP_ADD_TYPE = 'add';
|
| + var PROP_UPDATE_TYPE = 'update';
|
| + var PROP_RECONFIGURE_TYPE = 'reconfigure';
|
| + var PROP_DELETE_TYPE = 'delete';
|
| + var ARRAY_SPLICE_TYPE = 'splice';
|
| +
|
| // Detect and do basic sanity checking on Object/Array.observe.
|
| function detectObjectObserve() {
|
| if (typeof Object.observe !== 'function' ||
|
| @@ -66,29 +72,44 @@ if (typeof WeakMap === 'undefined') {
|
| }
|
|
|
| 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)
|
| + if (records.length !== 3)
|
| return false;
|
|
|
| - if (records[0].type != 'add' ||
|
| - records[1].type != 'update' ||
|
| - records[2].type != 'delete' ||
|
| - records[3].type != 'splice' ||
|
| - records[4].type != 'splice') {
|
| + // TODO(rafaelw): Remove this when new change record type names make it to
|
| + // chrome release.
|
| + if (records[0].type == 'new' &&
|
| + records[1].type == 'updated' &&
|
| + records[2].type == 'deleted') {
|
| + PROP_ADD_TYPE = 'new';
|
| + PROP_UPDATE_TYPE = 'updated';
|
| + PROP_RECONFIGURE_TYPE = 'reconfigured';
|
| + PROP_DELETE_TYPE = 'deleted';
|
| + } else if (records[0].type != 'add' ||
|
| + records[1].type != 'update' ||
|
| + records[2].type != 'delete') {
|
| + console.error('Unexpected change record names for Object.observe. ' +
|
| + 'Using dirty-checking instead');
|
| return false;
|
| }
|
| -
|
| Object.unobserve(test, callback);
|
| - Array.unobserve(arr, callback);
|
| +
|
| + test = [0];
|
| + Array.observe(test, callback);
|
| + test[1] = 1;
|
| + test.length = 0;
|
| + Object.deliverChangeRecords(callback);
|
| + if (records.length != 2)
|
| + return false;
|
| + if (records[0].type != ARRAY_SPLICE_TYPE ||
|
| + records[1].type != ARRAY_SPLICE_TYPE) {
|
| + return false;
|
| + }
|
| + Array.unobserve(test, callback);
|
|
|
| return true;
|
| }
|
| @@ -247,7 +268,7 @@ if (typeof WeakMap === 'undefined') {
|
| for (var i = 0; i < this.length; i++) {
|
| if (i)
|
| obj = obj[this[i - 1]];
|
| - if (!isObject(obj))
|
| + if (!obj)
|
| return;
|
| observe(obj);
|
| }
|
| @@ -457,7 +478,7 @@ if (typeof WeakMap === 'undefined') {
|
| var resetScheduled = false;
|
|
|
| function observe(obj) {
|
| - if (!obj)
|
| + if (!isObject(obj))
|
| return;
|
|
|
| var index = toRemove.indexOf(obj);
|
| @@ -658,14 +679,7 @@ if (typeof WeakMap === 'undefined') {
|
|
|
| var runningMicrotaskCheckpoint = false;
|
|
|
| - var hasDebugForceFullDelivery = hasObserve && (function() {
|
| - try {
|
| - eval('%RunMicrotasks()');
|
| - return true;
|
| - } catch (ex) {
|
| - return false;
|
| - }
|
| - })();
|
| + var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'function';
|
|
|
| global.Platform = global.Platform || {};
|
|
|
| @@ -674,7 +688,7 @@ if (typeof WeakMap === 'undefined') {
|
| return;
|
|
|
| if (hasDebugForceFullDelivery) {
|
| - eval('%RunMicrotasks()');
|
| + Object.deliverAllChangeRecords();
|
| return;
|
| }
|
|
|
| @@ -1104,11 +1118,10 @@ if (typeof WeakMap === 'undefined') {
|
| }
|
| }
|
|
|
| - var expectedRecordTypes = {
|
| - add: true,
|
| - update: true,
|
| - delete: true
|
| - };
|
| + var expectedRecordTypes = {};
|
| + expectedRecordTypes[PROP_ADD_TYPE] = true;
|
| + expectedRecordTypes[PROP_UPDATE_TYPE] = true;
|
| + expectedRecordTypes[PROP_DELETE_TYPE] = true;
|
|
|
| function notifyFunction(object, name) {
|
| if (typeof Object.observe !== 'function')
|
| @@ -1132,7 +1145,7 @@ if (typeof WeakMap === 'undefined') {
|
| var value = observable.open(function(newValue, oldValue) {
|
| value = newValue;
|
| if (notify)
|
| - notify('update', oldValue);
|
| + notify(PROP_UPDATE_TYPE, oldValue);
|
| });
|
|
|
| Object.defineProperty(target, name, {
|
| @@ -1174,10 +1187,10 @@ if (typeof WeakMap === 'undefined') {
|
| if (!(record.name in oldValues))
|
| oldValues[record.name] = record.oldValue;
|
|
|
| - if (record.type == 'update')
|
| + if (record.type == PROP_UPDATE_TYPE)
|
| continue;
|
|
|
| - if (record.type == 'add') {
|
| + if (record.type == PROP_ADD_TYPE) {
|
| if (record.name in removed)
|
| delete removed[record.name];
|
| else
|
| @@ -1574,12 +1587,12 @@ if (typeof WeakMap === 'undefined') {
|
| for (var i = 0; i < changeRecords.length; i++) {
|
| var record = changeRecords[i];
|
| switch(record.type) {
|
| - case 'splice':
|
| + case ARRAY_SPLICE_TYPE:
|
| mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
|
| break;
|
| - case 'add':
|
| - case 'update':
|
| - case 'delete':
|
| + case PROP_ADD_TYPE:
|
| + case PROP_UPDATE_TYPE:
|
| + case PROP_DELETE_TYPE:
|
| if (!isIndex(record.name))
|
| continue;
|
| var index = toNumber(record.name);
|
| @@ -1628,6 +1641,16 @@ if (typeof WeakMap === 'undefined') {
|
| global.CompoundObserver = CompoundObserver;
|
| global.Path = Path;
|
| global.ObserverTransform = ObserverTransform;
|
| +
|
| + // TODO(rafaelw): Only needed for testing until new change record names
|
| + // make it to release.
|
| + global.Observer.changeRecordTypes = {
|
| + add: PROP_ADD_TYPE,
|
| + update: PROP_UPDATE_TYPE,
|
| + reconfigure: PROP_RECONFIGURE_TYPE,
|
| + 'delete': PROP_DELETE_TYPE,
|
| + splice: ARRAY_SPLICE_TYPE
|
| + };
|
| })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && module ? global : this || window);
|
|
|
| // prepoulate window.Platform.flags for default controls
|
| @@ -1643,8 +1666,7 @@ window.logFlags = window.logFlags || {};
|
| o = o.split('=');
|
| o[0] && (flags[o[0]] = o[1] || true);
|
| });
|
| - var entryPoint = document.currentScript ||
|
| - document.querySelector('script[src*="platform.js"]');
|
| + 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++) {
|
| @@ -1662,19 +1684,13 @@ window.logFlags = window.logFlags || {};
|
| // 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;
|
| + 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: {}};
|
| @@ -2554,9 +2570,6 @@ window.ShadowDOMPolyfill = {};
|
| 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);
|
| }
|
| @@ -2753,17 +2766,8 @@ window.ShadowDOMPolyfill = {};
|
| 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;
|
| + return dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
|
| }
|
|
|
| function dispatchEvent(event, originalWrapperTarget) {
|
| @@ -2775,15 +2779,15 @@ window.ShadowDOMPolyfill = {};
|
| scope.renderAllPending();
|
| var eventPath = retarget(originalWrapperTarget);
|
|
|
| - // For window "load" events the "load" event is dispatched at the window but
|
| + // 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)) {
|
| + if (event.type === 'load' &&
|
| + eventPath.length === 2 &&
|
| + eventPath[0].target instanceof wrappers.Document) {
|
| eventPath.shift();
|
| }
|
|
|
| @@ -2853,26 +2857,17 @@ window.ShadowDOMPolyfill = {};
|
|
|
| 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;
|
| - }
|
| + if (originalEvent.relatedTarget) {
|
| + var relatedTarget = wrap(originalEvent.relatedTarget);
|
| +
|
| + var adjusted = adjustRelatedTarget(currentTarget, relatedTarget);
|
| + if (adjusted === target)
|
| + return true;
|
| +
|
| relatedTargetTable.set(event, adjusted);
|
| }
|
| }
|
| @@ -2959,14 +2954,10 @@ window.ShadowDOMPolyfill = {};
|
| * @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 {
|
| + if (type instanceof OriginalEvent)
|
| + this.impl = type;
|
| + else
|
| return wrap(constructEvent(OriginalEvent, 'Event', type, options));
|
| - }
|
| }
|
| Event.prototype = {
|
| get target() {
|
| @@ -3049,11 +3040,7 @@ window.ShadowDOMPolyfill = {};
|
|
|
| var relatedTargetProto = {
|
| get relatedTarget() {
|
| - var relatedTarget = relatedTargetTable.get(this);
|
| - // relatedTarget can be null.
|
| - if (relatedTarget !== undefined)
|
| - return relatedTarget;
|
| - return wrap(unwrap(this).relatedTarget);
|
| + return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget);
|
| }
|
| };
|
|
|
| @@ -3142,12 +3129,8 @@ window.ShadowDOMPolyfill = {};
|
| 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);
|
| + Event.call(this);
|
| }
|
| BeforeUnloadEvent.prototype = Object.create(Event.prototype);
|
| mixin(BeforeUnloadEvent.prototype, {
|
| @@ -3159,9 +3142,6 @@ window.ShadowDOMPolyfill = {};
|
| }
|
| });
|
|
|
| - if (OriginalBeforeUnloadEvent)
|
| - registerWrapper(OriginalBeforeUnloadEvent, BeforeUnloadEvent);
|
| -
|
| function isValidListener(fun) {
|
| if (typeof fun === 'function')
|
| return true;
|
| @@ -3490,7 +3470,6 @@ window.ShadowDOMPolyfill = {};
|
| 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;
|
| @@ -4139,8 +4118,7 @@ window.ShadowDOMPolyfill = {};
|
| 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));
|
| + return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode));
|
| },
|
|
|
| normalize: function() {
|
| @@ -4327,12 +4305,6 @@ window.ShadowDOMPolyfill = {};
|
| }
|
| wrapperList.length = i;
|
| return wrapperList;
|
| - },
|
| -
|
| - remove: function() {
|
| - var p = this.parentNode;
|
| - if (p)
|
| - p.removeChild(this);
|
| }
|
| };
|
|
|
| @@ -5275,14 +5247,8 @@ window.ShadowDOMPolyfill = {};
|
| 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);
|
| },
|
|
|
| @@ -6802,15 +6768,7 @@ window.ShadowDOMPolyfill = {};
|
| 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);
|
| -
|
| + var prototype = object.prototype;
|
|
|
| // If we already used the object as a prototype for another custom
|
| // element.
|
| @@ -6871,13 +6829,13 @@ window.ShadowDOMPolyfill = {};
|
| });
|
|
|
| var p = {prototype: newPrototype};
|
| - if (extendsOption)
|
| - p.extends = extendsOption;
|
| + if (object.extends)
|
| + p.extends = object.extends;
|
|
|
| function CustomElementConstructor(node) {
|
| if (!node) {
|
| - if (extendsOption) {
|
| - return document.createElement(extendsOption, tagName);
|
| + if (object.extends) {
|
| + return document.createElement(object.extends, tagName);
|
| } else {
|
| return document.createElement(tagName);
|
| }
|
| @@ -7079,31 +7037,6 @@ window.ShadowDOMPolyfill = {};
|
|
|
| })(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.
|
| @@ -7274,7 +7207,7 @@ window.ShadowDOMPolyfill = {};
|
|
|
| Shimmed features:
|
|
|
| - * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
|
| + * :host, :ancestor: 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.
|
| @@ -7448,7 +7381,7 @@ var ShadowCSS = {
|
| def.rootStyles = styles;
|
| def.scopeStyles = def.rootStyles;
|
| var extendee = this.registry[def.extendsName];
|
| - if (extendee) {
|
| + if (extendee && (!root || root.querySelector('shadow'))) {
|
| def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles);
|
| }
|
| return def;
|
| @@ -7543,7 +7476,7 @@ var ShadowCSS = {
|
| var unscoped = this.extractUnscopedRulesFromCssText(cssText);
|
| cssText = this.insertPolyfillHostInCssText(cssText);
|
| cssText = this.convertColonHost(cssText);
|
| - cssText = this.convertColonHostContext(cssText);
|
| + cssText = this.convertColonAncestor(cssText);
|
| cssText = this.convertCombinators(cssText);
|
| if (scopeSelector) {
|
| var self = this, cssText;
|
| @@ -7592,7 +7525,7 @@ var ShadowCSS = {
|
| this.colonHostPartReplacer);
|
| },
|
| /*
|
| - * convert a rule like :host-context(.foo) > .bar { }
|
| + * convert a rule like :ancestor(.foo) > .bar { }
|
| *
|
| * to
|
| *
|
| @@ -7600,15 +7533,15 @@ var ShadowCSS = {
|
| *
|
| * and
|
| *
|
| - * :host-context(.foo:host) .bar { ... }
|
| + * :ancestor(.foo:host) .bar { ... }
|
| *
|
| * to
|
| *
|
| * scopeName.foo .bar { ... }
|
| */
|
| - convertColonHostContext: function(cssText) {
|
| - return this.convertColonRule(cssText, cssColonHostContextRe,
|
| - this.colonHostContextPartReplacer);
|
| + convertColonAncestor: function(cssText) {
|
| + return this.convertColonRule(cssText, cssColonAncestorRe,
|
| + this.colonAncestorPartReplacer);
|
| },
|
| convertColonRule: function(cssText, regExp, partReplacer) {
|
| // p1 = :host, p2 = contents of (), p3 rest of rule
|
| @@ -7626,7 +7559,7 @@ var ShadowCSS = {
|
| }
|
| });
|
| },
|
| - colonHostContextPartReplacer: function(host, part, suffix) {
|
| + colonAncestorPartReplacer: function(host, part, suffix) {
|
| if (part.match(polyfillHost)) {
|
| return this.colonHostPartReplacer(host, part, suffix);
|
| } else {
|
| @@ -7640,10 +7573,7 @@ var ShadowCSS = {
|
| * 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;
|
| + return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' ');
|
| },
|
| // change a selector like 'div' to 'name div'
|
| scopeRules: function(cssRules, scopeSelector) {
|
| @@ -7716,31 +7646,17 @@ var ShadowCSS = {
|
| return scoped;
|
| },
|
| insertPolyfillHostInCssText: function(selector) {
|
| - return selector.replace(colonHostContextRe, polyfillHostContext).replace(
|
| - colonHostRe, polyfillHost);
|
| + return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
|
| + polyfillHost).replace(colonAncestorRe, polyfillAncestor);
|
| },
|
| 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: \'' +
|
| + if (rule.style.content && !rule.style.content.match(/['"]+/)) {
|
| + return rule.style.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;
|
| + return rule.style.cssText;
|
| },
|
| replaceTextInStyles: function(styles, action) {
|
| if (styles && action) {
|
| @@ -7776,28 +7692,21 @@ var selectorRe = /([^{]*)({[\s\S]*?})/gim,
|
| cssPartRe = /::part\(([^)]*)\)/gim,
|
| // note: :host pre-processed to -shadowcsshost.
|
| polyfillHost = '-shadowcsshost',
|
| - // note: :host-context pre-processed to -shadowcsshostcontext.
|
| - polyfillHostContext = '-shadowcsscontext',
|
| + // note: :ancestor pre-processed to -shadowcssancestor.
|
| + polyfillAncestor = '-shadowcssancestor',
|
| parenSuffix = ')(?:\\((' +
|
| '(?:\\([^)(]*\\)|[^)(]*)+?' +
|
| ')\\))?([^,{]*)';
|
| cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
|
| - cssColonHostContextRe = new RegExp('(' + polyfillHostContext + parenSuffix, 'gim'),
|
| + cssColonAncestorRe = new RegExp('(' + polyfillAncestor + parenSuffix, 'gim'),
|
| selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
|
| + hostRe = /@host/gim,
|
| colonHostRe = /\:host/gim,
|
| - colonHostContextRe = /\:host-context/gim,
|
| + colonAncestorRe = /\:ancestor/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
|
| - ];
|
| + polyfillAncestorRe = new RegExp(polyfillAncestor, 'gim');
|
|
|
| function stylesToCssText(styles, preserveComments) {
|
| var cssText = '';
|
| @@ -8009,18 +7918,30 @@ scope.ShadowCSS = ShadowCSS;
|
| 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;
|
| - };
|
| +
|
| + var originalCreateShadowRoot = Element.prototype.webkitCreateShadowRoot;
|
| + Element.prototype.webkitCreateShadowRoot = function() {
|
| + var elderRoot = this.webkitShadowRoot;
|
| + var root = originalCreateShadowRoot.call(this);
|
| + root.olderShadowRoot = elderRoot;
|
| + root.host = this;
|
| + CustomElements.watchShadow(this);
|
| + return root;
|
| + }
|
| +
|
| + Object.defineProperties(Element.prototype, {
|
| + shadowRoot: {
|
| + get: function() {
|
| + return this.webkitShadowRoot;
|
| + }
|
| + },
|
| + createShadowRoot: {
|
| + value: function() {
|
| + return this.webkitCreateShadowRoot();
|
| + }
|
| }
|
| });
|
| -
|
| +
|
| window.templateContent = function(inTemplate) {
|
| // if MDV exists, it may need to boostrap this template to reveal content
|
| if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
|
| @@ -9868,38 +9789,23 @@ window.HTMLImports = window.HTMLImports || {flags:{}};
|
| },
|
| 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);
|
| + 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 {
|
| - 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;
|
| @@ -11024,7 +10930,6 @@ if (useNative) {
|
| scope.upgradeDocument = nop;
|
| scope.upgradeDocumentTree = nop;
|
| scope.takeRecords = nop;
|
| - scope.reservedTagList = [];
|
|
|
| } else {
|
|
|
| @@ -11081,10 +10986,6 @@ if (useNative) {
|
| // 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');
|
| @@ -11128,19 +11029,6 @@ if (useNative) {
|
| 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) {
|
| @@ -11437,7 +11325,6 @@ if (!Object.__proto__ && !useNative) {
|
|
|
| // exports
|
| scope.instanceof = isInstance;
|
| -scope.reservedTagList = reservedTagList;
|
|
|
| // bc
|
| document.register = document.registerElement;
|
| @@ -11871,7 +11758,7 @@ scope.styleResolver = styleResolver;
|
| */
|
| (function() {
|
| function shadowSelector(v) {
|
| - return 'body /shadow-deep/ ' + selector(v);
|
| + return 'body ^^ ' + selector(v);
|
| }
|
| function selector(v) {
|
| return '[touch-action="' + v + '"]';
|
| @@ -11893,31 +11780,18 @@ scope.styleResolver = styleResolver;
|
| }
|
| ];
|
| 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);
|
| - }
|
| + attrib2css.forEach(function(r) {
|
| + if (String(r) === r) {
|
| + styles += selector(r) + rule(r) + '\n';
|
| + styles += shadowSelector(r) + rule(r) + '\n';
|
| + } else {
|
| + styles += r.selectors.map(selector) + rule(r.rule) + '\n';
|
| + styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n';
|
| + }
|
| + });
|
| + var el = document.createElement('style');
|
| + el.textContent = styles;
|
| + document.head.appendChild(el);
|
| })();
|
|
|
| /*
|
| @@ -11941,6 +11815,16 @@ scope.styleResolver = styleResolver;
|
| * @return {Event} A new PointerEvent of type `inType` and initialized with properties from `inDict`.
|
| */
|
| (function(scope) {
|
| + // test for DOM Level 4 Events
|
| + var NEW_MOUSE_EVENT = false;
|
| + var HAS_BUTTONS = false;
|
| + try {
|
| + var ev = new MouseEvent('click', {buttons: 1});
|
| + NEW_MOUSE_EVENT = true;
|
| + HAS_BUTTONS = ev.buttons === 1;
|
| + ev = null;
|
| + } catch(e) {
|
| + }
|
|
|
| var MOUSE_PROPS = [
|
| 'bubbles',
|
| @@ -11957,8 +11841,6 @@ scope.styleResolver = styleResolver;
|
| 'metaKey',
|
| 'button',
|
| 'relatedTarget',
|
| - 'pageX',
|
| - 'pageY'
|
| ];
|
|
|
| var MOUSE_DEFAULTS = [
|
| @@ -11975,23 +11857,73 @@ scope.styleResolver = styleResolver;
|
| false,
|
| false,
|
| 0,
|
| - null,
|
| - 0,
|
| - 0
|
| + null
|
| ];
|
|
|
| function PointerEvent(inType, inDict) {
|
| - inDict = inDict || Object.create(null);
|
| + inDict = inDict || {};
|
| + // According to the w3c spec,
|
| + // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button
|
| + // MouseEvent.button == 0 can mean either no mouse button depressed, or the
|
| + // left mouse button depressed.
|
| + //
|
| + // As of now, the only way to distinguish between the two states of
|
| + // MouseEvent.button is by using the deprecated MouseEvent.which property, as
|
| + // this maps mouse buttons to positive integers > 0, and uses 0 to mean that
|
| + // no mouse button is held.
|
| + //
|
| + // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,
|
| + // but initMouseEvent does not expose an argument with which to set
|
| + // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set
|
| + // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations
|
| + // of app developers.
|
| + //
|
| + // The only way to propagate the correct state of MouseEvent.which and
|
| + // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0
|
| + // is to call initMouseEvent with a buttonArg value of -1.
|
| + //
|
| + // This is fixed with DOM Level 4's use of buttons
|
| + var buttons = inDict.buttons;
|
| + // touch has two possible buttons state: 0 and 1, rely on being told the right one
|
| + if (!HAS_BUTTONS && !buttons && inType !== 'touch') {
|
| + switch (inDict.which) {
|
| + case 1: buttons = 1; break;
|
| + case 2: buttons = 4; break;
|
| + case 3: buttons = 2; break;
|
| + default: buttons = 0;
|
| + }
|
| + }
|
|
|
| - var e = document.createEvent('Event');
|
| - e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
|
| + var e;
|
| + if (NEW_MOUSE_EVENT) {
|
| + e = new MouseEvent(inType, inDict);
|
| + } else {
|
| + e = document.createEvent('MouseEvent');
|
| +
|
| + // import values from the given dictionary
|
| + var props = {}, p;
|
| + for(var i = 0; i < MOUSE_PROPS.length; i++) {
|
| + p = MOUSE_PROPS[i];
|
| + props[p] = inDict[p] || MOUSE_DEFAULTS[i];
|
| + }
|
|
|
| - // 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];
|
| + // define the properties inherited from MouseEvent
|
| + e.initMouseEvent(
|
| + inType, props.bubbles, props.cancelable, props.view, props.detail,
|
| + props.screenX, props.screenY, props.clientX, props.clientY, props.ctrlKey,
|
| + props.altKey, props.shiftKey, props.metaKey, props.button, props.relatedTarget
|
| + );
|
| + }
|
| +
|
| + // make the event pass instanceof checks
|
| + e.__proto__ = PointerEvent.prototype;
|
| +
|
| + // define the buttons property according to DOM Level 3 spec
|
| + if (!HAS_BUTTONS) {
|
| + // IE 10 has buttons on MouseEvent.prototype as a getter w/o any setting
|
| + // mechanism
|
| + Object.defineProperty(e, 'buttons', {get: function(){ return buttons; }, enumerable: true});
|
| }
|
| - e.buttons = inDict.buttons || 0;
|
|
|
| // Spec requires that pointers without pressure specified use 0.5 for down
|
| // state and 0 for up state.
|
| @@ -11999,26 +11931,27 @@ scope.styleResolver = styleResolver;
|
| if (inDict.pressure) {
|
| pressure = inDict.pressure;
|
| } else {
|
| - pressure = e.buttons ? 0.5 : 0;
|
| + pressure = 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;
|
| + Object.defineProperties(e, {
|
| + pointerId: { value: inDict.pointerId || 0, enumerable: true },
|
| + width: { value: inDict.width || 0, enumerable: true },
|
| + height: { value: inDict.height || 0, enumerable: true },
|
| + pressure: { value: pressure, enumerable: true },
|
| + tiltX: { value: inDict.tiltX || 0, enumerable: true },
|
| + tiltY: { value: inDict.tiltY || 0, enumerable: true },
|
| + pointerType: { value: inDict.pointerType || '', enumerable: true },
|
| + hwTimestamp: { value: inDict.hwTimestamp || 0, enumerable: true },
|
| + isPrimary: { value: inDict.isPrimary || false, enumerable: true }
|
| + });
|
| return e;
|
| }
|
|
|
| + // PointerEvent extends MouseEvent
|
| + PointerEvent.prototype = Object.create(MouseEvent.prototype);
|
| +
|
| // attach to window
|
| if (!scope.PointerEvent) {
|
| scope.PointerEvent = PointerEvent;
|
| @@ -12129,9 +12062,7 @@ scope.styleResolver = styleResolver;
|
| 'type',
|
| 'target',
|
| 'currentTarget',
|
| - 'which',
|
| - 'pageX',
|
| - 'pageY'
|
| + 'which'
|
| ];
|
|
|
| var CLONE_DEFAULTS = [
|
| @@ -12166,8 +12097,6 @@ scope.styleResolver = styleResolver;
|
| '',
|
| null,
|
| null,
|
| - 0,
|
| - 0,
|
| 0
|
| ];
|
|
|
| @@ -12186,12 +12115,13 @@ scope.styleResolver = styleResolver;
|
| * - pointercancel: a pointer will no longer generate events
|
| */
|
| var dispatcher = {
|
| + targets: new WeakMap(),
|
| + handledEvents: new WeakMap(),
|
| pointermap: new scope.PointerMap(),
|
| - eventMap: Object.create(null),
|
| - captureInfo: Object.create(null),
|
| + eventMap: {},
|
| // Scope objects for native events.
|
| // This exists for ease of testing.
|
| - eventSources: Object.create(null),
|
| + eventSources: {},
|
| eventSourceList: [],
|
| /**
|
| * Add a new event source that will generate pointer events.
|
| @@ -12281,7 +12211,7 @@ scope.styleResolver = styleResolver;
|
| // 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) {
|
| + if (this.handledEvents.get(inEvent)) {
|
| return;
|
| }
|
| var type = inEvent.type;
|
| @@ -12289,7 +12219,7 @@ scope.styleResolver = styleResolver;
|
| if (fn) {
|
| fn(inEvent);
|
| }
|
| - inEvent._handledByPE = true;
|
| + this.handledEvents.set(inEvent, true);
|
| },
|
| // set up event listeners
|
| listen: function(target, events) {
|
| @@ -12320,14 +12250,14 @@ scope.styleResolver = styleResolver;
|
| */
|
| makeEvent: function(inType, inEvent) {
|
| // relatedTarget must be null if pointer is captured
|
| - if (this.captureInfo[inEvent.pointerId]) {
|
| + if (this.captureInfo) {
|
| inEvent.relatedTarget = null;
|
| }
|
| var e = new PointerEvent(inType, inEvent);
|
| if (inEvent.preventDefault) {
|
| e.preventDefault = inEvent.preventDefault;
|
| }
|
| - e._target = e._target || inEvent.target;
|
| + this.targets.set(e, this.targets.get(inEvent) || inEvent.target);
|
| return e;
|
| },
|
| // make and dispatch an event in one call
|
| @@ -12343,7 +12273,7 @@ scope.styleResolver = styleResolver;
|
| * properties.
|
| */
|
| cloneEvent: function(inEvent) {
|
| - var eventCopy = Object.create(null), p;
|
| + var eventCopy = {}, p;
|
| for (var i = 0; i < CLONE_PROPS.length; i++) {
|
| p = CLONE_PROPS[i];
|
| eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
|
| @@ -12367,32 +12297,33 @@ scope.styleResolver = styleResolver;
|
| 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;
|
| + if (this.captureInfo) {
|
| + if (this.captureInfo.id === inEvent.pointerId) {
|
| + return this.captureInfo.target;
|
| + }
|
| + }
|
| + return this.targets.get(inEvent);
|
| },
|
| setCapture: function(inPointerId, inTarget) {
|
| - if (this.captureInfo[inPointerId]) {
|
| - this.releaseCapture(inPointerId);
|
| + if (this.captureInfo) {
|
| + this.releaseCapture(this.captureInfo.id);
|
| }
|
| - this.captureInfo[inPointerId] = inTarget;
|
| - var e = document.createEvent('Event');
|
| - e.initEvent('gotpointercapture', true, false);
|
| - e.pointerId = inPointerId;
|
| + this.captureInfo = {id: inPointerId, target: inTarget};
|
| + var e = new PointerEvent('gotpointercapture', { bubbles: true });
|
| this.implicitRelease = this.releaseCapture.bind(this, inPointerId);
|
| document.addEventListener('pointerup', this.implicitRelease);
|
| document.addEventListener('pointercancel', this.implicitRelease);
|
| - e._target = inTarget;
|
| + this.targets.set(e, 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;
|
| + if (this.captureInfo && this.captureInfo.id === inPointerId) {
|
| + var e = new PointerEvent('lostpointercapture', { bubbles: true });
|
| + var t = this.captureInfo.target;
|
| + this.captureInfo = null;
|
| document.removeEventListener('pointerup', this.implicitRelease);
|
| document.removeEventListener('pointercancel', this.implicitRelease);
|
| - e._target = t;
|
| + this.targets.set(e, t);
|
| this.asyncDispatchEvent(e);
|
| }
|
| },
|
| @@ -12409,7 +12340,7 @@ scope.styleResolver = styleResolver;
|
| }
|
| },
|
| asyncDispatchEvent: function(inEvent) {
|
| - requestAnimationFrame(this.dispatchEvent.bind(this, inEvent));
|
| + setTimeout(this.dispatchEvent.bind(this, inEvent), 0);
|
| }
|
| };
|
| dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
|
| @@ -12552,13 +12483,6 @@ scope.styleResolver = styleResolver;
|
| // 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,
|
| @@ -12600,9 +12524,6 @@ scope.styleResolver = styleResolver;
|
| 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) {
|
| @@ -12667,7 +12588,6 @@ scope.styleResolver = styleResolver;
|
|
|
| (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;
|
| @@ -12686,6 +12606,7 @@ scope.styleResolver = styleResolver;
|
|
|
| // handler block for native touch events
|
| var touchEvents = {
|
| + scrollType: new WeakMap(),
|
| events: [
|
| 'touchstart',
|
| 'touchmove',
|
| @@ -12710,21 +12631,21 @@ scope.styleResolver = styleResolver;
|
| var a = el.getAttribute(ATTRIB);
|
| var st = this.touchActionToScrollType(a);
|
| if (st) {
|
| - el._scrollType = st;
|
| + this.scrollType.set(el, st);
|
| dispatcher.listen(el, this.events);
|
| // set touch-action on shadows as well
|
| allShadows(el).forEach(function(s) {
|
| - s._scrollType = st;
|
| + this.scrollType.set(s, st);
|
| dispatcher.listen(s, this.events);
|
| }, this);
|
| }
|
| },
|
| elementRemoved: function(el) {
|
| - el._scrollType = undefined;
|
| + this.scrollType['delete'](el);
|
| dispatcher.unlisten(el, this.events);
|
| // remove touch-action from shadow
|
| allShadows(el).forEach(function(s) {
|
| - s._scrollType = undefined;
|
| + this.scrollType['delete'](s);
|
| dispatcher.unlisten(s, this.events);
|
| }, this);
|
| },
|
| @@ -12734,9 +12655,9 @@ scope.styleResolver = styleResolver;
|
| var oldSt = this.touchActionToScrollType(oldValue);
|
| // simply update scrollType if listeners are already established
|
| if (st && oldSt) {
|
| - el._scrollType = st;
|
| + this.scrollType.set(el, st);
|
| allShadows(el).forEach(function(s) {
|
| - s._scrollType = st;
|
| + this.scrollType.set(s, st);
|
| }, this);
|
| } else if (oldSt) {
|
| this.elementRemoved(el);
|
| @@ -12806,46 +12727,44 @@ scope.styleResolver = styleResolver;
|
| 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.pointerId = inTouch.identifier + 2;
|
| + e.target = findTarget(e);
|
| e.bubbles = true;
|
| e.cancelable = true;
|
| e.detail = this.clickCount;
|
| e.button = 0;
|
| - e.buttons = this.typeToButtons(cte.type);
|
| + e.buttons = this.typeToButtons(this.currentTouchEvent);
|
| 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));
|
| - }
|
| + this.currentTouchEvent = inEvent.type;
|
| + var pointers = touchMap(tl, this.touchToPointer, this);
|
| + // forward touch preventDefaults
|
| + pointers.forEach(function(p) {
|
| + p.preventDefault = function() {
|
| + this.scrolling = false;
|
| + this.firstXY = null;
|
| + inEvent.preventDefault();
|
| + };
|
| + }, this);
|
| + pointers.forEach(inFunction, this);
|
| },
|
| // 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;
|
| + var scrollAxis = this.scrollType.get(inEvent.currentTarget);
|
| if (scrollAxis === 'none') {
|
| // this element is a touch-action: none, should never scroll
|
| ret = false;
|
| @@ -12892,7 +12811,7 @@ scope.styleResolver = styleResolver;
|
| // index in pointermap.
|
| if (key !== 1 && !this.findTouch(tl, key - 2)) {
|
| var p = value.out;
|
| - d.push(p);
|
| + d.push(this.touchToPointer(p));
|
| }
|
| }, this);
|
| d.forEach(this.cancelOut, this);
|
| @@ -13108,7 +13027,8 @@ scope.styleResolver = styleResolver;
|
| var dispatcher = scope.dispatcher;
|
|
|
| // only activate if this platform does not have pointer events
|
| - if (window.PointerEvent !== scope.PointerEvent) {
|
| + if (window.navigator.pointerEnabled === undefined) {
|
| + Object.defineProperty(window.navigator, 'pointerEnabled', {value: true, enumerable: true});
|
|
|
| if (window.navigator.msPointerEnabled) {
|
| var tp = window.navigator.msMaxTouchPoints;
|
| @@ -13488,7 +13408,7 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| // 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));
|
| + setTimeout(this.runQueue.bind(this, inHandlerFns, e), 0);
|
| },
|
| // Dispatch the queued events
|
| runQueue: function(inHandlers, inEvent) {
|
| @@ -13549,7 +13469,10 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| }
|
| },
|
| asyncDispatchEvent: function(inEvent, inTarget) {
|
| - requestAnimationFrame(this.dispatchEvent.bind(this, inEvent, inTarget));
|
| + var fn = function() {
|
| + this.dispatchEvent(inEvent, inTarget);
|
| + }.bind(this);
|
| + setTimeout(fn, 0);
|
| },
|
| preventTap: function(inPointerId) {
|
| var t = this.recognizers.tap;
|
| @@ -14168,8 +14091,7 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| pointers.push(p);
|
| });
|
| var dist = 0;
|
| - // start with at least two pointers
|
| - var points = {a: pointers[0], b: pointers[1]};
|
| + var points = {};
|
| var x, y, d;
|
| for (var i = 0; i < pointers.length; i++) {
|
| var a = pointers[i];
|
| @@ -14347,12 +14269,19 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| }
|
| })(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
|
| +// 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(global) {
|
| 'use strict';
|
| @@ -14367,24 +14296,42 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| 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_ = {};
|
| + function unbind(node, name) {
|
| + var bindings = node.bindings;
|
| + if (!bindings) {
|
| + node.bindings = {};
|
| + return;
|
| + }
|
|
|
| - if (bindings[name])
|
| - binding[name].close();
|
| + var binding = bindings[name];
|
| + if (!binding)
|
| + return;
|
|
|
| - return bindings[name] = binding;
|
| + binding.close();
|
| + bindings[name] = undefined;
|
| }
|
|
|
| - function returnBinding(node, name, binding) {
|
| - return binding;
|
| - }
|
| + Node.prototype.unbind = function(name) {
|
| + unbind(this, name);
|
| + };
|
| +
|
| + Node.prototype.unbindAll = function() {
|
| + if (!this.bindings)
|
| + return;
|
| + var names = Object.keys(this.bindings);
|
| + for (var i = 0; i < names.length; i++) {
|
| + var binding = this.bindings[names[i]];
|
| + if (binding)
|
| + binding.close();
|
| + }
|
| +
|
| + this.bindings = {};
|
| + };
|
|
|
| function sanitizeValue(value) {
|
| return value == null ? '' : value;
|
| @@ -14400,19 +14347,6 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| };
|
| }
|
|
|
| - 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);
|
| @@ -14420,9 +14354,9 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (oneTime)
|
| return updateText(this, value);
|
|
|
| - var observable = value;
|
| - updateText(this, observable.open(textBinding(this)));
|
| - return maybeUpdateBindings(this, name, observable);
|
| + unbind(this, 'textContent');
|
| + updateText(this, value.open(textBinding(this)));
|
| + return this.bindings.textContent = value;
|
| }
|
|
|
| function updateAttribute(el, name, conditional, value) {
|
| @@ -14453,12 +14387,11 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (oneTime)
|
| return updateAttribute(this, name, conditional, value);
|
|
|
| -
|
| - var observable = value;
|
| + unbind(this, name);
|
| updateAttribute(this, name, conditional,
|
| - observable.open(attributeBinding(this, name, conditional)));
|
| + value.open(attributeBinding(this, name, conditional)));
|
|
|
| - return maybeUpdateBindings(this, name, observable);
|
| + return this.bindings[name] = value;
|
| };
|
|
|
| var checkboxEventType;
|
| @@ -14527,13 +14460,15 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| }
|
| input.addEventListener(eventType, eventHandler);
|
|
|
| - return {
|
| - close: function() {
|
| - input.removeEventListener(eventType, eventHandler);
|
| - observable.close();
|
| - },
|
| + var capturedClose = observable.close;
|
| + observable.close = function() {
|
| + if (!capturedClose)
|
| + return;
|
| + input.removeEventListener(eventType, eventHandler);
|
|
|
| - observable_: observable
|
| + observable.close = capturedClose;
|
| + observable.close();
|
| + capturedClose = undefined;
|
| }
|
| }
|
|
|
| @@ -14577,10 +14512,10 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (input.tagName === 'INPUT' &&
|
| input.type === 'radio') {
|
| getAssociatedRadioButtons(input).forEach(function(radio) {
|
| - var checkedBinding = radio.bindings_.checked;
|
| + var checkedBinding = radio.bindings.checked;
|
| if (checkedBinding) {
|
| // Set the value directly to avoid an infinite call stack.
|
| - checkedBinding.observable_.setValue(false);
|
| + checkedBinding.setValue(false);
|
| }
|
| });
|
| }
|
| @@ -14590,6 +14525,7 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| 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;
|
| @@ -14597,15 +14533,13 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (oneTime)
|
| return updateInput(this, name, value, sanitizeFn);
|
|
|
| -
|
| - var observable = value;
|
| - var binding = bindInputEvent(this, name, observable, postEventFn);
|
| + unbind(this, name);
|
| + bindInputEvent(this, name, value, postEventFn);
|
| updateInput(this, name,
|
| - observable.open(inputBinding(this, name, sanitizeFn)),
|
| + value.open(inputBinding(this, name, sanitizeFn)),
|
| sanitizeFn);
|
|
|
| - // Checkboxes may need to update bindings of other checkboxes.
|
| - return updateBindings(this, name, binding);
|
| + return this.bindings[name] = value;
|
| }
|
|
|
| HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
|
| @@ -14617,11 +14551,12 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (oneTime)
|
| return updateInput(this, 'value', value);
|
|
|
| - var observable = value;
|
| - var binding = bindInputEvent(this, 'value', observable);
|
| + unbind(this, 'value');
|
| + bindInputEvent(this, 'value', value);
|
| updateInput(this, 'value',
|
| - observable.open(inputBinding(this, 'value', sanitizeValue)));
|
| - return maybeUpdateBindings(this, name, binding);
|
| + value.open(inputBinding(this, 'value', sanitizeValue)));
|
| +
|
| + return this.bindings.value = value;
|
| }
|
|
|
| function updateOption(option, value) {
|
| @@ -14630,18 +14565,18 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| var selectBinding;
|
| var oldValue;
|
| if (parentNode instanceof HTMLSelectElement &&
|
| - parentNode.bindings_ &&
|
| - parentNode.bindings_.value) {
|
| + parentNode.bindings &&
|
| + parentNode.bindings.value) {
|
| select = parentNode;
|
| - selectBinding = select.bindings_.value;
|
| + selectBinding = select.bindings.value;
|
| oldValue = select.value;
|
| }
|
|
|
| option.value = sanitizeValue(value);
|
|
|
| if (select && select.value != oldValue) {
|
| - selectBinding.observable_.setValue(select.value);
|
| - selectBinding.observable_.discardChanges();
|
| + selectBinding.setValue(select.value);
|
| + selectBinding.discardChanges();
|
| Platform.performMicrotaskCheckpoint();
|
| }
|
| }
|
| @@ -14661,10 +14596,10 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| 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);
|
| + unbind(this, 'value');
|
| + bindInputEvent(this, 'value', value);
|
| + updateOption(this, value.open(optionBinding(this)));
|
| + return this.bindings.value = value;
|
| }
|
|
|
| HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
|
| @@ -14679,22 +14614,27 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (oneTime)
|
| return updateInput(this, name, value);
|
|
|
| - var observable = value;
|
| - var binding = bindInputEvent(this, name, observable);
|
| + unbind(this, name);
|
| + bindInputEvent(this, name, value);
|
| updateInput(this, name,
|
| - observable.open(inputBinding(this, name)));
|
| -
|
| - // Option update events may need to access select bindings.
|
| - return updateBindings(this, name, binding);
|
| + value.open(inputBinding(this, name)));
|
| + return this.bindings[name] = value;
|
| }
|
| })(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
|
| +// 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(global) {
|
| 'use strict';
|
| @@ -15159,13 +15099,8 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (oneTime)
|
| return;
|
|
|
| - if (!this.bindings_) {
|
| - this.bindings_ = { ref: value };
|
| - } else {
|
| - this.bindings_.ref = value;
|
| - }
|
| -
|
| - return value;
|
| + this.unbind('ref');
|
| + return this.bindings.ref = value;
|
| },
|
|
|
| processBindingDirectives_: function(directives) {
|
| @@ -15176,6 +15111,7 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (this.iterator_) {
|
| this.iterator_.close();
|
| this.iterator_ = undefined;
|
| + this.bindings.iterator = undefined;
|
| }
|
|
|
| return;
|
| @@ -15183,6 +15119,8 @@ PointerGestureEvent.prototype.preventTap = function() {
|
|
|
| if (!this.iterator_) {
|
| this.iterator_ = new TemplateIterator(this);
|
| + this.bindings = this.bindings || {};
|
| + this.bindings.iterator = this.iterator_;
|
| }
|
|
|
| this.iterator_.updateDependencies(directives, this.model_);
|
| @@ -15195,16 +15133,14 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| return this.iterator_;
|
| },
|
|
|
| - createInstance: function(model, bindingDelegate, delegate_) {
|
| + createInstance: function(model, bindingDelegate, delegate_,
|
| + instanceBindings_) {
|
| 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
|
| @@ -15219,32 +15155,21 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| var instance = stagingDocument.createDocumentFragment();
|
| instance.templateCreator_ = this;
|
| instance.protoContent_ = content;
|
| - instance.bindings_ = [];
|
| - instance.terminator_ = null;
|
| - var instanceRecord = instance.templateInstance_ = {
|
| +
|
| + var instanceRecord = {
|
| 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_);
|
| + instanceBindings_);
|
| clone.templateInstance_ = instanceRecord;
|
| - if (collectTerminator)
|
| - instance.terminator_ = clone;
|
| }
|
|
|
| instanceRecord.firstNode = instance.firstChild;
|
| @@ -15279,8 +15204,7 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| clear: function() {
|
| this.model_ = undefined;
|
| this.delegate_ = undefined;
|
| - if (this.bindings_ && this.bindings_.ref)
|
| - this.bindings_.ref.close()
|
| + this.bindings_ = undefined;
|
| this.refContent_ = undefined;
|
| if (!this.iterator_)
|
| return;
|
| @@ -15385,14 +15309,9 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| var pathString = s.slice(startIndex + 2, endIndex).trim();
|
| tokens.push(oneTime); // ONE_TIME?
|
| onlyOneTime = onlyOneTime && oneTime;
|
| + tokens.push(Path.get(pathString)); // PATH
|
| 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;
|
| }
|
| @@ -15610,14 +15529,14 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| }
|
| });
|
|
|
| - var emptyInstance = document.createDocumentFragment();
|
| - emptyInstance.bindings_ = [];
|
| - emptyInstance.terminator_ = null;
|
| -
|
| function TemplateIterator(templateElement) {
|
| this.closed = false;
|
| this.templateElement_ = templateElement;
|
| - this.instances = [];
|
| +
|
| + // Flattened array of tuples:
|
| + // <instanceTerminatorNode, [bindingsSetupByInstance]>
|
| + this.terminators = [];
|
| +
|
| this.deps = undefined;
|
| this.iteratedValue = [];
|
| this.presentValue = undefined;
|
| @@ -15712,53 +15631,63 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| this.iteratedValue));
|
| },
|
|
|
| - getLastInstanceNode: function(index) {
|
| + getTerminatorAt: function(index) {
|
| if (index == -1)
|
| return this.templateElement_;
|
| - var instance = this.instances[index];
|
| - var terminator = instance.terminator_;
|
| - if (!terminator)
|
| - return this.getLastInstanceNode(index - 1);
|
| -
|
| + var terminator = this.terminators[index*2];
|
| if (terminator.nodeType !== Node.ELEMENT_NODE ||
|
| this.templateElement_ === terminator) {
|
| return terminator;
|
| }
|
|
|
| - var subtemplateIterator = terminator.iterator_;
|
| - if (!subtemplateIterator)
|
| + var subIterator = terminator.iterator_;
|
| + if (!subIterator)
|
| return terminator;
|
|
|
| - return subtemplateIterator.getLastTemplateNode();
|
| + return subIterator.getTerminatorAt(subIterator.terminators.length/2 - 1);
|
| },
|
|
|
| - getLastTemplateNode: function() {
|
| - return this.getLastInstanceNode(this.instances.length - 1);
|
| - },
|
| + // TODO(rafaelw): If we inserting sequences of instances we can probably
|
| + // avoid lots of calls to getTerminatorAt(), or cache its result.
|
| + insertInstanceAt: function(index, fragment, instanceNodes,
|
| + instanceBindings) {
|
| + var previousTerminator = this.getTerminatorAt(index - 1);
|
| + var terminator = previousTerminator;
|
| + if (fragment)
|
| + terminator = fragment.lastChild || terminator;
|
| + else if (instanceNodes)
|
| + terminator = instanceNodes[instanceNodes.length - 1] || terminator;
|
|
|
| - insertInstanceAt: function(index, fragment) {
|
| - var previousInstanceLast = this.getLastInstanceNode(index - 1);
|
| + this.terminators.splice(index*2, 0, terminator, instanceBindings);
|
| var parent = this.templateElement_.parentNode;
|
| - this.instances.splice(index, 0, fragment);
|
| + var insertBeforeNode = previousTerminator.nextSibling;
|
|
|
| - parent.insertBefore(fragment, previousInstanceLast.nextSibling);
|
| + if (fragment) {
|
| + parent.insertBefore(fragment, insertBeforeNode);
|
| + } else if (instanceNodes) {
|
| + for (var i = 0; i < instanceNodes.length; i++)
|
| + parent.insertBefore(instanceNodes[i], insertBeforeNode);
|
| + }
|
| },
|
|
|
| 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];
|
| + var instanceNodes = [];
|
| + var previousTerminator = this.getTerminatorAt(index - 1);
|
| + var terminator = this.getTerminatorAt(index);
|
| + instanceNodes.instanceBindings = this.terminators[index*2 + 1];
|
| + this.terminators.splice(index*2, 2);
|
|
|
| - while (lastNode !== previousInstanceLast) {
|
| - var node = previousInstanceLast.nextSibling;
|
| - if (node == lastNode)
|
| - lastNode = previousInstanceLast;
|
| + var parent = this.templateElement_.parentNode;
|
| + while (terminator !== previousTerminator) {
|
| + var node = previousTerminator.nextSibling;
|
| + if (node == terminator)
|
| + terminator = previousTerminator;
|
|
|
| - instance.appendChild(parent.removeChild(node));
|
| + parent.removeChild(node);
|
| + instanceNodes.push(node);
|
| }
|
|
|
| - return instance;
|
| + return instanceNodes;
|
| },
|
|
|
| getDelegateFn: function(fn) {
|
| @@ -15792,50 +15721,46 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| 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);
|
| - }
|
| - }
|
| + splices.forEach(function(splice) {
|
| + splice.removed.forEach(function(model) {
|
| + var instanceNodes =
|
| + this.extractInstanceAt(splice.index + removeDelta);
|
| + instanceCache.set(model, instanceNodes);
|
| + }, this);
|
|
|
| removeDelta -= splice.addedCount;
|
| - }
|
| + }, this);
|
|
|
| - // Instance Insertions
|
| - for (var i = 0; i < splices.length; i++) {
|
| - var splice = splices[i];
|
| + splices.forEach(function(splice) {
|
| var addIndex = splice.index;
|
| for (; addIndex < splice.index + splice.addedCount; addIndex++) {
|
| var model = this.iteratedValue[addIndex];
|
| - var instance = instanceCache.get(model);
|
| - if (instance) {
|
| + var fragment = undefined;
|
| + var instanceNodes = instanceCache.get(model);
|
| + var instanceBindings;
|
| + if (instanceNodes) {
|
| instanceCache.delete(model);
|
| + instanceBindings = instanceNodes.instanceBindings;
|
| } else {
|
| - if (this.instanceModelFn_) {
|
| + instanceBindings = [];
|
| + if (this.instanceModelFn_)
|
| model = this.instanceModelFn_(model);
|
| - }
|
|
|
| - if (model === undefined) {
|
| - instance = emptyInstance;
|
| - } else {
|
| - instance = template.createInstance(model, undefined, delegate);
|
| + if (model !== undefined) {
|
| + fragment = template.createInstance(model, undefined, delegate,
|
| + instanceBindings);
|
| }
|
| }
|
|
|
| - this.insertInstanceAt(addIndex, instance);
|
| + this.insertInstanceAt(addIndex, fragment, instanceNodes,
|
| + instanceBindings);
|
| }
|
| - }
|
| + }, this);
|
|
|
| - instanceCache.forEach(function(instance) {
|
| - this.closeInstanceBindings(instance);
|
| + instanceCache.forEach(function(instanceNodes) {
|
| + this.closeInstanceBindings(instanceNodes.instanceBindings);
|
| }, this);
|
|
|
| if (this.instancePositionChangedFn_)
|
| @@ -15843,11 +15768,17 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| },
|
|
|
| reportInstanceMoved: function(index) {
|
| - var instance = this.instances[index];
|
| - if (instance === emptyInstance)
|
| - return;
|
| + var previousTerminator = this.getTerminatorAt(index - 1);
|
| + var terminator = this.getTerminatorAt(index);
|
| + if (previousTerminator === terminator)
|
| + return; // instance has zero nodes.
|
|
|
| - this.instancePositionChangedFn_(instance.templateInstance_, index);
|
| + // We must use the first node of the instance, because any subsequent
|
| + // nodes may have been generated by sub-templates.
|
| + // TODO(rafaelw): This is brittle WRT instance mutation -- e.g. if the
|
| + // first node was removed by script.
|
| + var templateInstance = previousTerminator.nextSibling.templateInstance;
|
| + this.instancePositionChangedFn_(templateInstance, index);
|
| },
|
|
|
| reportInstancesMoved: function(splices) {
|
| @@ -15875,17 +15806,16 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (offset == 0)
|
| return;
|
|
|
| - var length = this.instances.length;
|
| + var length = this.terminators.length / 2;
|
| 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();
|
| + closeInstanceBindings: function(instanceBindings) {
|
| + for (var i = 0; i < instanceBindings.length; i++) {
|
| + instanceBindings[i].close();
|
| }
|
| },
|
|
|
| @@ -15901,11 +15831,11 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| if (this.closed)
|
| return;
|
| this.unobserve();
|
| - for (var i = 0; i < this.instances.length; i++) {
|
| - this.closeInstanceBindings(this.instances[i]);
|
| + for (var i = 1; i < this.terminators.length; i += 2) {
|
| + this.closeInstanceBindings(this.terminators[i]);
|
| }
|
|
|
| - this.instances.length = 0;
|
| + this.terminators.length = 0;
|
| this.closeDeps();
|
| this.templateElement_.iterator_ = undefined;
|
| this.closed = true;
|
| @@ -16954,12 +16884,19 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| };
|
| })(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
|
| +// Copyright 2013 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';
|
| @@ -17386,18 +17323,10 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| return this.getValue(model, undefined, filterRegistry);
|
|
|
| var observer = new CompoundObserver();
|
| - // captures deps.
|
| - var firstValue = this.getValue(model, observer, filterRegistry);
|
| - var firstTime = true;
|
| + this.getValue(model, observer, filterRegistry); // captures deps.
|
| var self = this;
|
|
|
| function valueFn() {
|
| - // deps cannot have changed on first value retrieval.
|
| - if (firstTime) {
|
| - firstTime = false;
|
| - return firstValue;
|
| - }
|
| -
|
| if (self.dynamicDeps)
|
| observer.startReset();
|
|
|
| @@ -17541,23 +17470,6 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| }
|
| }
|
|
|
| - 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 = {
|
| @@ -17601,7 +17513,7 @@ PointerGestureEvent.prototype.preventTap = function() {
|
| return prepareEventBinding(path, name, this);
|
| }
|
|
|
| - if (!isLiteralExpression(pathString) && path.valid) {
|
| + if (path.valid) {
|
| if (path.length == 1) {
|
| return function(model, node, oneTime) {
|
| if (oneTime)
|
| @@ -17609,8 +17521,9 @@ PointerGestureEvent.prototype.preventTap = function() {
|
|
|
| var scope = findScope(model, path[0]);
|
| return new PathObserver(scope, path);
|
| - };
|
| + }
|
| }
|
| +
|
| return; // bail out early if pathString is simple path.
|
| }
|
|
|
| @@ -17673,17 +17586,14 @@ function flush() {
|
| };
|
|
|
| // 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();
|
| +var FLUSH_POLL_INTERVAL = 125;
|
| +window.addEventListener('WebComponentsReady', function() {
|
| + flush();
|
| + // flush periodically if platform does not have object observe.
|
| + if (!Observer.hasObjectObserve) {
|
| 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;
|
|
|