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

Unified Diff: pkg/polymer/lib/src/js/polymer/polymer.concat.js

Issue 335943003: merge to trunk all changes from 36817 until 37378 under the packages: polymer, (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/polymer/lib/src/js/polymer/polymer.concat.js
===================================================================
--- pkg/polymer/lib/src/js/polymer/polymer.concat.js (revision 37373)
+++ pkg/polymer/lib/src/js/polymer/polymer.concat.js (working copy)
@@ -1,16 +1,3551 @@
+/**
+ * @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 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 = {};
+(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 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() {
+ 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 (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 = {
+ version: '0.3.1-604ba08'
+};
+
+/*
+ * 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
// Platform is currently defining it as a function to allow for async loading
// of polymer; once we refine the loading process this likely goes away.
@@ -20,10 +3555,14 @@
/*
- * 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 @@
})(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 @@
})(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,135 +3701,149 @@
*/
})(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) {
- // 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 2013 The Polymer Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file.
- */
-
(function(scope) {
var typeHandlers = {
@@ -348,9 +3908,12 @@
})(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 @@
for (var n in apis) {
extend(prototype, apis[n]);
}
- }
+ };
// exports
@@ -378,10 +3941,14 @@
})(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 @@
})(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 @@
// (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 @@
})(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 @@
})(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,48 +4223,60 @@
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);
- }
+ this.observeArrayValue(n, this[n], 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);
- }
- }
- o.open(this.notifyPropertyChanges, this);
}
},
+ openPropertyObserver: function() {
+ if (this._propertyObserver) {
+ this._propertyObserver.open(this.notifyPropertyChanges, this);
+ }
+ },
notifyPropertyChanges: function(newValues, oldValues, paths) {
var name, method, called = {};
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 @@
}
}
},
- 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 @@
}
},
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 @@
},
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 @@
// 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]);
+ 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 Observer.defineComputedProperty(inA, inProperty, observable);
+ 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 @@
})(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 @@
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 @@
})(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 @@
}
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 @@
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 @@
// 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 @@
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 @@
})(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 @@
})(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 @@
})(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 @@
})(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 @@
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 @@
}
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 @@
})(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 @@
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 @@
},
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,102 +5341,144 @@
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) {
+
// magic words
var ATTRIBUTES_ATTRIBUTE = 'attributes';
@@ -1769,12 +5487,14 @@
// 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 @@
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 @@
}
}
},
+
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 @@
assetpath: 1,
'cache-csstext': 1
}
+
};
// add ATTRIBUTES_ATTRIBUTE to the blacklist
@@ -1830,13 +5556,63 @@
})(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
var api = scope.api;
var isBase = scope.isBase;
@@ -1897,6 +5673,8 @@
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 @@
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 @@
})(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 @@
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 @@
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 @@
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 @@
}
}
},
- addReadyCallback: function(callback) {
- if (callback) {
- readyCallbacks.push(callback);
- }
- },
waitToReady: true
};
+ var flushQueue = [];
+
var importQueue = [];
var mainQueue = [];
var readyCallbacks = [];
@@ -2200,10 +6025,14 @@
})(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 @@
})(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 @@
return (name && name.indexOf('-') >= 0);
}
- // exports
-
- scope.getRegisteredPrototype = getRegisteredPrototype;
-
// boot tasks
whenPolymerReady(function() {
@@ -2389,4 +6218,90 @@
})(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
« no previous file with comments | « pkg/polymer/lib/src/js/polymer/polymer-body.html ('k') | pkg/polymer/lib/src/js/polymer/polymer.concat.js.map » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698