Index: dart/pkg/polymer/lib/src/js/polymer/polymer.concat.js |
=================================================================== |
--- dart/pkg/polymer/lib/src/js/polymer/polymer.concat.js (revision 37358) |
+++ dart/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 |