| Index: pkg/polymer/lib/src/js/polymer/polymer.concat.js
|
| diff --git a/pkg/polymer/lib/src/js/polymer/polymer.concat.js b/pkg/polymer/lib/src/js/polymer/polymer.concat.js
|
| index 85a6554d084eb8e9ebf2d0f3302c1278158a976e..2478c928e744ef62ef805160cffdaedeb98749bb 100644
|
| --- a/pkg/polymer/lib/src/js/polymer/polymer.concat.js
|
| +++ b/pkg/polymer/lib/src/js/polymer/polymer.concat.js
|
| @@ -1,14 +1,3549 @@
|
| +/**
|
| + * @license
|
| + * 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
|
| + */
|
| +window.PolymerGestures = {};
|
| +
|
| +/*
|
| + * 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(scope) {
|
| + 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) {
|
| + if (!element) {
|
| + return document;
|
| + }
|
| + 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);
|
| + },
|
| + LCA: function(a, b) {
|
| + if (a === b) {
|
| + return a;
|
| + }
|
| + if (a && !b) {
|
| + return a;
|
| + }
|
| + if (b && !a) {
|
| + return b;
|
| + }
|
| + if (!b && !a) {
|
| + return document;
|
| + }
|
| + // fast case, a is a direct descendant of b or vice versa
|
| + if (a.contains && a.contains(b)) {
|
| + return a;
|
| + }
|
| + if (b.contains && 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; n && (i < u); i++) {
|
| + n = n.parentNode || n.host;
|
| + }
|
| + return n;
|
| + },
|
| + depth: function(n) {
|
| + var d = 0;
|
| + while(n) {
|
| + d++;
|
| + n = n.parentNode || n.host;
|
| + }
|
| + return d;
|
| + },
|
| + deepContains: function(a, b) {
|
| + var common = this.LCA(a, b);
|
| + // if a is the common ancestor, it must "deeply" contain b
|
| + return common === a;
|
| + },
|
| + insideNode: function(node, x, y) {
|
| + var rect = node.getBoundingClientRect();
|
| + return (rect.left <= x) && (x <= rect.right) && (rect.top <= y) && (y <= rect.bottom);
|
| + }
|
| + };
|
| + scope.targetFinding = target;
|
| + /**
|
| + * Given an event, finds the "deepest" node that could have been the original target before ShadowDOM retargetting
|
| + *
|
| + * @param {Event} Event An event object with clientX and clientY properties
|
| + * @return {Element} The probable event origninator
|
| + */
|
| + scope.findTarget = target.findTarget.bind(target);
|
| + /**
|
| + * Determines if the "container" node deeply contains the "containee" node, including situations where the "containee" is contained by one or more ShadowDOM
|
| + * roots.
|
| + *
|
| + * @param {Node} container
|
| + * @param {Node} containee
|
| + * @return {Boolean}
|
| + */
|
| + scope.deepContains = target.deepContains.bind(target);
|
| +
|
| + /**
|
| + * Determines if the x/y position is inside the given node.
|
| + *
|
| + * Example:
|
| + *
|
| + * function upHandler(event) {
|
| + * var innode = PolymerGestures.insideNode(event.target, event.clientX, event.clientY);
|
| + * if (innode) {
|
| + * // wait for tap?
|
| + * } else {
|
| + * // tap will never happen
|
| + * }
|
| + * }
|
| + *
|
| + * @param {Node} node
|
| + * @param {Number} x Screen X position
|
| + * @param {Number} y screen Y position
|
| + * @return {Boolean}
|
| + */
|
| + scope.insideNode = target.insideNode;
|
| +
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + *
|
| + * 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() {
|
| + function shadowSelector(v) {
|
| + return 'body /deep/ ' + selector(v);
|
| + }
|
| + function selector(v) {
|
| + return '[touch-action="' + v + '"]';
|
| + }
|
| + function rule(v) {
|
| + return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + ';}';
|
| + }
|
| + 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 hasTouchAction = typeof document.head.style.touchAction === 'string';
|
| + // only add shadow selectors if shadowdom is supported
|
| + var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoot;
|
| +
|
| + if (hasTouchAction) {
|
| + 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 (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
|
| + */
|
| +
|
| +/**
|
| + * 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
|
| + ];
|
| +
|
| + var NOP_FACTORY = function(){ return function(){}; };
|
| +
|
| + var eventFactory = {
|
| + // TODO(dfreedm): this is overridden by tap recognizer, needs review
|
| + preventTap: NOP_FACTORY,
|
| + makeBaseEvent: function(inType, inDict) {
|
| + var e = document.createEvent('Event');
|
| + e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
|
| + e.preventTap = eventFactory.preventTap(e);
|
| + return e;
|
| + },
|
| + makeGestureEvent: function(inType, inDict) {
|
| + inDict = inDict || Object.create(null);
|
| +
|
| + var e = this.makeBaseEvent(inType, inDict);
|
| + for (var i = 0, keys = Object.keys(inDict), k; i < keys.length; i++) {
|
| + k = keys[i];
|
| + e[k] = inDict[k];
|
| + }
|
| + return e;
|
| + },
|
| + makePointerEvent: function(inType, inDict) {
|
| + inDict = inDict || Object.create(null);
|
| +
|
| + var e = this.makeBaseEvent(inType, inDict);
|
| + // 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;
|
| + }
|
| + };
|
| +
|
| + scope.eventFactory = eventFactory;
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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
|
| + */
|
| +
|
| +/**
|
| + * 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.PolymerGestures);
|
| +
|
| +/*
|
| + * 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(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',
|
| + 'timeStamp',
|
| + // gesture addons
|
| + 'preventTap',
|
| + '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,
|
| + function(){},
|
| + false
|
| + ];
|
| +
|
| + var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined');
|
| +
|
| + var wrap = window.ShadowDOMPolyfill && ShadowDOMPolyfill.wrapIfNeeded || function(e){ return e; };
|
| +
|
| + var eventFactory = scope.eventFactory;
|
| + /**
|
| + * 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),
|
| + // Scope objects for native events.
|
| + // This exists for ease of testing.
|
| + eventSources: Object.create(null),
|
| + eventSourceList: [],
|
| + gestures: [],
|
| + gestureQueue: [],
|
| + /**
|
| + * 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);
|
| + }
|
| + },
|
| + registerGesture: function(name, source) {
|
| + this.gestures.push(source);
|
| + },
|
| + register: function(element) {
|
| + // NOTE: Work around for #4, don't add listeners to individual Polymer elmenets in SD Polyfill
|
| + if (window.ShadowDOMPolyfill && element !== document) {
|
| + return;
|
| + }
|
| + 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);
|
| + }
|
| + },
|
| + // EVENTS
|
| + down: function(inEvent) {
|
| + this.fireEvent('down', inEvent);
|
| + },
|
| + move: function(inEvent) {
|
| + // pipe move events into gesture queue directly
|
| + inEvent.type = 'move';
|
| + this.fillGestureQueue(inEvent);
|
| + },
|
| + up: function(inEvent) {
|
| + this.fireEvent('up', inEvent);
|
| + },
|
| + cancel: function(inEvent) {
|
| + inEvent.tapPrevented = true;
|
| + this.fireEvent('up', inEvent);
|
| + },
|
| + // LISTENER LOGIC
|
| + eventHandler: function(inEvent) {
|
| + // This is used to prevent multiple dispatch of events 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._handledByPG) {
|
| + return;
|
| + }
|
| + var type = inEvent.type;
|
| + var fn = this.eventMap && this.eventMap[type];
|
| + if (fn) {
|
| + fn(inEvent);
|
| + }
|
| + inEvent._handledByPG = 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: function(target, eventName) {
|
| + // NOTE: Work around for #4, use native event listener in SD Polyfill
|
| + if (window.ShadowDOMPolyfill) {
|
| + target.addEventListener_(eventName, this.boundHandler);
|
| + } else {
|
| + target.addEventListener(eventName, this.boundHandler);
|
| + }
|
| + },
|
| + removeEvent: function(target, eventName) {
|
| + // NOTE: Work around for #4, use native event listener in SD Polyfill
|
| + if (window.ShadowDOMPolyfill) {
|
| + target.removeEventListener_(eventName, this.boundHandler);
|
| + } else {
|
| + 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) {
|
| + var e = eventFactory.makePointerEvent(inType, inEvent);
|
| + e.preventDefault = inEvent.preventDefault;
|
| + e.tapPrevented = inEvent.tapPrevented;
|
| + 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 (p === 'target' || p === 'relatedTarget') {
|
| + if (HAS_SVG_INSTANCE && eventCopy[p] instanceof SVGElementInstance) {
|
| + eventCopy[p] = eventCopy[p].correspondingUseElement;
|
| + }
|
| + eventCopy[p] = wrap(eventCopy[p]);
|
| + }
|
| + }
|
| + // keep the semantics of preventDefault
|
| + eventCopy.preventDefault = inEvent.preventDefault;
|
| + return eventCopy;
|
| + },
|
| + /**
|
| + * 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: function(inEvent) {
|
| + var t = inEvent._target;
|
| + if (t) {
|
| + t.dispatchEvent(inEvent);
|
| + // clone the event for the gesture system to process
|
| + // clone after dispatch to pick up gesture prevention code
|
| + var clone = this.cloneEvent(inEvent);
|
| + clone.target = t;
|
| + this.fillGestureQueue(clone);
|
| + }
|
| + },
|
| + gestureTrigger: function() {
|
| + // process the gesture queue
|
| + for (var i = 0, e; i < this.gestureQueue.length; i++) {
|
| + e = this.gestureQueue[i];
|
| + for (var j = 0, g; j < this.gestures.length; j++) {
|
| + g = this.gestures[j];
|
| + if (g.events.indexOf(e.type) >= 0) {
|
| + g[e.type].call(g, e);
|
| + }
|
| + }
|
| + }
|
| + this.gestureQueue.length = 0;
|
| + },
|
| + fillGestureQueue: function(ev) {
|
| + // only trigger the gesture queue once
|
| + if (!this.gestureQueue.length) {
|
| + requestAnimationFrame(this.boundGestureTrigger);
|
| + }
|
| + this.gestureQueue.push(ev);
|
| + }
|
| + };
|
| + dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
|
| + dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher);
|
| + scope.dispatcher = dispatcher;
|
| + scope.register = dispatcher.register.bind(dispatcher);
|
| + scope.unregister = dispatcher.unregister.bind(dispatcher);
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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
|
| + */
|
| +
|
| +/**
|
| + * 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('PolymerGestures: MutationObservers not found, touch-action will not be dynamically detected');
|
| + };
|
| + }
|
| +
|
| + scope.Installer = Installer;
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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 (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',
|
| + ],
|
| + 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);
|
| + 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.mouseup(inEvent);
|
| + }
|
| + var e = this.prepareEvent(inEvent);
|
| + pointermap.set(this.POINTER_ID, e.target);
|
| + dispatcher.down(e);
|
| + }
|
| + },
|
| + mousemove: function(inEvent) {
|
| + if (!this.isEventSimulatedFromTouch(inEvent)) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.target = pointermap.get(this.POINTER_ID);
|
| + dispatcher.move(e);
|
| + }
|
| + },
|
| + mouseup: function(inEvent) {
|
| + if (!this.isEventSimulatedFromTouch(inEvent)) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.relatedTarget = e.target;
|
| + e.target = pointermap.get(this.POINTER_ID);
|
| + dispatcher.up(e);
|
| + this.cleanupMouse();
|
| + }
|
| + },
|
| + cleanupMouse: function() {
|
| + pointermap['delete'](this.POINTER_ID);
|
| + }
|
| + };
|
| +
|
| + scope.mouseEvents = mouseEvents;
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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(scope) {
|
| + var dispatcher = scope.dispatcher;
|
| + 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;
|
| + var HAS_TOUCH_ACTION = typeof document.head.style.touchAction === 'string';
|
| +
|
| + // handler block for native touch events
|
| + var touchEvents = {
|
| + events: [
|
| + 'touchstart',
|
| + 'touchmove',
|
| + 'touchend',
|
| + 'touchcancel'
|
| + ],
|
| + register: function(target) {
|
| + if (HAS_TOUCH_ACTION) {
|
| + dispatcher.listen(target, this.events);
|
| + } else {
|
| + INSTALLER.enableOnSubtree(target);
|
| + }
|
| + },
|
| + unregister: function(target) {
|
| + if (HAS_TOUCH_ACTION) {
|
| + 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;
|
| + },
|
| + findTarget: function(touch, id) {
|
| + if (this.currentTouchEvent.type === 'touchstart') {
|
| + return scope.findTarget(touch);
|
| + }
|
| + // reuse target we found in touchstart
|
| + return pointermap.get(id);
|
| + },
|
| + 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 = this.findTarget(inTouch, id);
|
| + e.bubbles = true;
|
| + e.cancelable = true;
|
| + e.detail = this.clickCount;
|
| + 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.down);
|
| + }
|
| + },
|
| + down: function(inPointer) {
|
| + var p = pointermap.set(inPointer.pointerId, inPointer.target);
|
| + dispatcher.down(inPointer);
|
| + },
|
| + touchmove: function(inEvent) {
|
| + if (HAS_TOUCH_ACTION) {
|
| + this.processTouches(inEvent, this.move);
|
| + } else {
|
| + if (!this.scrolling) {
|
| + if (this.shouldScroll(inEvent)) {
|
| + this.scrolling = true;
|
| + this.touchcancel(inEvent);
|
| + } else {
|
| + inEvent.preventDefault();
|
| + this.processTouches(inEvent, this.move);
|
| + }
|
| + }
|
| + }
|
| + },
|
| + move: function(inPointer) {
|
| + var pointer = pointermap.get(inPointer.pointerId);
|
| + // a finger drifted off the screen, ignore it
|
| + if (!pointer) {
|
| + return;
|
| + }
|
| + dispatcher.move(inPointer);
|
| + },
|
| + touchend: function(inEvent) {
|
| + this.dedupSynthMouse(inEvent);
|
| + this.processTouches(inEvent, this.up);
|
| + },
|
| + up: function(inPointer) {
|
| + if (!this.scrolling) {
|
| + inPointer.relatedTarget = scope.findTarget(inPointer);
|
| + dispatcher.up(inPointer);
|
| + }
|
| + this.cleanUpPointer(inPointer);
|
| + },
|
| + cancel: function(inPointer) {
|
| + inPointer.relatedTarget = scope.findTarget(inPointer);
|
| + dispatcher.cancel(inPointer);
|
| + this.cleanUpPointer(inPointer);
|
| + },
|
| + touchcancel: function(inEvent) {
|
| + this.processTouches(inEvent, this.cancel);
|
| + },
|
| + 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) {
|
| + INSTALLER = new scope.Installer(touchEvents.elementAdded, touchEvents.elementRemoved, touchEvents.elementChanged, touchEvents);
|
| + }
|
| +
|
| + scope.touchEvents = touchEvents;
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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(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',
|
| + 'MSPointerCancel',
|
| + ],
|
| + 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) {
|
| + var e = this.prepareEvent(inEvent);
|
| + pointermap.set(inEvent.pointerId, e.target);
|
| + dispatcher.down(e);
|
| + },
|
| + MSPointerMove: function(inEvent) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.target = pointermap.get(e.pointerId);
|
| + dispatcher.move(e);
|
| + },
|
| + MSPointerUp: function(inEvent) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.relatedTarget = e.target;
|
| + e.target = pointermap.get(e.pointerId);
|
| + dispatcher.up(e);
|
| + this.cleanup(inEvent.pointerId);
|
| + },
|
| + MSPointerCancel: function(inEvent) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.relatedTarget = e.target;
|
| + e.target = pointermap.get(e.pointerId);
|
| + dispatcher.cancel(e);
|
| + this.cleanup(inEvent.pointerId);
|
| + }
|
| + };
|
| +
|
| + scope.msEvents = msEvents;
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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(scope) {
|
| + var dispatcher = scope.dispatcher;
|
| + var pointermap = dispatcher.pointermap;
|
| + var pointerEvents = {
|
| + events: [
|
| + 'pointerdown',
|
| + 'pointermove',
|
| + 'pointerup',
|
| + 'pointercancel'
|
| + ],
|
| + prepareEvent: function(inEvent) {
|
| + return dispatcher.cloneEvent(inEvent);
|
| + },
|
| + register: function(target) {
|
| + dispatcher.listen(target, this.events);
|
| + },
|
| + unregister: function(target) {
|
| + dispatcher.unlisten(target, this.events);
|
| + },
|
| + cleanup: function(id) {
|
| + pointermap['delete'](id);
|
| + },
|
| + pointerdown: function(inEvent) {
|
| + var e = this.prepareEvent(inEvent);
|
| + pointermap.set(e.pointerId, e.target);
|
| + dispatcher.down(e);
|
| + },
|
| + pointermove: function(inEvent) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.target = pointermap.get(e.pointerId);
|
| + dispatcher.move(e);
|
| + },
|
| + pointerup: function(inEvent) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.relatedTarget = e.target;
|
| + e.target = pointermap.get(e.pointerId);
|
| + dispatcher.up(e);
|
| + this.cleanup(inEvent.pointerId);
|
| + },
|
| + pointercancel: function(inEvent) {
|
| + var e = this.prepareEvent(inEvent);
|
| + e.relatedTarget = e.target;
|
| + e.target = pointermap.get(e.pointerId);
|
| + dispatcher.cancel(e);
|
| + this.cleanup(inEvent.pointerId);
|
| + }
|
| + };
|
| +
|
| + scope.pointerEvents = pointerEvents;
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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
|
| + */
|
| +
|
| +/**
|
| + * 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;
|
| +
|
| + if (window.PointerEvent) {
|
| + dispatcher.registerSource('pointer', scope.pointerEvents);
|
| + } else if (window.navigator.msPointerEnabled) {
|
| + dispatcher.registerSource('ms', scope.msEvents);
|
| + } else {
|
| + dispatcher.registerSource('mouse', scope.mouseEvents);
|
| + if (window.ontouchstart !== undefined) {
|
| + dispatcher.registerSource('touch', scope.touchEvents);
|
| + }
|
| + }
|
| +
|
| + dispatcher.register(document);
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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
|
| + */
|
| +
|
| +/**
|
| + * 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 eventFactory = scope.eventFactory;
|
| + var pointermap = new scope.PointerMap();
|
| + var track = {
|
| + events: [
|
| + 'down',
|
| + 'move',
|
| + 'up',
|
| + ],
|
| + 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 e = eventFactory.makeGestureEvent(inType, {
|
| + bubbles: true,
|
| + cancelable: true,
|
| + dx: d.x,
|
| + dy: d.y,
|
| + ddx: dd.x,
|
| + ddy: dd.y,
|
| + x: inEvent.x,
|
| + y: inEvent.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.relatedTarget,
|
| + pointerType: inEvent.pointerType,
|
| + pointerId: inEvent.pointerId
|
| + });
|
| + t.downTarget.dispatchEvent(e);
|
| + },
|
| + down: 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);
|
| + }
|
| + },
|
| + move: 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);
|
| + }
|
| + p.lastMoveEvent = inEvent;
|
| + }
|
| + },
|
| + up: function(inEvent) {
|
| + var p = pointermap.get(inEvent.pointerId);
|
| + if (p) {
|
| + if (p.tracking) {
|
| + this.fireTrack('trackend', inEvent, p);
|
| + }
|
| + pointermap.delete(inEvent.pointerId);
|
| + }
|
| + }
|
| + };
|
| + dispatcher.registerGesture('track', track);
|
| + })(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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
|
| + */
|
| +
|
| +/**
|
| + * 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 eventFactory = scope.eventFactory;
|
| + 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: [
|
| + 'down',
|
| + 'move',
|
| + 'up',
|
| + ],
|
| + 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;
|
| + },
|
| + down: function(inEvent) {
|
| + if (inEvent.isPrimary && !this.heldPointer) {
|
| + this.heldPointer = inEvent;
|
| + this.target = inEvent.target;
|
| + this.holdJob = setInterval(this.pulse.bind(this), this.HOLD_DELAY);
|
| + }
|
| + },
|
| + up: function(inEvent) {
|
| + if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
|
| + this.cancel();
|
| + }
|
| + },
|
| + move: 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 = {
|
| + bubbles: true,
|
| + cancelable: true,
|
| + pointerType: this.heldPointer.pointerType,
|
| + pointerId: this.heldPointer.pointerId,
|
| + x: this.heldPointer.clientX,
|
| + y: this.heldPointer.clientY
|
| + };
|
| + if (inHoldTime) {
|
| + p.holdTime = inHoldTime;
|
| + }
|
| + var e = eventFactory.makeGestureEvent(inType, p);
|
| + this.target.dispatchEvent(e);
|
| + }
|
| + };
|
| + dispatcher.registerGesture('hold', hold);
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + * 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
|
| + */
|
| +
|
| +/**
|
| + * 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 eventFactory = scope.eventFactory;
|
| + var pointermap = new scope.PointerMap();
|
| + var tap = {
|
| + events: [
|
| + 'down',
|
| + 'up'
|
| + ],
|
| + down: function(inEvent) {
|
| + if (inEvent.isPrimary && !inEvent.tapPrevented) {
|
| + pointermap.set(inEvent.pointerId, {
|
| + target: inEvent.target,
|
| + buttons: inEvent.buttons,
|
| + x: inEvent.clientX,
|
| + y: inEvent.clientY
|
| + });
|
| + }
|
| + },
|
| + shouldTap: function(e, downState) {
|
| + if (e.pointerType === 'mouse') {
|
| + // only allow left click to tap for mouse
|
| + return downState.buttons === 1;
|
| + }
|
| + return !e.tapPrevented;
|
| + },
|
| + up: function(inEvent) {
|
| + var start = pointermap.get(inEvent.pointerId);
|
| + if (start && this.shouldTap(inEvent, start)) {
|
| + // up.relatedTarget is target currently under finger
|
| + var t = scope.targetFinding.LCA(start.target, inEvent.relatedTarget);
|
| + if (t) {
|
| + var e = eventFactory.makeGestureEvent('tap', {
|
| + bubbles: true,
|
| + cancelable: true,
|
| + x: inEvent.clientX,
|
| + y: inEvent.clientY,
|
| + detail: inEvent.detail,
|
| + pointerType: inEvent.pointerType,
|
| + pointerId: inEvent.pointerId,
|
| + altKey: inEvent.altKey,
|
| + ctrlKey: inEvent.ctrlKey,
|
| + metaKey: inEvent.metaKey,
|
| + shiftKey: inEvent.shiftKey
|
| + });
|
| + t.dispatchEvent(e);
|
| + }
|
| + }
|
| + pointermap.delete(inEvent.pointerId);
|
| + }
|
| + };
|
| + // patch eventFactory to remove id from tap's pointermap for preventTap calls
|
| + eventFactory.preventTap = function(e) {
|
| + return function() {
|
| + e.tapPrevented = true;
|
| + pointermap.delete(e.pointerId);
|
| + };
|
| + };
|
| + dispatcher.registerGesture('tap', tap);
|
| +})(window.PolymerGestures);
|
| +
|
| +/*
|
| + 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';
|
| +
|
| + 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) {
|
| + this.dynamicDeps = typeof object == 'function' ||
|
| + object.dynamicDeps ||
|
| + (accessor == '[' && !(property instanceof Literal));
|
| +
|
| + // 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.simplePath =
|
| + !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();
|
| + });
|
| + }
|
| +
|
| + 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 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 (!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;
|
| +
|
| +})(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.
|
| + * 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
|
| */
|
| -Polymer = {};
|
| +Polymer = {
|
| + version: '0.3.1-604ba08'
|
| +};
|
|
|
| /*
|
| - * 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.
|
| + * 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
|
| */
|
|
|
| // TODO(sorvell): this ensures Polymer is an object and not a function
|
| @@ -20,10 +3555,14 @@ if (typeof window.Polymer === 'function') {
|
|
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // copy own properties from 'api' to 'prototype, with name hinting for 'super'
|
| @@ -53,10 +3592,13 @@ if (typeof window.Polymer === 'function') {
|
|
|
| })(Polymer);
|
|
|
| -/*
|
| - * 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.
|
| +/*
|
| + * 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(scope) {
|
| @@ -121,10 +3663,14 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| var registry = {};
|
| @@ -155,133 +3701,147 @@ if (typeof window.Polymer === 'function') {
|
| */
|
| })(Polymer);
|
|
|
| -/*
|
| - * 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) {
|
| - // super
|
| -
|
| - // `arrayOfArgs` is an optional array of args like one might pass
|
| - // to `Function.apply`
|
| -
|
| - // TODO(sjmiles):
|
| - // $super must be installed on an instance or prototype chain
|
| - // as `super`, and invoked via `this`, e.g.
|
| - // `this.super();`
|
| -
|
| - // will not work if function objects are not unique, for example,
|
| - // when using mixins.
|
| - // The memoization strategy assumes each function exists on only one
|
| - // prototype chain i.e. we use the function object for memoizing)
|
| - // perhaps we can bookkeep on the prototype itself instead
|
| - function $super(arrayOfArgs) {
|
| - // since we are thunking a method call, performance is important here:
|
| - // memoize all lookups, once memoized the fast path calls no other
|
| - // functions
|
| - //
|
| - // find the caller (cannot be `strict` because of 'caller')
|
| - var caller = $super.caller;
|
| - // memoized 'name of method'
|
| - var nom = caller.nom;
|
| - // memoized next implementation prototype
|
| - var _super = caller._super;
|
| - if (!_super) {
|
| - if (!nom) {
|
| - nom = caller.nom = nameInThis.call(this, caller);
|
| - }
|
| - if (!nom) {
|
| - console.warn('called super() on a method not installed declaratively (has no .nom property)');
|
| - }
|
| - // super prototype is either cached or we have to find it
|
| - // by searching __proto__ (at the 'top')
|
| - _super = memoizeSuper(caller, nom, getPrototypeOf(this));
|
| - }
|
| - if (!_super) {
|
| - // if _super is falsey, there is no super implementation
|
| - //console.warn('called $super(' + nom + ') where there is no super implementation');
|
| - } else {
|
| - // our super function
|
| - var fn = _super[nom];
|
| - // memoize information so 'fn' can call 'super'
|
| - if (!fn._super) {
|
| - memoizeSuper(fn, nom, _super);
|
| - }
|
| - // invoke the inherited method
|
| - // if 'fn' is not function valued, this will throw
|
| - return fn.apply(this, arrayOfArgs || []);
|
| - }
|
| - }
|
| -
|
| - function nextSuper(proto, name, caller) {
|
| - // look for an inherited prototype that implements name
|
| - while (proto) {
|
| - if ((proto[name] !== caller) && proto[name]) {
|
| - return proto;
|
| - }
|
| - proto = getPrototypeOf(proto);
|
| - }
|
| - }
|
| -
|
| - function memoizeSuper(method, name, proto) {
|
| - // find and cache next prototype containing `name`
|
| - // we need the prototype so we can do another lookup
|
| - // from here
|
| - method._super = nextSuper(proto, name, method);
|
| - if (method._super) {
|
| - // _super is a prototype, the actual method is _super[name]
|
| - // tag super method with it's name for further lookups
|
| - method._super[name].nom = name;
|
| - }
|
| - return method._super;
|
| - }
|
| -
|
| - function nameInThis(value) {
|
| - var p = this.__proto__;
|
| - while (p && p !== HTMLElement.prototype) {
|
| - // TODO(sjmiles): getOwnPropertyNames is absurdly expensive
|
| - var n$ = Object.getOwnPropertyNames(p);
|
| - for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) {
|
| - var d = Object.getOwnPropertyDescriptor(p, n);
|
| - if (typeof d.value === 'function' && d.value === value) {
|
| - return n;
|
| - }
|
| - }
|
| - p = p.__proto__;
|
| - }
|
| - }
|
| -
|
| - // NOTE: In some platforms (IE10) the prototype chain is faked via
|
| - // __proto__. Therefore, always get prototype via __proto__ instead of
|
| - // the more standard Object.getPrototypeOf.
|
| - function getPrototypeOf(prototype) {
|
| - return prototype.__proto__;
|
| - }
|
| -
|
| - // utility function to precompute name tags for functions
|
| - // in a (unchained) prototype
|
| - function hintSuper(prototype) {
|
| - // tag functions with their prototype name to optimize
|
| - // super call invocations
|
| - for (var n in prototype) {
|
| - var pd = Object.getOwnPropertyDescriptor(prototype, n);
|
| - if (pd && typeof pd.value === 'function') {
|
| - pd.value.nom = n;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // exports
|
| -
|
| - scope.super = $super;
|
| -
|
| -})(Polymer);
|
| +/*
|
| + * 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(scope) {
|
| + // super
|
| +
|
| + // `arrayOfArgs` is an optional array of args like one might pass
|
| + // to `Function.apply`
|
| +
|
| + // TODO(sjmiles):
|
| + // $super must be installed on an instance or prototype chain
|
| + // as `super`, and invoked via `this`, e.g.
|
| + // `this.super();`
|
| +
|
| + // will not work if function objects are not unique, for example,
|
| + // when using mixins.
|
| + // The memoization strategy assumes each function exists on only one
|
| + // prototype chain i.e. we use the function object for memoizing)
|
| + // perhaps we can bookkeep on the prototype itself instead
|
| + function $super(arrayOfArgs) {
|
| + // since we are thunking a method call, performance is important here:
|
| + // memoize all lookups, once memoized the fast path calls no other
|
| + // functions
|
| + //
|
| + // find the caller (cannot be `strict` because of 'caller')
|
| + var caller = $super.caller;
|
| + // memoized 'name of method'
|
| + var nom = caller.nom;
|
| + // memoized next implementation prototype
|
| + var _super = caller._super;
|
| + if (!_super) {
|
| + if (!nom) {
|
| + nom = caller.nom = nameInThis.call(this, caller);
|
| + }
|
| + if (!nom) {
|
| + console.warn('called super() on a method not installed declaratively (has no .nom property)');
|
| + }
|
| + // super prototype is either cached or we have to find it
|
| + // by searching __proto__ (at the 'top')
|
| + // invariant: because we cache _super on fn below, we never reach
|
| + // here from inside a series of calls to super(), so it's ok to
|
| + // start searching from the prototype of 'this' (at the 'top')
|
| + // we must never memoize a null super for this reason
|
| + _super = memoizeSuper(caller, nom, getPrototypeOf(this));
|
| + }
|
| + // our super function
|
| + var fn = _super[nom];
|
| + if (fn) {
|
| + // memoize information so 'fn' can call 'super'
|
| + if (!fn._super) {
|
| + // must not memoize null, or we lose our invariant above
|
| + memoizeSuper(fn, nom, _super);
|
| + }
|
| + // invoke the inherited method
|
| + // if 'fn' is not function valued, this will throw
|
| + return fn.apply(this, arrayOfArgs || []);
|
| + }
|
| + }
|
| +
|
| + function nameInThis(value) {
|
| + var p = this.__proto__;
|
| + while (p && p !== HTMLElement.prototype) {
|
| + // TODO(sjmiles): getOwnPropertyNames is absurdly expensive
|
| + var n$ = Object.getOwnPropertyNames(p);
|
| + for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) {
|
| + var d = Object.getOwnPropertyDescriptor(p, n);
|
| + if (typeof d.value === 'function' && d.value === value) {
|
| + return n;
|
| + }
|
| + }
|
| + p = p.__proto__;
|
| + }
|
| + }
|
| +
|
| + function memoizeSuper(method, name, proto) {
|
| + // find and cache next prototype containing `name`
|
| + // we need the prototype so we can do another lookup
|
| + // from here
|
| + var s = nextSuper(proto, name, method);
|
| + if (s[name]) {
|
| + // `s` is a prototype, the actual method is `s[name]`
|
| + // tag super method with it's name for quicker lookups
|
| + s[name].nom = name;
|
| + }
|
| + return method._super = s;
|
| + }
|
| +
|
| + function nextSuper(proto, name, caller) {
|
| + // look for an inherited prototype that implements name
|
| + while (proto) {
|
| + if ((proto[name] !== caller) && proto[name]) {
|
| + return proto;
|
| + }
|
| + proto = getPrototypeOf(proto);
|
| + }
|
| + // must not return null, or we lose our invariant above
|
| + // in this case, a super() call was invoked where no superclass
|
| + // method exists
|
| + // TODO(sjmiles): thow an exception?
|
| + return Object;
|
| + }
|
| +
|
| + // NOTE: In some platforms (IE10) the prototype chain is faked via
|
| + // __proto__. Therefore, always get prototype via __proto__ instead of
|
| + // the more standard Object.getPrototypeOf.
|
| + function getPrototypeOf(prototype) {
|
| + return prototype.__proto__;
|
| + }
|
| +
|
| + // utility function to precompute name tags for functions
|
| + // in a (unchained) prototype
|
| + function hintSuper(prototype) {
|
| + // tag functions with their prototype name to optimize
|
| + // super call invocations
|
| + for (var n in prototype) {
|
| + var pd = Object.getOwnPropertyDescriptor(prototype, n);
|
| + if (pd && typeof pd.value === 'function') {
|
| + pd.value.nom = n;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // exports
|
| +
|
| + scope.super = $super;
|
| +
|
| +})(Polymer);
|
|
|
| -/*
|
| - * 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.
|
| +/*
|
| + * 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(scope) {
|
| @@ -348,9 +3908,12 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| @@ -369,7 +3932,7 @@ if (typeof window.Polymer === 'function') {
|
| for (var n in apis) {
|
| extend(prototype, apis[n]);
|
| }
|
| - }
|
| + };
|
|
|
| // exports
|
|
|
| @@ -378,10 +3941,14 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| var utils = {
|
| @@ -481,9 +4048,12 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
| @@ -505,24 +4075,10 @@ if (typeof window.Polymer === 'function') {
|
| // (1) we don't want the attribute to be set and (2) we want to support
|
| // multiple event listeners ('host' and 'instance') and Node.bind
|
| // by default supports 1 thing being bound.
|
| - // We do, however, leverage the event hookup code in PolymerExpressions
|
| - // so that we have a common code path for handling declarative events.
|
| - var self = this, bindable, eventName;
|
| - for (var n in events) {
|
| - eventName = EVENT_PREFIX + n;
|
| - bindable = PolymerExpressions.prepareEventBinding(
|
| - Path.get(events[n]),
|
| - eventName,
|
| - {
|
| - resolveEventHandler: function(model, path, node) {
|
| - var fn = path.getValueFrom(self);
|
| - if (fn) {
|
| - return fn.bind(self);
|
| - }
|
| - }
|
| - }
|
| - );
|
| - bindable(this, this, false);
|
| + for (var type in events) {
|
| + var methodName = events[type];
|
| + this.addEventListener(type, this.element.getEventHandler(this, this,
|
| + methodName));
|
| }
|
| },
|
| // call 'method' or function method on 'obj' with 'args', if the method exists
|
| @@ -546,10 +4102,14 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // instance api for attributes
|
| @@ -640,10 +4200,14 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // imports
|
| @@ -659,27 +4223,24 @@ if (typeof window.Polymer === 'function') {
|
| var empty = [];
|
|
|
| var properties = {
|
| - observeProperties: function() {
|
| - var n$ = this._observeNames, pn$ = this._publishNames;
|
| - if ((n$ && n$.length) || (pn$ && pn$.length)) {
|
| - var self = this;
|
| - var o = this._propertyObserver = new CompoundObserver();
|
| - // keep track of property observer so we can shut it down
|
| + createPropertyObserver: function() {
|
| + var n$ = this._observeNames;
|
| + if (n$ && n$.length) {
|
| + var o = this._propertyObserver = new CompoundObserver(true);
|
| this.registerObservers([o]);
|
| + // TODO(sorvell): may not be kosher to access the value here (this[n]);
|
| + // previously we looked at the descriptor on the prototype
|
| + // this doesn't work for inheritance and not for accessors without
|
| + // a value property
|
| for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
|
| o.addPath(this, n);
|
| - // observer array properties
|
| - var pd = Object.getOwnPropertyDescriptor(this.__proto__, n);
|
| - if (pd && pd.value) {
|
| - this.observeArrayValue(n, pd.value, null);
|
| - }
|
| - }
|
| - for (var i=0, l=pn$.length, n; (i<l) && (n=pn$[i]); i++) {
|
| - if (!this.observe || (this.observe[n] === undefined)) {
|
| - o.addPath(this, n);
|
| - }
|
| + this.observeArrayValue(n, this[n], null);
|
| }
|
| - o.open(this.notifyPropertyChanges, this);
|
| + }
|
| + },
|
| + openPropertyObserver: function() {
|
| + if (this._propertyObserver) {
|
| + this._propertyObserver.open(this.notifyPropertyChanges, this);
|
| }
|
| },
|
| notifyPropertyChanges: function(newValues, oldValues, paths) {
|
| @@ -687,20 +4248,35 @@ if (typeof window.Polymer === 'function') {
|
| for (var i in oldValues) {
|
| // note: paths is of form [object, path, object, path]
|
| name = paths[2 * i + 1];
|
| - if (this.publish[name] !== undefined) {
|
| - this.reflectPropertyToAttribute(name);
|
| - }
|
| method = this.observe[name];
|
| if (method) {
|
| - this.observeArrayValue(name, newValues[i], oldValues[i]);
|
| + var ov = oldValues[i], nv = newValues[i];
|
| + // observes the value if it is an array
|
| + this.observeArrayValue(name, nv, ov);
|
| if (!called[method]) {
|
| - called[method] = true;
|
| - // observes the value if it is an array
|
| - this.invokeMethod(method, [oldValues[i], newValues[i], arguments]);
|
| + // only invoke change method if one of ov or nv is not (undefined | null)
|
| + if ((ov !== undefined && ov !== null) || (nv !== undefined && nv !== null)) {
|
| + called[method] = true;
|
| + // TODO(sorvell): call method with the set of values it's expecting;
|
| + // e.g. 'foo bar': 'invalidate' expects the new and old values for
|
| + // foo and bar. Currently we give only one of these and then
|
| + // deliver all the arguments.
|
| + this.invokeMethod(method, [ov, nv, arguments]);
|
| + }
|
| }
|
| }
|
| }
|
| },
|
| + deliverChanges: function() {
|
| + if (this._propertyObserver) {
|
| + this._propertyObserver.deliver();
|
| + }
|
| + },
|
| + propertyChanged_: function(name, value, oldValue) {
|
| + if (this.reflect[name]) {
|
| + this.reflectPropertyToAttribute(name);
|
| + }
|
| + },
|
| observeArrayValue: function(name, value, old) {
|
| // we only care if there are registered side-effects
|
| var callbackName = this.observe[name];
|
| @@ -721,8 +4297,11 @@ if (typeof window.Polymer === 'function') {
|
| }
|
| }
|
| },
|
| - bindProperty: function(property, observable) {
|
| - // apply Polymer two-way reference binding
|
| + bindProperty: function(property, observable, oneTime) {
|
| + if (oneTime) {
|
| + this[property] = observable;
|
| + return;
|
| + }
|
| return bindProperties(this, property, observable);
|
| },
|
| invokeMethod: function(method, args) {
|
| @@ -732,10 +4311,14 @@ if (typeof window.Polymer === 'function') {
|
| }
|
| },
|
| registerObservers: function(observers) {
|
| + this._observers = this._observers || [];
|
| this._observers.push(observers);
|
| },
|
| // observer array items are arrays of observers.
|
| closeObservers: function() {
|
| + if (!this._observers) {
|
| + return;
|
| + }
|
| for (var i=0, l=this._observers.length; i<l; i++) {
|
| this.closeObserverArray(this._observers[i]);
|
| }
|
| @@ -764,10 +4347,8 @@ if (typeof window.Polymer === 'function') {
|
| },
|
| closeNamedObservers: function() {
|
| if (this._namedObservers) {
|
| - var keys=Object.keys(this._namedObservers);
|
| - for (var i=0, l=keys.length, k, o; (i < l) && (k=keys[i]); i++) {
|
| - o = this._namedObservers[k];
|
| - o.close();
|
| + for (var i in this._namedObservers) {
|
| + this.closeNamedObserver(i);
|
| }
|
| this._namedObservers = {};
|
| }
|
| @@ -777,23 +4358,24 @@ if (typeof window.Polymer === 'function') {
|
| // property binding
|
| // bind a property in A to a path in B by converting A[property] to a
|
| // getter/setter pair that accesses B[...path...]
|
| - function bindProperties(inA, inProperty, observable) {
|
| - log.bind && console.log(LOG_BIND_PROPS, inB.localName || 'object', inPath, inA.localName, inProperty);
|
| - // capture A's value if B's value is null or undefined,
|
| - // otherwise use B's value
|
| - // TODO(sorvell): need to review, can do with ObserverTransform
|
| - var v = observable.discardChanges();
|
| - if (v === null || v === undefined) {
|
| - observable.setValue(inA[inProperty]);
|
| - }
|
| - return Observer.defineComputedProperty(inA, inProperty, observable);
|
| + function bindProperties(a, property, observable) {
|
| + // apply Polymer two-way reference binding
|
| + return Observer.bindToInstance(a, property, observable, resolveBindingValue);
|
| + }
|
| +
|
| + // capture A's value if B's value is null or undefined,
|
| + // otherwise use B's value
|
| + function resolveBindingValue(oldValue, value) {
|
| + if (value === undefined && oldValue === null) {
|
| + return value;
|
| + }
|
| + return (value === null || value === undefined) ? oldValue : value;
|
| }
|
|
|
| // logging
|
| var LOG_OBSERVE = '[%s] watching [%s]';
|
| var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]';
|
| var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]';
|
| - var LOG_BIND_PROPS = "[%s]: bindProperties: [%s] to [%s].[%s]";
|
|
|
| // exports
|
|
|
| @@ -802,47 +4384,27 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // imports
|
|
|
| var log = window.logFlags || 0;
|
| - var events = scope.api.instance.events;
|
| -
|
| - var syntax = new PolymerExpressions();
|
| - syntax.resolveEventHandler = function(model, path, node) {
|
| - var ctlr = findEventController(node);
|
| - if (ctlr) {
|
| - var fn = path.getValueFrom(ctlr);
|
| - if (fn) {
|
| - return fn.bind(ctlr);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // An event controller is the host element for the shadowRoot in which
|
| - // the node exists, or the first ancestor with a 'lightDomController'
|
| - // property.
|
| - function findEventController(node) {
|
| - while (node.parentNode) {
|
| - if (node.lightDomController) {
|
| - return node;
|
| - }
|
| - node = node.parentNode;
|
| - }
|
| - return node.host;
|
| - };
|
|
|
| // element api supporting mdv
|
| -
|
| var mdv = {
|
| - syntax: syntax,
|
| instanceTemplate: function(template) {
|
| - var dom = template.createInstance(this, this.syntax);
|
| + // ensure a default bindingDelegate
|
| + var syntax = this.syntax || (!template.bindingDelegate &&
|
| + this.element.syntax);
|
| + var dom = template.createInstance(this, syntax);
|
| this.registerObservers(dom.bindings_);
|
| return dom;
|
| },
|
| @@ -854,18 +4416,26 @@ if (typeof window.Polymer === 'function') {
|
| return this.mixinSuper(arguments);
|
| } else {
|
| // use n-way Polymer binding
|
| - var observer = this.bindProperty(property, observable);
|
| - this.reflectPropertyToAttribute(property);
|
| + var observer = this.bindProperty(property, observable, oneTime);
|
| // NOTE: reflecting binding information is typically required only for
|
| // tooling. It has a performance cost so it's opt-in in Node.bind.
|
| - if (Platform.enableBindingsReflection) {
|
| + if (Platform.enableBindingsReflection && observer) {
|
| observer.path = observable.path_;
|
| - this.bindings_ = this.bindings_ || {};
|
| - this.bindings_[name] = observer;
|
| + this._recordBinding(property, observer);
|
| + }
|
| + if (this.reflect[property]) {
|
| + this.reflectPropertyToAttribute(property);
|
| }
|
| return observer;
|
| }
|
| },
|
| + bindFinished: function() {
|
| + this.makeElementReady();
|
| + },
|
| + _recordBinding: function(name, observer) {
|
| + this.bindings_ = this.bindings_ || {};
|
| + this.bindings_[name] = observer;
|
| + },
|
| // TODO(sorvell): unbind/unbindAll has been removed, as public api, from
|
| // TemplateBinding. We still need to close/dispose of observers but perhaps
|
| // we should choose a more explicit name.
|
| @@ -921,10 +4491,14 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| var base = {
|
| @@ -953,22 +4527,39 @@ if (typeof window.Polymer === 'function') {
|
| }
|
| this.created();
|
| this.prepareElement();
|
| + // TODO(sorvell): replace when ShadowDOMPolyfill issue is corrected
|
| + // https://github.com/Polymer/ShadowDOM/issues/420
|
| + if (!this.ownerDocument.isStagingDocument || window.ShadowDOMPolyfill) {
|
| + this.makeElementReady();
|
| + }
|
| },
|
| // system entry point, do not override
|
| prepareElement: function() {
|
| + if (this._elementPrepared) {
|
| + console.warn('Element already prepared', this.localName);
|
| + return;
|
| + }
|
| this._elementPrepared = true;
|
| - // install shadowRoots storage
|
| + // storage for shadowRoots info
|
| this.shadowRoots = {};
|
| - // storage for closeable observers.
|
| - this._observers = [];
|
| // install property observers
|
| - this.observeProperties();
|
| + this.createPropertyObserver();
|
| + // TODO (sorvell): temporarily open observer when created
|
| + this.openPropertyObserver();
|
| // install boilerplate attributes
|
| this.copyInstanceAttributes();
|
| // process input attributes
|
| this.takeAttributes();
|
| // add event listeners
|
| this.addHostListeners();
|
| + },
|
| + makeElementReady: function() {
|
| + if (this._readied) {
|
| + return;
|
| + }
|
| + this._readied = true;
|
| + // TODO(sorvell): We could create an entry point here
|
| + // for the user to compute property values.
|
| // process declarative resources
|
| this.parseDeclarations(this.__proto__);
|
| // TODO(sorvell): CE polyfill uses unresolved attribute to simulate
|
| @@ -977,6 +4568,9 @@ if (typeof window.Polymer === 'function') {
|
| this.removeAttribute('unresolved');
|
| // user entry point
|
| this.ready();
|
| + // TODO (sorvell): temporarily open observer when created
|
| + // turn on property observation and take any initial changes
|
| + //this.openPropertyObserver();
|
| },
|
| attachedCallback: function() {
|
| this.cancelUnbindAll();
|
| @@ -1068,11 +4662,11 @@ if (typeof window.Polymer === 'function') {
|
| // utility function that stamps a <template> into light-dom
|
| lightFromTemplate: function(template, refNode) {
|
| if (template) {
|
| - // TODO(sorvell): mark this element as a lightDOMController so that
|
| + // TODO(sorvell): mark this element as an eventController so that
|
| // event listeners on bound nodes inside it will be called on it.
|
| // Note, the expectation here is that events on all descendants
|
| // should be handled by this element.
|
| - this.lightDomController = true;
|
| + this.eventController = this;
|
| // stamp template
|
| // which includes parsing and applying MDV bindings before being
|
| // inserted (to avoid {{}} in attribute values)
|
| @@ -1093,8 +4687,8 @@ if (typeof window.Polymer === 'function') {
|
| shadowRootReady: function(root) {
|
| // locate nodes with id and store references to them in this.$ hash
|
| this.marshalNodeReferences(root);
|
| - // set up pointer gestures
|
| - PointerGestures.register(root);
|
| + // set up polymer gestures
|
| + PolymerGestures.register(root);
|
| },
|
| // locate nodes with id and store references to them in this.$ hash
|
| marshalNodeReferences: function(root) {
|
| @@ -1146,10 +4740,14 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // imports
|
| @@ -1249,10 +4847,14 @@ if (typeof window.Polymer === 'function') {
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // imports
|
| @@ -1348,10 +4950,13 @@ if (typeof window.Polymer === 'function') {
|
|
|
| })(Polymer);
|
|
|
| -/*
|
| - * 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.
|
| +/*
|
| + * 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(scope) {
|
| @@ -1377,10 +4982,14 @@ scope.api.declaration.path = path;
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // imports
|
| @@ -1400,14 +5009,17 @@ scope.api.declaration.path = path;
|
| var styles = {
|
| // returns true if resources are loading
|
| loadStyles: function(callback) {
|
| - var content = this.templateContent();
|
| + var template = this.fetchTemplate();
|
| + var content = template && this.templateContent();
|
| if (content) {
|
| this.convertSheetsToStyles(content);
|
| + var styles = this.findLoadableStyles(content);
|
| + if (styles.length) {
|
| + var templateUrl = template.ownerDocument.baseURI;
|
| + return Platform.styleResolver.loadStyles(styles, templateUrl, callback);
|
| + }
|
| }
|
| - var styles = this.findLoadableStyles(content);
|
| - if (styles.length) {
|
| - Platform.styleResolver.loadStyles(styles, callback);
|
| - } else if (callback) {
|
| + if (callback) {
|
| callback();
|
| }
|
| },
|
| @@ -1503,10 +5115,6 @@ scope.api.declaration.path = path;
|
| }
|
| return matcher ? nodes.filter(matcher) : nodes;
|
| },
|
| - templateContent: function() {
|
| - var template = this.querySelector('template');
|
| - return template && templateContent(template);
|
| - },
|
| /**
|
| * Promotes external stylesheets and <style> elements with the attribute
|
| * polymer-scope='global' into global scope.
|
| @@ -1618,9 +5226,12 @@ scope.api.declaration.path = path;
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
| @@ -1632,7 +5243,19 @@ scope.api.declaration.path = path;
|
| var EVENT_PREFIX = api.EVENT_PREFIX;
|
| // polymer-element declarative api: events feature
|
|
|
| - var events = {
|
| + var mixedCaseEventTypes = {};
|
| + [
|
| + 'webkitAnimationStart',
|
| + 'webkitAnimationEnd',
|
| + 'webkitTransitionEnd',
|
| + 'DOMFocusOut',
|
| + 'DOMFocusIn',
|
| + 'DOMMouseScroll'
|
| + ].forEach(function(e) {
|
| + mixedCaseEventTypes[e.toLowerCase()] = e;
|
| + });
|
| +
|
| + var events = {
|
| parseHostEvents: function() {
|
| // our delegates map
|
| var delegates = this.prototype.eventDelegates;
|
| @@ -1656,6 +5279,59 @@ scope.api.declaration.path = path;
|
| },
|
| removeEventPrefix: function(n) {
|
| return n.slice(prefixLength);
|
| + },
|
| + findController: function(node) {
|
| + while (node.parentNode) {
|
| + if (node.eventController) {
|
| + return node.eventController;
|
| + }
|
| + node = node.parentNode;
|
| + }
|
| + return node.host;
|
| + },
|
| + getEventHandler: function(controller, target, method) {
|
| + var events = this;
|
| + return function(e) {
|
| + if (!controller || !controller.PolymerBase) {
|
| + controller = events.findController(target);
|
| + }
|
| +
|
| + var args = [e, e.detail, e.currentTarget];
|
| + controller.dispatchMethod(controller, method, args);
|
| + };
|
| + },
|
| + prepareEventBinding: function(pathString, name, node) {
|
| + if (!this.hasEventPrefix(name))
|
| + return;
|
| +
|
| + var eventType = this.removeEventPrefix(name);
|
| + eventType = mixedCaseEventTypes[eventType] || eventType;
|
| +
|
| + var events = this;
|
| +
|
| + return function(model, node, oneTime) {
|
| + var handler = events.getEventHandler(undefined, node, pathString);
|
| + node.addEventListener(eventType, handler);
|
| +
|
| + if (oneTime)
|
| + return;
|
| +
|
| + // TODO(rafaelw): This is really pointless work. Aside from the cost
|
| + // of these allocations, NodeBind is going to setAttribute back to its
|
| + // current value. Fixing this would mean changing the TemplateBinding
|
| + // binding delegate API.
|
| + function bindingValue() {
|
| + return '{{ ' + pathString + ' }}';
|
| + }
|
| +
|
| + return {
|
| + open: bindingValue,
|
| + discardChanges: bindingValue,
|
| + close: function() {
|
| + node.removeEventListener(eventType, handler);
|
| + }
|
| + };
|
| + };
|
| }
|
| };
|
|
|
| @@ -1665,99 +5341,141 @@ scope.api.declaration.path = path;
|
| scope.api.declaration.events = events;
|
|
|
| })(Polymer);
|
| -/*
|
| - * 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) {
|
| -
|
| - // element api
|
| -
|
| - var properties = {
|
| - inferObservers: function(prototype) {
|
| - // called before prototype.observe is chained to inherited object
|
| - var observe = prototype.observe, property;
|
| - for (var n in prototype) {
|
| - if (n.slice(-7) === 'Changed') {
|
| - if (!observe) {
|
| - observe = (prototype.observe = {});
|
| - }
|
| - property = n.slice(0, -7)
|
| - observe[property] = observe[property] || n;
|
| - }
|
| - }
|
| - },
|
| - explodeObservers: function(prototype) {
|
| - // called before prototype.observe is chained to inherited object
|
| - var o = prototype.observe;
|
| - if (o) {
|
| - var exploded = {};
|
| - for (var n in o) {
|
| - var names = n.split(' ');
|
| - for (var i=0, ni; ni=names[i]; i++) {
|
| - exploded[ni] = o[n];
|
| - }
|
| - }
|
| - prototype.observe = exploded;
|
| - }
|
| - },
|
| - optimizePropertyMaps: function(prototype) {
|
| - if (prototype.observe) {
|
| - // construct name list
|
| - var a = prototype._observeNames = [];
|
| - for (var n in prototype.observe) {
|
| - var names = n.split(' ');
|
| - for (var i=0, ni; ni=names[i]; i++) {
|
| - a.push(ni);
|
| - }
|
| - }
|
| - }
|
| - if (prototype.publish) {
|
| - // construct name list
|
| - var a = prototype._publishNames = [];
|
| - for (var n in prototype.publish) {
|
| - a.push(n);
|
| - }
|
| - }
|
| - },
|
| - publishProperties: function(prototype, base) {
|
| - // if we have any properties to publish
|
| - var publish = prototype.publish;
|
| - if (publish) {
|
| - // transcribe `publish` entries onto own prototype
|
| - this.requireProperties(publish, prototype, base);
|
| - // construct map of lower-cased property names
|
| - prototype._publishLC = this.lowerCaseMap(publish);
|
| - }
|
| - },
|
| - requireProperties: function(properties, prototype, base) {
|
| - // ensure a prototype value for each property
|
| - for (var n in properties) {
|
| - if (prototype[n] === undefined && base[n] === undefined) {
|
| - prototype[n] = properties[n];
|
| - }
|
| - }
|
| - },
|
| - lowerCaseMap: function(properties) {
|
| - var map = {};
|
| - for (var n in properties) {
|
| - map[n.toLowerCase()] = n;
|
| - }
|
| - return map;
|
| - }
|
| - };
|
| -
|
| - // exports
|
| -
|
| - scope.api.declaration.properties = properties;
|
| -
|
| -})(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
| +
|
| + // element api
|
| +
|
| + var properties = {
|
| + inferObservers: function(prototype) {
|
| + // called before prototype.observe is chained to inherited object
|
| + var observe = prototype.observe, property;
|
| + for (var n in prototype) {
|
| + if (n.slice(-7) === 'Changed') {
|
| + if (!observe) {
|
| + observe = (prototype.observe = {});
|
| + }
|
| + property = n.slice(0, -7)
|
| + observe[property] = observe[property] || n;
|
| + }
|
| + }
|
| + },
|
| + explodeObservers: function(prototype) {
|
| + // called before prototype.observe is chained to inherited object
|
| + var o = prototype.observe;
|
| + if (o) {
|
| + var exploded = {};
|
| + for (var n in o) {
|
| + var names = n.split(' ');
|
| + for (var i=0, ni; ni=names[i]; i++) {
|
| + exploded[ni] = o[n];
|
| + }
|
| + }
|
| + prototype.observe = exploded;
|
| + }
|
| + },
|
| + optimizePropertyMaps: function(prototype) {
|
| + if (prototype.observe) {
|
| + // construct name list
|
| + var a = prototype._observeNames = [];
|
| + for (var n in prototype.observe) {
|
| + var names = n.split(' ');
|
| + for (var i=0, ni; ni=names[i]; i++) {
|
| + a.push(ni);
|
| + }
|
| + }
|
| + }
|
| + if (prototype.publish) {
|
| + // construct name list
|
| + var a = prototype._publishNames = [];
|
| + for (var n in prototype.publish) {
|
| + a.push(n);
|
| + }
|
| + }
|
| + },
|
| + publishProperties: function(prototype, base) {
|
| + // if we have any properties to publish
|
| + var publish = prototype.publish;
|
| + if (publish) {
|
| + // transcribe `publish` entries onto own prototype
|
| + this.requireProperties(publish, prototype, base);
|
| + // construct map of lower-cased property names
|
| + prototype._publishLC = this.lowerCaseMap(publish);
|
| + }
|
| + },
|
| + // sync prototype to property descriptors;
|
| + // desriptor format contains default value and optionally a
|
| + // hint for reflecting the property to an attribute.
|
| + // e.g. {foo: 5, bar: {value: true, reflect: true}}
|
| + // reflect: {foo: true} is also supported
|
| + //
|
| + requireProperties: function(propertyDescriptors, prototype, base) {
|
| + // reflected properties
|
| + prototype.reflect = prototype.reflect || {};
|
| + // ensure a prototype value for each property
|
| + // and update the property's reflect to attribute status
|
| + for (var n in propertyDescriptors) {
|
| + var propertyDescriptor = propertyDescriptors[n];
|
| + var reflects = this.reflectHintForDescriptor(propertyDescriptor);
|
| + if (prototype.reflect[n] === undefined && reflects !== undefined) {
|
| + prototype.reflect[n] = reflects;
|
| + }
|
| + if (prototype[n] === undefined) {
|
| + prototype[n] = this.valueForDescriptor(propertyDescriptor);
|
| + }
|
| + }
|
| + },
|
| + valueForDescriptor: function(propertyDescriptor) {
|
| + var value = typeof propertyDescriptor === 'object' &&
|
| + propertyDescriptor ? propertyDescriptor.value : propertyDescriptor;
|
| + return value !== undefined ? value : null;
|
| + },
|
| + // returns the value of the descriptor's 'reflect' property or undefined
|
| + reflectHintForDescriptor: function(propertyDescriptor) {
|
| + if (typeof propertyDescriptor === 'object' &&
|
| + propertyDescriptor && propertyDescriptor.reflect !== undefined) {
|
| + return propertyDescriptor.reflect;
|
| + }
|
| + },
|
| + lowerCaseMap: function(properties) {
|
| + var map = {};
|
| + for (var n in properties) {
|
| + map[n.toLowerCase()] = n;
|
| + }
|
| + return map;
|
| + },
|
| + createPropertyAccessors: function(prototype) {
|
| + var n$ = prototype._publishNames;
|
| + if (n$ && n$.length) {
|
| + for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) {
|
| + Observer.createBindablePrototypeAccessor(prototype, n);
|
| + }
|
| + }
|
| + }
|
| + };
|
| +
|
| + // exports
|
| +
|
| + scope.api.declaration.properties = properties;
|
| +
|
| +})(Polymer);
|
| +
|
| +/*
|
| + * 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(scope) {
|
|
|
| @@ -1769,12 +5487,14 @@ scope.api.declaration.path = path;
|
| // attributes api
|
|
|
| var attributes = {
|
| +
|
| inheritAttributesObjects: function(prototype) {
|
| // chain our lower-cased publish map to the inherited version
|
| this.inheritObject(prototype, 'publishLC');
|
| // chain our instance attributes map to the inherited version
|
| this.inheritObject(prototype, '_instanceAttributes');
|
| },
|
| +
|
| publishAttributes: function(prototype, base) {
|
| // merge names from 'attributes' attribute
|
| var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE);
|
| @@ -1789,11 +5509,14 @@ scope.api.declaration.path = path;
|
| n = names[i].trim();
|
| // do not override explicit entries
|
| if (n && publish[n] === undefined && base[n] === undefined) {
|
| - publish[n] = null;
|
| + // supply an empty 'descriptor' object and let the publishProperties
|
| + // code determine a default
|
| + publish[n] = Polymer.nob;
|
| }
|
| }
|
| }
|
| },
|
| +
|
| // record clonable attributes from <element>
|
| accumulateInstanceAttributes: function() {
|
| // inherit instance attributes
|
| @@ -1806,9 +5529,11 @@ scope.api.declaration.path = path;
|
| }
|
| }
|
| },
|
| +
|
| isInstanceAttribute: function(name) {
|
| return !this.blackList[name] && name.slice(0,3) !== 'on-';
|
| },
|
| +
|
| // do not clone these attributes onto instances
|
| blackList: {
|
| name: 1,
|
| @@ -1818,6 +5543,7 @@ scope.api.declaration.path = path;
|
| assetpath: 1,
|
| 'cache-csstext': 1
|
| }
|
| +
|
| };
|
|
|
| // add ATTRIBUTES_ATTRIBUTE to the blacklist
|
| @@ -1830,10 +5556,60 @@ scope.api.declaration.path = path;
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
| +
|
| + // imports
|
| + var events = scope.api.declaration.events;
|
| +
|
| + var syntax = new PolymerExpressions();
|
| + var prepareBinding = syntax.prepareBinding;
|
| +
|
| + // Polymer takes a first crack at the binding to see if it's a declarative
|
| + // event handler.
|
| + syntax.prepareBinding = function(pathString, name, node) {
|
| + return events.prepareEventBinding(pathString, name, node) ||
|
| + prepareBinding.call(syntax, pathString, name, node);
|
| + };
|
| +
|
| + // declaration api supporting mdv
|
| + var mdv = {
|
| + syntax: syntax,
|
| + fetchTemplate: function() {
|
| + return this.querySelector('template');
|
| + },
|
| + templateContent: function() {
|
| + var template = this.fetchTemplate();
|
| + return template && Platform.templateContent(template);
|
| + },
|
| + installBindingDelegate: function(template) {
|
| + if (template) {
|
| + template.bindingDelegate = this.syntax;
|
| + }
|
| + }
|
| + };
|
| +
|
| + // exports
|
| + scope.api.declaration.mdv = mdv;
|
| +
|
| +})(Polymer);
|
| +
|
| +/*
|
| + * 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(scope) {
|
|
|
| // imports
|
| @@ -1897,6 +5673,8 @@ scope.api.declaration.path = path;
|
| this.inheritObject('observe', prototype, base);
|
| // chain publish object to inherited
|
| this.inheritObject('publish', prototype, base);
|
| + // chain reflect object to inherited
|
| + this.inheritObject('reflect', prototype, base);
|
| // chain our lower-cased publish map to the inherited version
|
| this.inheritObject('_publishLC', prototype, base);
|
| // chain our instance attributes map to the inherited version
|
| @@ -1909,6 +5687,9 @@ scope.api.declaration.path = path;
|
| desugarAfterChaining: function(name, extendee) {
|
| // build side-chained lists to optimize iterations
|
| this.optimizePropertyMaps(this.prototype);
|
| + this.createPropertyAccessors(this.prototype);
|
| + // install mdv delegate on template
|
| + this.installBindingDelegate(this.fetchTemplate());
|
| // install external stylesheets as if they are inline
|
| this.installSheets();
|
| // adjust any paths in dom from imports
|
| @@ -2074,16 +5855,43 @@ scope.api.declaration.path = path;
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| + /*
|
| +
|
| + Elements are added to a registration queue so that they register in
|
| + the proper order at the appropriate time. We do this for a few reasons:
|
| +
|
| + * to enable elements to load resources (like stylesheets)
|
| + asynchronously. We need to do this until the platform provides an efficient
|
| + alternative. One issue is that remote @import stylesheets are
|
| + re-fetched whenever stamped into a shadowRoot.
|
| +
|
| + * to ensure elements loaded 'at the same time' (e.g. via some set of
|
| + imports) are registered as a batch. This allows elements to be enured from
|
| + upgrade ordering as long as they query the dom tree 1 task after
|
| + upgrade (aka domReady). This is a performance tradeoff. On the one hand,
|
| + elements that could register while imports are loading are prevented from
|
| + doing so. On the other, grouping upgrades into a single task means less
|
| + incremental work (for example style recalcs), Also, we can ensure the
|
| + document is in a known state at the single quantum of time when
|
| + elements upgrade.
|
| +
|
| + */
|
| var queue = {
|
| // tell the queue to wait for an element to be ready
|
| wait: function(element, check, go) {
|
| - if (this.indexOf(element) === -1) {
|
| + var shouldAdd = (this.indexOf(element) === -1 &&
|
| + flushQueue.indexOf(element) === -1);
|
| + if (shouldAdd) {
|
| this.add(element);
|
| element.__check = check;
|
| element.__go = go;
|
| @@ -2106,8 +5914,7 @@ scope.api.declaration.path = path;
|
| go: function(element) {
|
| var readied = this.remove(element);
|
| if (readied) {
|
| - readied.__go.call(readied);
|
| - readied.__check = readied.__go = null;
|
| + this.addToFlushQueue(readied);
|
| this.check();
|
| }
|
| },
|
| @@ -2139,7 +5946,19 @@ scope.api.declaration.path = path;
|
| isEmpty: function() {
|
| return !importQueue.length && !mainQueue.length;
|
| },
|
| + addToFlushQueue: function(element) {
|
| + flushQueue.push(element);
|
| + },
|
| + flush: function() {
|
| + var element;
|
| + while (flushQueue.length) {
|
| + element = flushQueue.shift();
|
| + element.__go.call(element);
|
| + element.__check = element.__go = null;
|
| + }
|
| + },
|
| ready: function() {
|
| + this.flush();
|
| // TODO(sorvell): As an optimization, turn off CE polyfill upgrading
|
| // while registering. This way we avoid having to upgrade each document
|
| // piecemeal per registration and can instead register all elements
|
| @@ -2150,6 +5969,15 @@ scope.api.declaration.path = path;
|
| CustomElements.upgradeDocumentTree(document);
|
| CustomElements.ready = true;
|
| }
|
| + Platform.flush();
|
| + requestAnimationFrame(this.flushReadyCallbacks);
|
| + },
|
| + addReadyCallback: function(callback) {
|
| + if (callback) {
|
| + readyCallbacks.push(callback);
|
| + }
|
| + },
|
| + flushReadyCallbacks: function() {
|
| if (readyCallbacks) {
|
| var fn;
|
| while (readyCallbacks.length) {
|
| @@ -2158,14 +5986,11 @@ scope.api.declaration.path = path;
|
| }
|
| }
|
| },
|
| - addReadyCallback: function(callback) {
|
| - if (callback) {
|
| - readyCallbacks.push(callback);
|
| - }
|
| - },
|
| waitToReady: true
|
| };
|
|
|
| + var flushQueue = [];
|
| +
|
| var importQueue = [];
|
| var mainQueue = [];
|
| var readyCallbacks = [];
|
| @@ -2200,10 +6025,14 @@ scope.api.declaration.path = path;
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| var whenPolymerReady = scope.whenPolymerReady;
|
| @@ -2239,10 +6068,14 @@ scope.api.declaration.path = path;
|
| })(Polymer);
|
|
|
| /*
|
| - * 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.
|
| + * 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(scope) {
|
|
|
| // imports
|
| @@ -2370,10 +6203,6 @@ scope.api.declaration.path = path;
|
| return (name && name.indexOf('-') >= 0);
|
| }
|
|
|
| - // exports
|
| -
|
| - scope.getRegisteredPrototype = getRegisteredPrototype;
|
| -
|
| // boot tasks
|
|
|
| whenPolymerReady(function() {
|
| @@ -2389,4 +6218,90 @@ scope.api.declaration.path = path;
|
|
|
| })(Polymer);
|
|
|
| +/*
|
| + * 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
|
| + */
|
| +
|
| +/**
|
| + * The `auto-binding` element extends the template element. It provides a quick
|
| + * and easy way to do data binding without the need to setup a model.
|
| + * The `auto-binding` element itself serves as the model and controller for the
|
| + * elements it contains. Both data and event handlers can be bound.
|
| + *
|
| + * The `auto-binding` element acts just like a template that is bound to
|
| + * a model. It stamps its content in the dom adjacent to itself. When the
|
| + * content is stamped, the `template-bound` event is fired.
|
| + *
|
| + * Example:
|
| + *
|
| + * <template is="auto-binding">
|
| + * <div>Say something: <input value="{{value}}"></div>
|
| + * <div>You said: {{value}}</div>
|
| + * <button on-tap="{{buttonTap}}">Tap me!</button>
|
| + * </template>
|
| + * <script>
|
| + * var template = document.querySelector('template');
|
| + * template.value = 'something';
|
| + * template.buttonTap = function() {
|
| + * console.log('tap!');
|
| + * };
|
| + * </script>
|
| + *
|
| + * @module Polymer
|
| + * @status stable
|
| +*/
|
| +
|
| +(function() {
|
| +
|
| + var element = document.createElement('polymer-element');
|
| + element.setAttribute('name', 'auto-binding');
|
| + element.setAttribute('extends', 'template');
|
| + element.init();
|
| +
|
| + Polymer('auto-binding', {
|
| +
|
| + createdCallback: function() {
|
| + this.syntax = this.bindingDelegate = this.makeSyntax();
|
| + // delay stamping until polymer-ready so that auto-binding is not
|
| + // required to load last.
|
| + Polymer.whenPolymerReady(function() {
|
| + this.model = this;
|
| + this.setAttribute('bind', '');
|
| + // we don't bother with an explicit signal here, we could ust a MO
|
| + // if necessary
|
| + this.async(function() {
|
| + // note: this will marshall *all* the elements in the parentNode
|
| + // rather than just stamped ones. We'd need to use createInstance
|
| + // to fix this or something else fancier.
|
| + this.marshalNodeReferences(this.parentNode);
|
| + // template stamping is asynchronous so stamping isn't complete
|
| + // by polymer-ready; fire an event so users can use stamped elements
|
| + this.fire('template-bound');
|
| + });
|
| + }.bind(this));
|
| + },
|
| +
|
| + makeSyntax: function() {
|
| + var events = Object.create(Polymer.api.declaration.events);
|
| + var self = this;
|
| + events.findController = function() { return self.model; };
|
| +
|
| + var syntax = new PolymerExpressions();
|
| + var prepareBinding = syntax.prepareBinding;
|
| + syntax.prepareBinding = function(pathString, name, node) {
|
| + return events.prepareEventBinding(pathString, name, node) ||
|
| + prepareBinding.call(syntax, pathString, name, node);
|
| + };
|
| + return syntax;
|
| + }
|
| +
|
| + });
|
| +
|
| +})();
|
| +
|
| //# sourceMappingURL=polymer.concat.js.map
|
|
|