OLD | NEW |
| 1 /** |
| 2 * @license |
| 3 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 4 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 5 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 6 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 7 * Code distributed by Google as part of the polymer project is also |
| 8 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 9 */ |
| 10 window.PolymerGestures = {}; |
| 11 |
1 /* | 12 /* |
2 * Copyright 2013 The Polymer Authors. All rights reserved. | 13 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style | 14 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
4 * license that can be found in the LICENSE file. | 15 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
5 */ | 16 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
6 Polymer = {}; | 17 * Code distributed by Google as part of the polymer project is also |
| 18 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 19 */ |
| 20 |
| 21 (function(scope) { |
| 22 var target = { |
| 23 shadow: function(inEl) { |
| 24 if (inEl) { |
| 25 return inEl.shadowRoot || inEl.webkitShadowRoot; |
| 26 } |
| 27 }, |
| 28 canTarget: function(shadow) { |
| 29 return shadow && Boolean(shadow.elementFromPoint); |
| 30 }, |
| 31 targetingShadow: function(inEl) { |
| 32 var s = this.shadow(inEl); |
| 33 if (this.canTarget(s)) { |
| 34 return s; |
| 35 } |
| 36 }, |
| 37 olderShadow: function(shadow) { |
| 38 var os = shadow.olderShadowRoot; |
| 39 if (!os) { |
| 40 var se = shadow.querySelector('shadow'); |
| 41 if (se) { |
| 42 os = se.olderShadowRoot; |
| 43 } |
| 44 } |
| 45 return os; |
| 46 }, |
| 47 allShadows: function(element) { |
| 48 var shadows = [], s = this.shadow(element); |
| 49 while(s) { |
| 50 shadows.push(s); |
| 51 s = this.olderShadow(s); |
| 52 } |
| 53 return shadows; |
| 54 }, |
| 55 searchRoot: function(inRoot, x, y) { |
| 56 if (inRoot) { |
| 57 var t = inRoot.elementFromPoint(x, y); |
| 58 var st, sr, os; |
| 59 // is element a shadow host? |
| 60 sr = this.targetingShadow(t); |
| 61 while (sr) { |
| 62 // find the the element inside the shadow root |
| 63 st = sr.elementFromPoint(x, y); |
| 64 if (!st) { |
| 65 // check for older shadows |
| 66 sr = this.olderShadow(sr); |
| 67 } else { |
| 68 // shadowed element may contain a shadow root |
| 69 var ssr = this.targetingShadow(st); |
| 70 return this.searchRoot(ssr, x, y) || st; |
| 71 } |
| 72 } |
| 73 // light dom element is the target |
| 74 return t; |
| 75 } |
| 76 }, |
| 77 owner: function(element) { |
| 78 if (!element) { |
| 79 return document; |
| 80 } |
| 81 var s = element; |
| 82 // walk up until you hit the shadow root or document |
| 83 while (s.parentNode) { |
| 84 s = s.parentNode; |
| 85 } |
| 86 // the owner element is expected to be a Document or ShadowRoot |
| 87 if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGME
NT_NODE) { |
| 88 s = document; |
| 89 } |
| 90 return s; |
| 91 }, |
| 92 findTarget: function(inEvent) { |
| 93 var x = inEvent.clientX, y = inEvent.clientY; |
| 94 // if the listener is in the shadow root, it is much faster to start there |
| 95 var s = this.owner(inEvent.target); |
| 96 // if x, y is not in this root, fall back to document search |
| 97 if (!s.elementFromPoint(x, y)) { |
| 98 s = document; |
| 99 } |
| 100 return this.searchRoot(s, x, y); |
| 101 }, |
| 102 LCA: function(a, b) { |
| 103 if (a === b) { |
| 104 return a; |
| 105 } |
| 106 if (a && !b) { |
| 107 return a; |
| 108 } |
| 109 if (b && !a) { |
| 110 return b; |
| 111 } |
| 112 if (!b && !a) { |
| 113 return document; |
| 114 } |
| 115 // fast case, a is a direct descendant of b or vice versa |
| 116 if (a.contains && a.contains(b)) { |
| 117 return a; |
| 118 } |
| 119 if (b.contains && b.contains(a)) { |
| 120 return b; |
| 121 } |
| 122 var adepth = this.depth(a); |
| 123 var bdepth = this.depth(b); |
| 124 var d = adepth - bdepth; |
| 125 if (d > 0) { |
| 126 a = this.walk(a, d); |
| 127 } else { |
| 128 b = this.walk(b, -d); |
| 129 } |
| 130 while(a && b && a !== b) { |
| 131 a = this.walk(a, 1); |
| 132 b = this.walk(b, 1); |
| 133 } |
| 134 return a; |
| 135 }, |
| 136 walk: function(n, u) { |
| 137 for (var i = 0; n && (i < u); i++) { |
| 138 n = n.parentNode || n.host; |
| 139 } |
| 140 return n; |
| 141 }, |
| 142 depth: function(n) { |
| 143 var d = 0; |
| 144 while(n) { |
| 145 d++; |
| 146 n = n.parentNode || n.host; |
| 147 } |
| 148 return d; |
| 149 }, |
| 150 deepContains: function(a, b) { |
| 151 var common = this.LCA(a, b); |
| 152 // if a is the common ancestor, it must "deeply" contain b |
| 153 return common === a; |
| 154 }, |
| 155 insideNode: function(node, x, y) { |
| 156 var rect = node.getBoundingClientRect(); |
| 157 return (rect.left <= x) && (x <= rect.right) && (rect.top <= y) && (y <= r
ect.bottom); |
| 158 } |
| 159 }; |
| 160 scope.targetFinding = target; |
| 161 /** |
| 162 * Given an event, finds the "deepest" node that could have been the original
target before ShadowDOM retargetting |
| 163 * |
| 164 * @param {Event} Event An event object with clientX and clientY properties |
| 165 * @return {Element} The probable event origninator |
| 166 */ |
| 167 scope.findTarget = target.findTarget.bind(target); |
| 168 /** |
| 169 * Determines if the "container" node deeply contains the "containee" node, in
cluding situations where the "containee" is contained by one or more ShadowDOM |
| 170 * roots. |
| 171 * |
| 172 * @param {Node} container |
| 173 * @param {Node} containee |
| 174 * @return {Boolean} |
| 175 */ |
| 176 scope.deepContains = target.deepContains.bind(target); |
| 177 |
| 178 /** |
| 179 * Determines if the x/y position is inside the given node. |
| 180 * |
| 181 * Example: |
| 182 * |
| 183 * function upHandler(event) { |
| 184 * var innode = PolymerGestures.insideNode(event.target, event.clientX,
event.clientY); |
| 185 * if (innode) { |
| 186 * // wait for tap? |
| 187 * } else { |
| 188 * // tap will never happen |
| 189 * } |
| 190 * } |
| 191 * |
| 192 * @param {Node} node |
| 193 * @param {Number} x Screen X position |
| 194 * @param {Number} y screen Y position |
| 195 * @return {Boolean} |
| 196 */ |
| 197 scope.insideNode = target.insideNode; |
| 198 |
| 199 })(window.PolymerGestures); |
7 | 200 |
8 /* | 201 /* |
9 * Copyright 2013 The Polymer Authors. All rights reserved. | 202 * |
10 * Use of this source code is governed by a BSD-style | 203 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
11 * license that can be found in the LICENSE file. | 204 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 205 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 206 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 207 * Code distributed by Google as part of the polymer project is also |
| 208 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 209 */ |
| 210 |
| 211 (function() { |
| 212 function shadowSelector(v) { |
| 213 return 'body /deep/ ' + selector(v); |
| 214 } |
| 215 function selector(v) { |
| 216 return '[touch-action="' + v + '"]'; |
| 217 } |
| 218 function rule(v) { |
| 219 return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + ';}'; |
| 220 } |
| 221 var attrib2css = [ |
| 222 'none', |
| 223 'auto', |
| 224 'pan-x', |
| 225 'pan-y', |
| 226 { |
| 227 rule: 'pan-x pan-y', |
| 228 selectors: [ |
| 229 'pan-x pan-y', |
| 230 'pan-y pan-x' |
| 231 ] |
| 232 } |
| 233 ]; |
| 234 var styles = ''; |
| 235 // only install stylesheet if the browser has touch action support |
| 236 var head = document.head; |
| 237 var hasTouchAction = typeof document.head.style.touchAction === 'string'; |
| 238 // only add shadow selectors if shadowdom is supported |
| 239 var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoo
t; |
| 240 |
| 241 if (hasTouchAction) { |
| 242 attrib2css.forEach(function(r) { |
| 243 if (String(r) === r) { |
| 244 styles += selector(r) + rule(r) + '\n'; |
| 245 if (hasShadowRoot) { |
| 246 styles += shadowSelector(r) + rule(r) + '\n'; |
| 247 } |
| 248 } else { |
| 249 styles += r.selectors.map(selector) + rule(r.rule) + '\n'; |
| 250 if (hasShadowRoot) { |
| 251 styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n'; |
| 252 } |
| 253 } |
| 254 }); |
| 255 |
| 256 var el = document.createElement('style'); |
| 257 el.textContent = styles; |
| 258 document.head.appendChild(el); |
| 259 } |
| 260 })(); |
| 261 |
| 262 /* |
| 263 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 264 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 265 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 266 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 267 * Code distributed by Google as part of the polymer project is also |
| 268 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 269 */ |
| 270 |
| 271 /** |
| 272 * This is the constructor for new PointerEvents. |
| 273 * |
| 274 * New Pointer Events must be given a type, and an optional dictionary of |
| 275 * initialization properties. |
| 276 * |
| 277 * Due to certain platform requirements, events returned from the constructor |
| 278 * identify as MouseEvents. |
| 279 * |
| 280 * @constructor |
| 281 * @param {String} inType The type of the event to create. |
| 282 * @param {Object} [inDict] An optional dictionary of initial event properties. |
| 283 * @return {Event} A new PointerEvent of type `inType` and initialized with prop
erties from `inDict`. |
| 284 */ |
| 285 (function(scope) { |
| 286 |
| 287 var MOUSE_PROPS = [ |
| 288 'bubbles', |
| 289 'cancelable', |
| 290 'view', |
| 291 'detail', |
| 292 'screenX', |
| 293 'screenY', |
| 294 'clientX', |
| 295 'clientY', |
| 296 'ctrlKey', |
| 297 'altKey', |
| 298 'shiftKey', |
| 299 'metaKey', |
| 300 'button', |
| 301 'relatedTarget', |
| 302 'pageX', |
| 303 'pageY' |
| 304 ]; |
| 305 |
| 306 var MOUSE_DEFAULTS = [ |
| 307 false, |
| 308 false, |
| 309 null, |
| 310 null, |
| 311 0, |
| 312 0, |
| 313 0, |
| 314 0, |
| 315 false, |
| 316 false, |
| 317 false, |
| 318 false, |
| 319 0, |
| 320 null, |
| 321 0, |
| 322 0 |
| 323 ]; |
| 324 |
| 325 var NOP_FACTORY = function(){ return function(){}; }; |
| 326 |
| 327 var eventFactory = { |
| 328 // TODO(dfreedm): this is overridden by tap recognizer, needs review |
| 329 preventTap: NOP_FACTORY, |
| 330 makeBaseEvent: function(inType, inDict) { |
| 331 var e = document.createEvent('Event'); |
| 332 e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false); |
| 333 e.preventTap = eventFactory.preventTap(e); |
| 334 return e; |
| 335 }, |
| 336 makeGestureEvent: function(inType, inDict) { |
| 337 inDict = inDict || Object.create(null); |
| 338 |
| 339 var e = this.makeBaseEvent(inType, inDict); |
| 340 for (var i = 0, keys = Object.keys(inDict), k; i < keys.length; i++) { |
| 341 k = keys[i]; |
| 342 e[k] = inDict[k]; |
| 343 } |
| 344 return e; |
| 345 }, |
| 346 makePointerEvent: function(inType, inDict) { |
| 347 inDict = inDict || Object.create(null); |
| 348 |
| 349 var e = this.makeBaseEvent(inType, inDict); |
| 350 // define inherited MouseEvent properties |
| 351 for(var i = 0, p; i < MOUSE_PROPS.length; i++) { |
| 352 p = MOUSE_PROPS[i]; |
| 353 e[p] = inDict[p] || MOUSE_DEFAULTS[i]; |
| 354 } |
| 355 e.buttons = inDict.buttons || 0; |
| 356 |
| 357 // Spec requires that pointers without pressure specified use 0.5 for down |
| 358 // state and 0 for up state. |
| 359 var pressure = 0; |
| 360 if (inDict.pressure) { |
| 361 pressure = inDict.pressure; |
| 362 } else { |
| 363 pressure = e.buttons ? 0.5 : 0; |
| 364 } |
| 365 |
| 366 // add x/y properties aliased to clientX/Y |
| 367 e.x = e.clientX; |
| 368 e.y = e.clientY; |
| 369 |
| 370 // define the properties of the PointerEvent interface |
| 371 e.pointerId = inDict.pointerId || 0; |
| 372 e.width = inDict.width || 0; |
| 373 e.height = inDict.height || 0; |
| 374 e.pressure = pressure; |
| 375 e.tiltX = inDict.tiltX || 0; |
| 376 e.tiltY = inDict.tiltY || 0; |
| 377 e.pointerType = inDict.pointerType || ''; |
| 378 e.hwTimestamp = inDict.hwTimestamp || 0; |
| 379 e.isPrimary = inDict.isPrimary || false; |
| 380 return e; |
| 381 } |
| 382 }; |
| 383 |
| 384 scope.eventFactory = eventFactory; |
| 385 })(window.PolymerGestures); |
| 386 |
| 387 /* |
| 388 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 389 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 390 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 391 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 392 * Code distributed by Google as part of the polymer project is also |
| 393 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 394 */ |
| 395 |
| 396 /** |
| 397 * This module implements an map of pointer states |
| 398 */ |
| 399 (function(scope) { |
| 400 var USE_MAP = window.Map && window.Map.prototype.forEach; |
| 401 var POINTERS_FN = function(){ return this.size; }; |
| 402 function PointerMap() { |
| 403 if (USE_MAP) { |
| 404 var m = new Map(); |
| 405 m.pointers = POINTERS_FN; |
| 406 return m; |
| 407 } else { |
| 408 this.keys = []; |
| 409 this.values = []; |
| 410 } |
| 411 } |
| 412 |
| 413 PointerMap.prototype = { |
| 414 set: function(inId, inEvent) { |
| 415 var i = this.keys.indexOf(inId); |
| 416 if (i > -1) { |
| 417 this.values[i] = inEvent; |
| 418 } else { |
| 419 this.keys.push(inId); |
| 420 this.values.push(inEvent); |
| 421 } |
| 422 }, |
| 423 has: function(inId) { |
| 424 return this.keys.indexOf(inId) > -1; |
| 425 }, |
| 426 'delete': function(inId) { |
| 427 var i = this.keys.indexOf(inId); |
| 428 if (i > -1) { |
| 429 this.keys.splice(i, 1); |
| 430 this.values.splice(i, 1); |
| 431 } |
| 432 }, |
| 433 get: function(inId) { |
| 434 var i = this.keys.indexOf(inId); |
| 435 return this.values[i]; |
| 436 }, |
| 437 clear: function() { |
| 438 this.keys.length = 0; |
| 439 this.values.length = 0; |
| 440 }, |
| 441 // return value, key, map |
| 442 forEach: function(callback, thisArg) { |
| 443 this.values.forEach(function(v, i) { |
| 444 callback.call(thisArg, v, this.keys[i], this); |
| 445 }, this); |
| 446 }, |
| 447 pointers: function() { |
| 448 return this.keys.length; |
| 449 } |
| 450 }; |
| 451 |
| 452 scope.PointerMap = PointerMap; |
| 453 })(window.PolymerGestures); |
| 454 |
| 455 /* |
| 456 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 457 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 458 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 459 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 460 * Code distributed by Google as part of the polymer project is also |
| 461 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 462 */ |
| 463 |
| 464 (function(scope) { |
| 465 var CLONE_PROPS = [ |
| 466 // MouseEvent |
| 467 'bubbles', |
| 468 'cancelable', |
| 469 'view', |
| 470 'detail', |
| 471 'screenX', |
| 472 'screenY', |
| 473 'clientX', |
| 474 'clientY', |
| 475 'ctrlKey', |
| 476 'altKey', |
| 477 'shiftKey', |
| 478 'metaKey', |
| 479 'button', |
| 480 'relatedTarget', |
| 481 // DOM Level 3 |
| 482 'buttons', |
| 483 // PointerEvent |
| 484 'pointerId', |
| 485 'width', |
| 486 'height', |
| 487 'pressure', |
| 488 'tiltX', |
| 489 'tiltY', |
| 490 'pointerType', |
| 491 'hwTimestamp', |
| 492 'isPrimary', |
| 493 // event instance |
| 494 'type', |
| 495 'target', |
| 496 'currentTarget', |
| 497 'which', |
| 498 'pageX', |
| 499 'pageY', |
| 500 'timeStamp', |
| 501 // gesture addons |
| 502 'preventTap', |
| 503 'tapPrevented' |
| 504 ]; |
| 505 |
| 506 var CLONE_DEFAULTS = [ |
| 507 // MouseEvent |
| 508 false, |
| 509 false, |
| 510 null, |
| 511 null, |
| 512 0, |
| 513 0, |
| 514 0, |
| 515 0, |
| 516 false, |
| 517 false, |
| 518 false, |
| 519 false, |
| 520 0, |
| 521 null, |
| 522 // DOM Level 3 |
| 523 0, |
| 524 // PointerEvent |
| 525 0, |
| 526 0, |
| 527 0, |
| 528 0, |
| 529 0, |
| 530 0, |
| 531 '', |
| 532 0, |
| 533 false, |
| 534 // event instance |
| 535 '', |
| 536 null, |
| 537 null, |
| 538 0, |
| 539 0, |
| 540 0, |
| 541 0, |
| 542 function(){}, |
| 543 false |
| 544 ]; |
| 545 |
| 546 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined'); |
| 547 |
| 548 var wrap = window.ShadowDOMPolyfill && ShadowDOMPolyfill.wrapIfNeeded || funct
ion(e){ return e; }; |
| 549 |
| 550 var eventFactory = scope.eventFactory; |
| 551 /** |
| 552 * This module is for normalizing events. Mouse and Touch events will be |
| 553 * collected here, and fire PointerEvents that have the same semantics, no |
| 554 * matter the source. |
| 555 * Events fired: |
| 556 * - pointerdown: a pointing is added |
| 557 * - pointerup: a pointer is removed |
| 558 * - pointermove: a pointer is moved |
| 559 * - pointerover: a pointer crosses into an element |
| 560 * - pointerout: a pointer leaves an element |
| 561 * - pointercancel: a pointer will no longer generate events |
| 562 */ |
| 563 var dispatcher = { |
| 564 pointermap: new scope.PointerMap(), |
| 565 eventMap: Object.create(null), |
| 566 // Scope objects for native events. |
| 567 // This exists for ease of testing. |
| 568 eventSources: Object.create(null), |
| 569 eventSourceList: [], |
| 570 gestures: [], |
| 571 gestureQueue: [], |
| 572 /** |
| 573 * Add a new event source that will generate pointer events. |
| 574 * |
| 575 * `inSource` must contain an array of event names named `events`, and |
| 576 * functions with the names specified in the `events` array. |
| 577 * @param {string} name A name for the event source |
| 578 * @param {Object} source A new source of platform events. |
| 579 */ |
| 580 registerSource: function(name, source) { |
| 581 var s = source; |
| 582 var newEvents = s.events; |
| 583 if (newEvents) { |
| 584 newEvents.forEach(function(e) { |
| 585 if (s[e]) { |
| 586 this.eventMap[e] = s[e].bind(s); |
| 587 } |
| 588 }, this); |
| 589 this.eventSources[name] = s; |
| 590 this.eventSourceList.push(s); |
| 591 } |
| 592 }, |
| 593 registerGesture: function(name, source) { |
| 594 this.gestures.push(source); |
| 595 }, |
| 596 register: function(element) { |
| 597 // NOTE: Work around for #4, don't add listeners to individual Polymer elm
enets in SD Polyfill |
| 598 if (window.ShadowDOMPolyfill && element !== document) { |
| 599 return; |
| 600 } |
| 601 var l = this.eventSourceList.length; |
| 602 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) { |
| 603 // call eventsource register |
| 604 es.register.call(es, element); |
| 605 } |
| 606 }, |
| 607 unregister: function(element) { |
| 608 var l = this.eventSourceList.length; |
| 609 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) { |
| 610 // call eventsource register |
| 611 es.unregister.call(es, element); |
| 612 } |
| 613 }, |
| 614 // EVENTS |
| 615 down: function(inEvent) { |
| 616 this.fireEvent('down', inEvent); |
| 617 }, |
| 618 move: function(inEvent) { |
| 619 // pipe move events into gesture queue directly |
| 620 inEvent.type = 'move'; |
| 621 this.fillGestureQueue(inEvent); |
| 622 }, |
| 623 up: function(inEvent) { |
| 624 this.fireEvent('up', inEvent); |
| 625 }, |
| 626 cancel: function(inEvent) { |
| 627 inEvent.tapPrevented = true; |
| 628 this.fireEvent('up', inEvent); |
| 629 }, |
| 630 // LISTENER LOGIC |
| 631 eventHandler: function(inEvent) { |
| 632 // This is used to prevent multiple dispatch of events from |
| 633 // platform events. This can happen when two elements in different scopes |
| 634 // are set up to create pointer events, which is relevant to Shadow DOM. |
| 635 if (inEvent._handledByPG) { |
| 636 return; |
| 637 } |
| 638 var type = inEvent.type; |
| 639 var fn = this.eventMap && this.eventMap[type]; |
| 640 if (fn) { |
| 641 fn(inEvent); |
| 642 } |
| 643 inEvent._handledByPG = true; |
| 644 }, |
| 645 // set up event listeners |
| 646 listen: function(target, events) { |
| 647 events.forEach(function(e) { |
| 648 this.addEvent(target, e); |
| 649 }, this); |
| 650 }, |
| 651 // remove event listeners |
| 652 unlisten: function(target, events) { |
| 653 events.forEach(function(e) { |
| 654 this.removeEvent(target, e); |
| 655 }, this); |
| 656 }, |
| 657 addEvent: function(target, eventName) { |
| 658 // NOTE: Work around for #4, use native event listener in SD Polyfill |
| 659 if (window.ShadowDOMPolyfill) { |
| 660 target.addEventListener_(eventName, this.boundHandler); |
| 661 } else { |
| 662 target.addEventListener(eventName, this.boundHandler); |
| 663 } |
| 664 }, |
| 665 removeEvent: function(target, eventName) { |
| 666 // NOTE: Work around for #4, use native event listener in SD Polyfill |
| 667 if (window.ShadowDOMPolyfill) { |
| 668 target.removeEventListener_(eventName, this.boundHandler); |
| 669 } else { |
| 670 target.removeEventListener(eventName, this.boundHandler); |
| 671 } |
| 672 }, |
| 673 // EVENT CREATION AND TRACKING |
| 674 /** |
| 675 * Creates a new Event of type `inType`, based on the information in |
| 676 * `inEvent`. |
| 677 * |
| 678 * @param {string} inType A string representing the type of event to create |
| 679 * @param {Event} inEvent A platform event with a target |
| 680 * @return {Event} A PointerEvent of type `inType` |
| 681 */ |
| 682 makeEvent: function(inType, inEvent) { |
| 683 var e = eventFactory.makePointerEvent(inType, inEvent); |
| 684 e.preventDefault = inEvent.preventDefault; |
| 685 e.tapPrevented = inEvent.tapPrevented; |
| 686 e._target = e._target || inEvent.target; |
| 687 return e; |
| 688 }, |
| 689 // make and dispatch an event in one call |
| 690 fireEvent: function(inType, inEvent) { |
| 691 var e = this.makeEvent(inType, inEvent); |
| 692 return this.dispatchEvent(e); |
| 693 }, |
| 694 /** |
| 695 * Returns a snapshot of inEvent, with writable properties. |
| 696 * |
| 697 * @param {Event} inEvent An event that contains properties to copy. |
| 698 * @return {Object} An object containing shallow copies of `inEvent`'s |
| 699 * properties. |
| 700 */ |
| 701 cloneEvent: function(inEvent) { |
| 702 var eventCopy = Object.create(null), p; |
| 703 for (var i = 0; i < CLONE_PROPS.length; i++) { |
| 704 p = CLONE_PROPS[i]; |
| 705 eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i]; |
| 706 // Work around SVGInstanceElement shadow tree |
| 707 // Return the <use> element that is represented by the instance for Safa
ri, Chrome, IE. |
| 708 // This is the behavior implemented by Firefox. |
| 709 if (p === 'target' || p === 'relatedTarget') { |
| 710 if (HAS_SVG_INSTANCE && eventCopy[p] instanceof SVGElementInstance) { |
| 711 eventCopy[p] = eventCopy[p].correspondingUseElement; |
| 712 } |
| 713 eventCopy[p] = wrap(eventCopy[p]); |
| 714 } |
| 715 } |
| 716 // keep the semantics of preventDefault |
| 717 eventCopy.preventDefault = inEvent.preventDefault; |
| 718 return eventCopy; |
| 719 }, |
| 720 /** |
| 721 * Dispatches the event to its target. |
| 722 * |
| 723 * @param {Event} inEvent The event to be dispatched. |
| 724 * @return {Boolean} True if an event handler returns true, false otherwise. |
| 725 */ |
| 726 dispatchEvent: function(inEvent) { |
| 727 var t = inEvent._target; |
| 728 if (t) { |
| 729 t.dispatchEvent(inEvent); |
| 730 // clone the event for the gesture system to process |
| 731 // clone after dispatch to pick up gesture prevention code |
| 732 var clone = this.cloneEvent(inEvent); |
| 733 clone.target = t; |
| 734 this.fillGestureQueue(clone); |
| 735 } |
| 736 }, |
| 737 gestureTrigger: function() { |
| 738 // process the gesture queue |
| 739 for (var i = 0, e; i < this.gestureQueue.length; i++) { |
| 740 e = this.gestureQueue[i]; |
| 741 for (var j = 0, g; j < this.gestures.length; j++) { |
| 742 g = this.gestures[j]; |
| 743 if (g.events.indexOf(e.type) >= 0) { |
| 744 g[e.type].call(g, e); |
| 745 } |
| 746 } |
| 747 } |
| 748 this.gestureQueue.length = 0; |
| 749 }, |
| 750 fillGestureQueue: function(ev) { |
| 751 // only trigger the gesture queue once |
| 752 if (!this.gestureQueue.length) { |
| 753 requestAnimationFrame(this.boundGestureTrigger); |
| 754 } |
| 755 this.gestureQueue.push(ev); |
| 756 } |
| 757 }; |
| 758 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher); |
| 759 dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher); |
| 760 scope.dispatcher = dispatcher; |
| 761 scope.register = dispatcher.register.bind(dispatcher); |
| 762 scope.unregister = dispatcher.unregister.bind(dispatcher); |
| 763 })(window.PolymerGestures); |
| 764 |
| 765 /* |
| 766 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 767 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 768 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 769 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 770 * Code distributed by Google as part of the polymer project is also |
| 771 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 772 */ |
| 773 |
| 774 /** |
| 775 * This module uses Mutation Observers to dynamically adjust which nodes will |
| 776 * generate Pointer Events. |
| 777 * |
| 778 * All nodes that wish to generate Pointer Events must have the attribute |
| 779 * `touch-action` set to `none`. |
| 780 */ |
| 781 (function(scope) { |
| 782 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); |
| 783 var map = Array.prototype.map.call.bind(Array.prototype.map); |
| 784 var toArray = Array.prototype.slice.call.bind(Array.prototype.slice); |
| 785 var filter = Array.prototype.filter.call.bind(Array.prototype.filter); |
| 786 var MO = window.MutationObserver || window.WebKitMutationObserver; |
| 787 var SELECTOR = '[touch-action]'; |
| 788 var OBSERVER_INIT = { |
| 789 subtree: true, |
| 790 childList: true, |
| 791 attributes: true, |
| 792 attributeOldValue: true, |
| 793 attributeFilter: ['touch-action'] |
| 794 }; |
| 795 |
| 796 function Installer(add, remove, changed, binder) { |
| 797 this.addCallback = add.bind(binder); |
| 798 this.removeCallback = remove.bind(binder); |
| 799 this.changedCallback = changed.bind(binder); |
| 800 if (MO) { |
| 801 this.observer = new MO(this.mutationWatcher.bind(this)); |
| 802 } |
| 803 } |
| 804 |
| 805 Installer.prototype = { |
| 806 watchSubtree: function(target) { |
| 807 // Only watch scopes that can target find, as these are top-level. |
| 808 // Otherwise we can see duplicate additions and removals that add noise. |
| 809 // |
| 810 // TODO(dfreedman): For some instances with ShadowDOMPolyfill, we can see |
| 811 // a removal without an insertion when a node is redistributed among |
| 812 // shadows. Since it all ends up correct in the document, watching only |
| 813 // the document will yield the correct mutations to watch. |
| 814 if (scope.targetFinding.canTarget(target)) { |
| 815 this.observer.observe(target, OBSERVER_INIT); |
| 816 } |
| 817 }, |
| 818 enableOnSubtree: function(target) { |
| 819 this.watchSubtree(target); |
| 820 if (target === document && document.readyState !== 'complete') { |
| 821 this.installOnLoad(); |
| 822 } else { |
| 823 this.installNewSubtree(target); |
| 824 } |
| 825 }, |
| 826 installNewSubtree: function(target) { |
| 827 forEach(this.findElements(target), this.addElement, this); |
| 828 }, |
| 829 findElements: function(target) { |
| 830 if (target.querySelectorAll) { |
| 831 return target.querySelectorAll(SELECTOR); |
| 832 } |
| 833 return []; |
| 834 }, |
| 835 removeElement: function(el) { |
| 836 this.removeCallback(el); |
| 837 }, |
| 838 addElement: function(el) { |
| 839 this.addCallback(el); |
| 840 }, |
| 841 elementChanged: function(el, oldValue) { |
| 842 this.changedCallback(el, oldValue); |
| 843 }, |
| 844 concatLists: function(accum, list) { |
| 845 return accum.concat(toArray(list)); |
| 846 }, |
| 847 // register all touch-action = none nodes on document load |
| 848 installOnLoad: function() { |
| 849 document.addEventListener('readystatechange', function() { |
| 850 if (document.readyState === 'complete') { |
| 851 this.installNewSubtree(document); |
| 852 } |
| 853 }.bind(this)); |
| 854 }, |
| 855 isElement: function(n) { |
| 856 return n.nodeType === Node.ELEMENT_NODE; |
| 857 }, |
| 858 flattenMutationTree: function(inNodes) { |
| 859 // find children with touch-action |
| 860 var tree = map(inNodes, this.findElements, this); |
| 861 // make sure the added nodes are accounted for |
| 862 tree.push(filter(inNodes, this.isElement)); |
| 863 // flatten the list |
| 864 return tree.reduce(this.concatLists, []); |
| 865 }, |
| 866 mutationWatcher: function(mutations) { |
| 867 mutations.forEach(this.mutationHandler, this); |
| 868 }, |
| 869 mutationHandler: function(m) { |
| 870 if (m.type === 'childList') { |
| 871 var added = this.flattenMutationTree(m.addedNodes); |
| 872 added.forEach(this.addElement, this); |
| 873 var removed = this.flattenMutationTree(m.removedNodes); |
| 874 removed.forEach(this.removeElement, this); |
| 875 } else if (m.type === 'attributes') { |
| 876 this.elementChanged(m.target, m.oldValue); |
| 877 } |
| 878 } |
| 879 }; |
| 880 |
| 881 if (!MO) { |
| 882 Installer.prototype.watchSubtree = function(){ |
| 883 console.warn('PolymerGestures: MutationObservers not found, touch-action w
ill not be dynamically detected'); |
| 884 }; |
| 885 } |
| 886 |
| 887 scope.Installer = Installer; |
| 888 })(window.PolymerGestures); |
| 889 |
| 890 /* |
| 891 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 892 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 893 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 894 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 895 * Code distributed by Google as part of the polymer project is also |
| 896 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 897 */ |
| 898 |
| 899 (function (scope) { |
| 900 var dispatcher = scope.dispatcher; |
| 901 var pointermap = dispatcher.pointermap; |
| 902 // radius around touchend that swallows mouse events |
| 903 var DEDUP_DIST = 25; |
| 904 |
| 905 var WHICH_TO_BUTTONS = [0, 1, 4, 2]; |
| 906 |
| 907 var HAS_BUTTONS = false; |
| 908 try { |
| 909 HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1; |
| 910 } catch (e) {} |
| 911 |
| 912 // handler block for native mouse events |
| 913 var mouseEvents = { |
| 914 POINTER_ID: 1, |
| 915 POINTER_TYPE: 'mouse', |
| 916 events: [ |
| 917 'mousedown', |
| 918 'mousemove', |
| 919 'mouseup', |
| 920 ], |
| 921 register: function(target) { |
| 922 dispatcher.listen(target, this.events); |
| 923 }, |
| 924 unregister: function(target) { |
| 925 dispatcher.unlisten(target, this.events); |
| 926 }, |
| 927 lastTouches: [], |
| 928 // collide with the global mouse listener |
| 929 isEventSimulatedFromTouch: function(inEvent) { |
| 930 var lts = this.lastTouches; |
| 931 var x = inEvent.clientX, y = inEvent.clientY; |
| 932 for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) { |
| 933 // simulated mouse events will be swallowed near a primary touchend |
| 934 var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y); |
| 935 if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) { |
| 936 return true; |
| 937 } |
| 938 } |
| 939 }, |
| 940 prepareEvent: function(inEvent) { |
| 941 var e = dispatcher.cloneEvent(inEvent); |
| 942 e.pointerId = this.POINTER_ID; |
| 943 e.isPrimary = true; |
| 944 e.pointerType = this.POINTER_TYPE; |
| 945 if (!HAS_BUTTONS) { |
| 946 e.buttons = WHICH_TO_BUTTONS[e.which] || 0; |
| 947 } |
| 948 return e; |
| 949 }, |
| 950 mousedown: function(inEvent) { |
| 951 if (!this.isEventSimulatedFromTouch(inEvent)) { |
| 952 var p = pointermap.has(this.POINTER_ID); |
| 953 // TODO(dfreedman) workaround for some elements not sending mouseup |
| 954 // http://crbug/149091 |
| 955 if (p) { |
| 956 this.mouseup(inEvent); |
| 957 } |
| 958 var e = this.prepareEvent(inEvent); |
| 959 pointermap.set(this.POINTER_ID, e.target); |
| 960 dispatcher.down(e); |
| 961 } |
| 962 }, |
| 963 mousemove: function(inEvent) { |
| 964 if (!this.isEventSimulatedFromTouch(inEvent)) { |
| 965 var e = this.prepareEvent(inEvent); |
| 966 e.target = pointermap.get(this.POINTER_ID); |
| 967 dispatcher.move(e); |
| 968 } |
| 969 }, |
| 970 mouseup: function(inEvent) { |
| 971 if (!this.isEventSimulatedFromTouch(inEvent)) { |
| 972 var e = this.prepareEvent(inEvent); |
| 973 e.relatedTarget = e.target; |
| 974 e.target = pointermap.get(this.POINTER_ID); |
| 975 dispatcher.up(e); |
| 976 this.cleanupMouse(); |
| 977 } |
| 978 }, |
| 979 cleanupMouse: function() { |
| 980 pointermap['delete'](this.POINTER_ID); |
| 981 } |
| 982 }; |
| 983 |
| 984 scope.mouseEvents = mouseEvents; |
| 985 })(window.PolymerGestures); |
| 986 |
| 987 /* |
| 988 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 989 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 990 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 991 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 992 * Code distributed by Google as part of the polymer project is also |
| 993 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 994 */ |
| 995 |
| 996 (function(scope) { |
| 997 var dispatcher = scope.dispatcher; |
| 998 var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding); |
| 999 var pointermap = dispatcher.pointermap; |
| 1000 var touchMap = Array.prototype.map.call.bind(Array.prototype.map); |
| 1001 // This should be long enough to ignore compat mouse events made by touch |
| 1002 var DEDUP_TIMEOUT = 2500; |
| 1003 var CLICK_COUNT_TIMEOUT = 200; |
| 1004 var ATTRIB = 'touch-action'; |
| 1005 var INSTALLER; |
| 1006 var HAS_TOUCH_ACTION = typeof document.head.style.touchAction === 'string'; |
| 1007 |
| 1008 // handler block for native touch events |
| 1009 var touchEvents = { |
| 1010 events: [ |
| 1011 'touchstart', |
| 1012 'touchmove', |
| 1013 'touchend', |
| 1014 'touchcancel' |
| 1015 ], |
| 1016 register: function(target) { |
| 1017 if (HAS_TOUCH_ACTION) { |
| 1018 dispatcher.listen(target, this.events); |
| 1019 } else { |
| 1020 INSTALLER.enableOnSubtree(target); |
| 1021 } |
| 1022 }, |
| 1023 unregister: function(target) { |
| 1024 if (HAS_TOUCH_ACTION) { |
| 1025 dispatcher.unlisten(target, this.events); |
| 1026 } else { |
| 1027 // TODO(dfreedman): is it worth it to disconnect the MO? |
| 1028 } |
| 1029 }, |
| 1030 elementAdded: function(el) { |
| 1031 var a = el.getAttribute(ATTRIB); |
| 1032 var st = this.touchActionToScrollType(a); |
| 1033 if (st) { |
| 1034 el._scrollType = st; |
| 1035 dispatcher.listen(el, this.events); |
| 1036 // set touch-action on shadows as well |
| 1037 allShadows(el).forEach(function(s) { |
| 1038 s._scrollType = st; |
| 1039 dispatcher.listen(s, this.events); |
| 1040 }, this); |
| 1041 } |
| 1042 }, |
| 1043 elementRemoved: function(el) { |
| 1044 el._scrollType = undefined; |
| 1045 dispatcher.unlisten(el, this.events); |
| 1046 // remove touch-action from shadow |
| 1047 allShadows(el).forEach(function(s) { |
| 1048 s._scrollType = undefined; |
| 1049 dispatcher.unlisten(s, this.events); |
| 1050 }, this); |
| 1051 }, |
| 1052 elementChanged: function(el, oldValue) { |
| 1053 var a = el.getAttribute(ATTRIB); |
| 1054 var st = this.touchActionToScrollType(a); |
| 1055 var oldSt = this.touchActionToScrollType(oldValue); |
| 1056 // simply update scrollType if listeners are already established |
| 1057 if (st && oldSt) { |
| 1058 el._scrollType = st; |
| 1059 allShadows(el).forEach(function(s) { |
| 1060 s._scrollType = st; |
| 1061 }, this); |
| 1062 } else if (oldSt) { |
| 1063 this.elementRemoved(el); |
| 1064 } else if (st) { |
| 1065 this.elementAdded(el); |
| 1066 } |
| 1067 }, |
| 1068 scrollTypes: { |
| 1069 EMITTER: 'none', |
| 1070 XSCROLLER: 'pan-x', |
| 1071 YSCROLLER: 'pan-y', |
| 1072 SCROLLER: /^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/ |
| 1073 }, |
| 1074 touchActionToScrollType: function(touchAction) { |
| 1075 var t = touchAction; |
| 1076 var st = this.scrollTypes; |
| 1077 if (t === 'none') { |
| 1078 return 'none'; |
| 1079 } else if (t === st.XSCROLLER) { |
| 1080 return 'X'; |
| 1081 } else if (t === st.YSCROLLER) { |
| 1082 return 'Y'; |
| 1083 } else if (st.SCROLLER.exec(t)) { |
| 1084 return 'XY'; |
| 1085 } |
| 1086 }, |
| 1087 POINTER_TYPE: 'touch', |
| 1088 firstTouch: null, |
| 1089 isPrimaryTouch: function(inTouch) { |
| 1090 return this.firstTouch === inTouch.identifier; |
| 1091 }, |
| 1092 setPrimaryTouch: function(inTouch) { |
| 1093 // set primary touch if there no pointers, or the only pointer is the mous
e |
| 1094 if (pointermap.pointers() === 0 || (pointermap.pointers() === 1 && pointer
map.has(1))) { |
| 1095 this.firstTouch = inTouch.identifier; |
| 1096 this.firstXY = {X: inTouch.clientX, Y: inTouch.clientY}; |
| 1097 this.scrolling = false; |
| 1098 this.cancelResetClickCount(); |
| 1099 } |
| 1100 }, |
| 1101 removePrimaryPointer: function(inPointer) { |
| 1102 if (inPointer.isPrimary) { |
| 1103 this.firstTouch = null; |
| 1104 this.firstXY = null; |
| 1105 this.resetClickCount(); |
| 1106 } |
| 1107 }, |
| 1108 clickCount: 0, |
| 1109 resetId: null, |
| 1110 resetClickCount: function() { |
| 1111 var fn = function() { |
| 1112 this.clickCount = 0; |
| 1113 this.resetId = null; |
| 1114 }.bind(this); |
| 1115 this.resetId = setTimeout(fn, CLICK_COUNT_TIMEOUT); |
| 1116 }, |
| 1117 cancelResetClickCount: function() { |
| 1118 if (this.resetId) { |
| 1119 clearTimeout(this.resetId); |
| 1120 } |
| 1121 }, |
| 1122 typeToButtons: function(type) { |
| 1123 var ret = 0; |
| 1124 if (type === 'touchstart' || type === 'touchmove') { |
| 1125 ret = 1; |
| 1126 } |
| 1127 return ret; |
| 1128 }, |
| 1129 findTarget: function(touch, id) { |
| 1130 if (this.currentTouchEvent.type === 'touchstart') { |
| 1131 return scope.findTarget(touch); |
| 1132 } |
| 1133 // reuse target we found in touchstart |
| 1134 return pointermap.get(id); |
| 1135 }, |
| 1136 touchToPointer: function(inTouch) { |
| 1137 var cte = this.currentTouchEvent; |
| 1138 var e = dispatcher.cloneEvent(inTouch); |
| 1139 // Spec specifies that pointerId 1 is reserved for Mouse. |
| 1140 // Touch identifiers can start at 0. |
| 1141 // Add 2 to the touch identifier for compatibility. |
| 1142 var id = e.pointerId = inTouch.identifier + 2; |
| 1143 e.target = this.findTarget(inTouch, id); |
| 1144 e.bubbles = true; |
| 1145 e.cancelable = true; |
| 1146 e.detail = this.clickCount; |
| 1147 e.buttons = this.typeToButtons(cte.type); |
| 1148 e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0; |
| 1149 e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0; |
| 1150 e.pressure = inTouch.webkitForce || inTouch.force || 0.5; |
| 1151 e.isPrimary = this.isPrimaryTouch(inTouch); |
| 1152 e.pointerType = this.POINTER_TYPE; |
| 1153 // forward touch preventDefaults |
| 1154 var self = this; |
| 1155 e.preventDefault = function() { |
| 1156 self.scrolling = false; |
| 1157 self.firstXY = null; |
| 1158 cte.preventDefault(); |
| 1159 }; |
| 1160 return e; |
| 1161 }, |
| 1162 processTouches: function(inEvent, inFunction) { |
| 1163 var tl = inEvent.changedTouches; |
| 1164 this.currentTouchEvent = inEvent; |
| 1165 for (var i = 0, t; i < tl.length; i++) { |
| 1166 t = tl[i]; |
| 1167 inFunction.call(this, this.touchToPointer(t)); |
| 1168 } |
| 1169 }, |
| 1170 // For single axis scrollers, determines whether the element should emit |
| 1171 // pointer events or behave as a scroller |
| 1172 shouldScroll: function(inEvent) { |
| 1173 if (this.firstXY) { |
| 1174 var ret; |
| 1175 var scrollAxis = inEvent.currentTarget._scrollType; |
| 1176 if (scrollAxis === 'none') { |
| 1177 // this element is a touch-action: none, should never scroll |
| 1178 ret = false; |
| 1179 } else if (scrollAxis === 'XY') { |
| 1180 // this element should always scroll |
| 1181 ret = true; |
| 1182 } else { |
| 1183 var t = inEvent.changedTouches[0]; |
| 1184 // check the intended scroll axis, and other axis |
| 1185 var a = scrollAxis; |
| 1186 var oa = scrollAxis === 'Y' ? 'X' : 'Y'; |
| 1187 var da = Math.abs(t['client' + a] - this.firstXY[a]); |
| 1188 var doa = Math.abs(t['client' + oa] - this.firstXY[oa]); |
| 1189 // if delta in the scroll axis > delta other axis, scroll instead of |
| 1190 // making events |
| 1191 ret = da >= doa; |
| 1192 } |
| 1193 this.firstXY = null; |
| 1194 return ret; |
| 1195 } |
| 1196 }, |
| 1197 findTouch: function(inTL, inId) { |
| 1198 for (var i = 0, l = inTL.length, t; i < l && (t = inTL[i]); i++) { |
| 1199 if (t.identifier === inId) { |
| 1200 return true; |
| 1201 } |
| 1202 } |
| 1203 }, |
| 1204 // In some instances, a touchstart can happen without a touchend. This |
| 1205 // leaves the pointermap in a broken state. |
| 1206 // Therefore, on every touchstart, we remove the touches that did not fire a |
| 1207 // touchend event. |
| 1208 // To keep state globally consistent, we fire a |
| 1209 // pointercancel for this "abandoned" touch |
| 1210 vacuumTouches: function(inEvent) { |
| 1211 var tl = inEvent.touches; |
| 1212 // pointermap.pointers() should be < tl.length here, as the touchstart has
not |
| 1213 // been processed yet. |
| 1214 if (pointermap.pointers() >= tl.length) { |
| 1215 var d = []; |
| 1216 pointermap.forEach(function(value, key) { |
| 1217 // Never remove pointerId == 1, which is mouse. |
| 1218 // Touch identifiers are 2 smaller than their pointerId, which is the |
| 1219 // index in pointermap. |
| 1220 if (key !== 1 && !this.findTouch(tl, key - 2)) { |
| 1221 var p = value.out; |
| 1222 d.push(p); |
| 1223 } |
| 1224 }, this); |
| 1225 d.forEach(this.cancelOut, this); |
| 1226 } |
| 1227 }, |
| 1228 touchstart: function(inEvent) { |
| 1229 this.vacuumTouches(inEvent); |
| 1230 this.setPrimaryTouch(inEvent.changedTouches[0]); |
| 1231 this.dedupSynthMouse(inEvent); |
| 1232 if (!this.scrolling) { |
| 1233 this.clickCount++; |
| 1234 this.processTouches(inEvent, this.down); |
| 1235 } |
| 1236 }, |
| 1237 down: function(inPointer) { |
| 1238 var p = pointermap.set(inPointer.pointerId, inPointer.target); |
| 1239 dispatcher.down(inPointer); |
| 1240 }, |
| 1241 touchmove: function(inEvent) { |
| 1242 if (HAS_TOUCH_ACTION) { |
| 1243 this.processTouches(inEvent, this.move); |
| 1244 } else { |
| 1245 if (!this.scrolling) { |
| 1246 if (this.shouldScroll(inEvent)) { |
| 1247 this.scrolling = true; |
| 1248 this.touchcancel(inEvent); |
| 1249 } else { |
| 1250 inEvent.preventDefault(); |
| 1251 this.processTouches(inEvent, this.move); |
| 1252 } |
| 1253 } |
| 1254 } |
| 1255 }, |
| 1256 move: function(inPointer) { |
| 1257 var pointer = pointermap.get(inPointer.pointerId); |
| 1258 // a finger drifted off the screen, ignore it |
| 1259 if (!pointer) { |
| 1260 return; |
| 1261 } |
| 1262 dispatcher.move(inPointer); |
| 1263 }, |
| 1264 touchend: function(inEvent) { |
| 1265 this.dedupSynthMouse(inEvent); |
| 1266 this.processTouches(inEvent, this.up); |
| 1267 }, |
| 1268 up: function(inPointer) { |
| 1269 if (!this.scrolling) { |
| 1270 inPointer.relatedTarget = scope.findTarget(inPointer); |
| 1271 dispatcher.up(inPointer); |
| 1272 } |
| 1273 this.cleanUpPointer(inPointer); |
| 1274 }, |
| 1275 cancel: function(inPointer) { |
| 1276 inPointer.relatedTarget = scope.findTarget(inPointer); |
| 1277 dispatcher.cancel(inPointer); |
| 1278 this.cleanUpPointer(inPointer); |
| 1279 }, |
| 1280 touchcancel: function(inEvent) { |
| 1281 this.processTouches(inEvent, this.cancel); |
| 1282 }, |
| 1283 cleanUpPointer: function(inPointer) { |
| 1284 pointermap['delete'](inPointer.pointerId); |
| 1285 this.removePrimaryPointer(inPointer); |
| 1286 }, |
| 1287 // prevent synth mouse events from creating pointer events |
| 1288 dedupSynthMouse: function(inEvent) { |
| 1289 var lts = scope.mouseEvents.lastTouches; |
| 1290 var t = inEvent.changedTouches[0]; |
| 1291 // only the primary finger will synth mouse events |
| 1292 if (this.isPrimaryTouch(t)) { |
| 1293 // remember x/y of last touch |
| 1294 var lt = {x: t.clientX, y: t.clientY}; |
| 1295 lts.push(lt); |
| 1296 var fn = (function(lts, lt){ |
| 1297 var i = lts.indexOf(lt); |
| 1298 if (i > -1) { |
| 1299 lts.splice(i, 1); |
| 1300 } |
| 1301 }).bind(null, lts, lt); |
| 1302 setTimeout(fn, DEDUP_TIMEOUT); |
| 1303 } |
| 1304 } |
| 1305 }; |
| 1306 |
| 1307 if (!HAS_TOUCH_ACTION) { |
| 1308 INSTALLER = new scope.Installer(touchEvents.elementAdded, touchEvents.elemen
tRemoved, touchEvents.elementChanged, touchEvents); |
| 1309 } |
| 1310 |
| 1311 scope.touchEvents = touchEvents; |
| 1312 })(window.PolymerGestures); |
| 1313 |
| 1314 /* |
| 1315 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 1316 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 1317 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 1318 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 1319 * Code distributed by Google as part of the polymer project is also |
| 1320 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 1321 */ |
| 1322 |
| 1323 (function(scope) { |
| 1324 var dispatcher = scope.dispatcher; |
| 1325 var pointermap = dispatcher.pointermap; |
| 1326 var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MS
POINTER_TYPE_MOUSE === 'number'; |
| 1327 var msEvents = { |
| 1328 events: [ |
| 1329 'MSPointerDown', |
| 1330 'MSPointerMove', |
| 1331 'MSPointerUp', |
| 1332 'MSPointerCancel', |
| 1333 ], |
| 1334 register: function(target) { |
| 1335 dispatcher.listen(target, this.events); |
| 1336 }, |
| 1337 unregister: function(target) { |
| 1338 dispatcher.unlisten(target, this.events); |
| 1339 }, |
| 1340 POINTER_TYPES: [ |
| 1341 '', |
| 1342 'unavailable', |
| 1343 'touch', |
| 1344 'pen', |
| 1345 'mouse' |
| 1346 ], |
| 1347 prepareEvent: function(inEvent) { |
| 1348 var e = inEvent; |
| 1349 if (HAS_BITMAP_TYPE) { |
| 1350 e = dispatcher.cloneEvent(inEvent); |
| 1351 e.pointerType = this.POINTER_TYPES[inEvent.pointerType]; |
| 1352 } |
| 1353 return e; |
| 1354 }, |
| 1355 cleanup: function(id) { |
| 1356 pointermap['delete'](id); |
| 1357 }, |
| 1358 MSPointerDown: function(inEvent) { |
| 1359 var e = this.prepareEvent(inEvent); |
| 1360 pointermap.set(inEvent.pointerId, e.target); |
| 1361 dispatcher.down(e); |
| 1362 }, |
| 1363 MSPointerMove: function(inEvent) { |
| 1364 var e = this.prepareEvent(inEvent); |
| 1365 e.target = pointermap.get(e.pointerId); |
| 1366 dispatcher.move(e); |
| 1367 }, |
| 1368 MSPointerUp: function(inEvent) { |
| 1369 var e = this.prepareEvent(inEvent); |
| 1370 e.relatedTarget = e.target; |
| 1371 e.target = pointermap.get(e.pointerId); |
| 1372 dispatcher.up(e); |
| 1373 this.cleanup(inEvent.pointerId); |
| 1374 }, |
| 1375 MSPointerCancel: function(inEvent) { |
| 1376 var e = this.prepareEvent(inEvent); |
| 1377 e.relatedTarget = e.target; |
| 1378 e.target = pointermap.get(e.pointerId); |
| 1379 dispatcher.cancel(e); |
| 1380 this.cleanup(inEvent.pointerId); |
| 1381 } |
| 1382 }; |
| 1383 |
| 1384 scope.msEvents = msEvents; |
| 1385 })(window.PolymerGestures); |
| 1386 |
| 1387 /* |
| 1388 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 1389 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 1390 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 1391 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 1392 * Code distributed by Google as part of the polymer project is also |
| 1393 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 1394 */ |
| 1395 |
| 1396 (function(scope) { |
| 1397 var dispatcher = scope.dispatcher; |
| 1398 var pointermap = dispatcher.pointermap; |
| 1399 var pointerEvents = { |
| 1400 events: [ |
| 1401 'pointerdown', |
| 1402 'pointermove', |
| 1403 'pointerup', |
| 1404 'pointercancel' |
| 1405 ], |
| 1406 prepareEvent: function(inEvent) { |
| 1407 return dispatcher.cloneEvent(inEvent); |
| 1408 }, |
| 1409 register: function(target) { |
| 1410 dispatcher.listen(target, this.events); |
| 1411 }, |
| 1412 unregister: function(target) { |
| 1413 dispatcher.unlisten(target, this.events); |
| 1414 }, |
| 1415 cleanup: function(id) { |
| 1416 pointermap['delete'](id); |
| 1417 }, |
| 1418 pointerdown: function(inEvent) { |
| 1419 var e = this.prepareEvent(inEvent); |
| 1420 pointermap.set(e.pointerId, e.target); |
| 1421 dispatcher.down(e); |
| 1422 }, |
| 1423 pointermove: function(inEvent) { |
| 1424 var e = this.prepareEvent(inEvent); |
| 1425 e.target = pointermap.get(e.pointerId); |
| 1426 dispatcher.move(e); |
| 1427 }, |
| 1428 pointerup: function(inEvent) { |
| 1429 var e = this.prepareEvent(inEvent); |
| 1430 e.relatedTarget = e.target; |
| 1431 e.target = pointermap.get(e.pointerId); |
| 1432 dispatcher.up(e); |
| 1433 this.cleanup(inEvent.pointerId); |
| 1434 }, |
| 1435 pointercancel: function(inEvent) { |
| 1436 var e = this.prepareEvent(inEvent); |
| 1437 e.relatedTarget = e.target; |
| 1438 e.target = pointermap.get(e.pointerId); |
| 1439 dispatcher.cancel(e); |
| 1440 this.cleanup(inEvent.pointerId); |
| 1441 } |
| 1442 }; |
| 1443 |
| 1444 scope.pointerEvents = pointerEvents; |
| 1445 })(window.PolymerGestures); |
| 1446 |
| 1447 /* |
| 1448 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 1449 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 1450 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 1451 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 1452 * Code distributed by Google as part of the polymer project is also |
| 1453 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 1454 */ |
| 1455 |
| 1456 /** |
| 1457 * This module contains the handlers for native platform events. |
| 1458 * From here, the dispatcher is called to create unified pointer events. |
| 1459 * Included are touch events (v1), mouse events, and MSPointerEvents. |
| 1460 */ |
| 1461 (function(scope) { |
| 1462 var dispatcher = scope.dispatcher; |
| 1463 |
| 1464 if (window.PointerEvent) { |
| 1465 dispatcher.registerSource('pointer', scope.pointerEvents); |
| 1466 } else if (window.navigator.msPointerEnabled) { |
| 1467 dispatcher.registerSource('ms', scope.msEvents); |
| 1468 } else { |
| 1469 dispatcher.registerSource('mouse', scope.mouseEvents); |
| 1470 if (window.ontouchstart !== undefined) { |
| 1471 dispatcher.registerSource('touch', scope.touchEvents); |
| 1472 } |
| 1473 } |
| 1474 |
| 1475 dispatcher.register(document); |
| 1476 })(window.PolymerGestures); |
| 1477 |
| 1478 /* |
| 1479 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 1480 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 1481 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 1482 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 1483 * Code distributed by Google as part of the polymer project is also |
| 1484 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 1485 */ |
| 1486 |
| 1487 /** |
| 1488 * This event denotes the beginning of a series of tracking events. |
| 1489 * |
| 1490 * @module PointerGestures |
| 1491 * @submodule Events |
| 1492 * @class trackstart |
| 1493 */ |
| 1494 /** |
| 1495 * Pixels moved in the x direction since trackstart. |
| 1496 * @type Number |
| 1497 * @property dx |
| 1498 */ |
| 1499 /** |
| 1500 * Pixes moved in the y direction since trackstart. |
| 1501 * @type Number |
| 1502 * @property dy |
| 1503 */ |
| 1504 /** |
| 1505 * Pixels moved in the x direction since the last track. |
| 1506 * @type Number |
| 1507 * @property ddx |
| 1508 */ |
| 1509 /** |
| 1510 * Pixles moved in the y direction since the last track. |
| 1511 * @type Number |
| 1512 * @property ddy |
| 1513 */ |
| 1514 /** |
| 1515 * The clientX position of the track gesture. |
| 1516 * @type Number |
| 1517 * @property clientX |
| 1518 */ |
| 1519 /** |
| 1520 * The clientY position of the track gesture. |
| 1521 * @type Number |
| 1522 * @property clientY |
| 1523 */ |
| 1524 /** |
| 1525 * The pageX position of the track gesture. |
| 1526 * @type Number |
| 1527 * @property pageX |
| 1528 */ |
| 1529 /** |
| 1530 * The pageY position of the track gesture. |
| 1531 * @type Number |
| 1532 * @property pageY |
| 1533 */ |
| 1534 /** |
| 1535 * The screenX position of the track gesture. |
| 1536 * @type Number |
| 1537 * @property screenX |
| 1538 */ |
| 1539 /** |
| 1540 * The screenY position of the track gesture. |
| 1541 * @type Number |
| 1542 * @property screenY |
| 1543 */ |
| 1544 /** |
| 1545 * The last x axis direction of the pointer. |
| 1546 * @type Number |
| 1547 * @property xDirection |
| 1548 */ |
| 1549 /** |
| 1550 * The last y axis direction of the pointer. |
| 1551 * @type Number |
| 1552 * @property yDirection |
| 1553 */ |
| 1554 /** |
| 1555 * A shared object between all tracking events. |
| 1556 * @type Object |
| 1557 * @property trackInfo |
| 1558 */ |
| 1559 /** |
| 1560 * The element currently under the pointer. |
| 1561 * @type Element |
| 1562 * @property relatedTarget |
| 1563 */ |
| 1564 /** |
| 1565 * The type of pointer that make the track gesture. |
| 1566 * @type String |
| 1567 * @property pointerType |
| 1568 */ |
| 1569 /** |
| 1570 * |
| 1571 * This event fires for all pointer movement being tracked. |
| 1572 * |
| 1573 * @class track |
| 1574 * @extends trackstart |
| 1575 */ |
| 1576 /** |
| 1577 * This event fires when the pointer is no longer being tracked. |
| 1578 * |
| 1579 * @class trackend |
| 1580 * @extends trackstart |
| 1581 */ |
| 1582 |
| 1583 (function(scope) { |
| 1584 var dispatcher = scope.dispatcher; |
| 1585 var eventFactory = scope.eventFactory; |
| 1586 var pointermap = new scope.PointerMap(); |
| 1587 var track = { |
| 1588 events: [ |
| 1589 'down', |
| 1590 'move', |
| 1591 'up', |
| 1592 ], |
| 1593 WIGGLE_THRESHOLD: 4, |
| 1594 clampDir: function(inDelta) { |
| 1595 return inDelta > 0 ? 1 : -1; |
| 1596 }, |
| 1597 calcPositionDelta: function(inA, inB) { |
| 1598 var x = 0, y = 0; |
| 1599 if (inA && inB) { |
| 1600 x = inB.pageX - inA.pageX; |
| 1601 y = inB.pageY - inA.pageY; |
| 1602 } |
| 1603 return {x: x, y: y}; |
| 1604 }, |
| 1605 fireTrack: function(inType, inEvent, inTrackingData) { |
| 1606 var t = inTrackingData; |
| 1607 var d = this.calcPositionDelta(t.downEvent, inEvent); |
| 1608 var dd = this.calcPositionDelta(t.lastMoveEvent, inEvent); |
| 1609 if (dd.x) { |
| 1610 t.xDirection = this.clampDir(dd.x); |
| 1611 } |
| 1612 if (dd.y) { |
| 1613 t.yDirection = this.clampDir(dd.y); |
| 1614 } |
| 1615 var e = eventFactory.makeGestureEvent(inType, { |
| 1616 bubbles: true, |
| 1617 cancelable: true, |
| 1618 dx: d.x, |
| 1619 dy: d.y, |
| 1620 ddx: dd.x, |
| 1621 ddy: dd.y, |
| 1622 x: inEvent.x, |
| 1623 y: inEvent.y, |
| 1624 clientX: inEvent.clientX, |
| 1625 clientY: inEvent.clientY, |
| 1626 pageX: inEvent.pageX, |
| 1627 pageY: inEvent.pageY, |
| 1628 screenX: inEvent.screenX, |
| 1629 screenY: inEvent.screenY, |
| 1630 xDirection: t.xDirection, |
| 1631 yDirection: t.yDirection, |
| 1632 trackInfo: t.trackInfo, |
| 1633 relatedTarget: inEvent.relatedTarget, |
| 1634 pointerType: inEvent.pointerType, |
| 1635 pointerId: inEvent.pointerId |
| 1636 }); |
| 1637 t.downTarget.dispatchEvent(e); |
| 1638 }, |
| 1639 down: function(inEvent) { |
| 1640 if (inEvent.isPrimary && (inEvent.pointerType === 'mouse' ? inEvent.butto
ns === 1 : true)) { |
| 1641 var p = { |
| 1642 downEvent: inEvent, |
| 1643 downTarget: inEvent.target, |
| 1644 trackInfo: {}, |
| 1645 lastMoveEvent: null, |
| 1646 xDirection: 0, |
| 1647 yDirection: 0, |
| 1648 tracking: false |
| 1649 }; |
| 1650 pointermap.set(inEvent.pointerId, p); |
| 1651 } |
| 1652 }, |
| 1653 move: function(inEvent) { |
| 1654 var p = pointermap.get(inEvent.pointerId); |
| 1655 if (p) { |
| 1656 if (!p.tracking) { |
| 1657 var d = this.calcPositionDelta(p.downEvent, inEvent); |
| 1658 var move = d.x * d.x + d.y * d.y; |
| 1659 // start tracking only if finger moves more than WIGGLE_THRESHOLD |
| 1660 if (move > this.WIGGLE_THRESHOLD) { |
| 1661 p.tracking = true; |
| 1662 this.fireTrack('trackstart', p.downEvent, p); |
| 1663 this.fireTrack('track', inEvent, p); |
| 1664 } |
| 1665 } else { |
| 1666 this.fireTrack('track', inEvent, p); |
| 1667 } |
| 1668 p.lastMoveEvent = inEvent; |
| 1669 } |
| 1670 }, |
| 1671 up: function(inEvent) { |
| 1672 var p = pointermap.get(inEvent.pointerId); |
| 1673 if (p) { |
| 1674 if (p.tracking) { |
| 1675 this.fireTrack('trackend', inEvent, p); |
| 1676 } |
| 1677 pointermap.delete(inEvent.pointerId); |
| 1678 } |
| 1679 } |
| 1680 }; |
| 1681 dispatcher.registerGesture('track', track); |
| 1682 })(window.PolymerGestures); |
| 1683 |
| 1684 /* |
| 1685 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 1686 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 1687 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 1688 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 1689 * Code distributed by Google as part of the polymer project is also |
| 1690 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 1691 */ |
| 1692 |
| 1693 /** |
| 1694 * This event is fired when a pointer is held down for 200ms. |
| 1695 * |
| 1696 * @module PointerGestures |
| 1697 * @submodule Events |
| 1698 * @class hold |
| 1699 */ |
| 1700 /** |
| 1701 * Type of pointer that made the holding event. |
| 1702 * @type String |
| 1703 * @property pointerType |
| 1704 */ |
| 1705 /** |
| 1706 * Screen X axis position of the held pointer |
| 1707 * @type Number |
| 1708 * @property clientX |
| 1709 */ |
| 1710 /** |
| 1711 * Screen Y axis position of the held pointer |
| 1712 * @type Number |
| 1713 * @property clientY |
| 1714 */ |
| 1715 /** |
| 1716 * Type of pointer that made the holding event. |
| 1717 * @type String |
| 1718 * @property pointerType |
| 1719 */ |
| 1720 /** |
| 1721 * This event is fired every 200ms while a pointer is held down. |
| 1722 * |
| 1723 * @class holdpulse |
| 1724 * @extends hold |
| 1725 */ |
| 1726 /** |
| 1727 * Milliseconds pointer has been held down. |
| 1728 * @type Number |
| 1729 * @property holdTime |
| 1730 */ |
| 1731 /** |
| 1732 * This event is fired when a held pointer is released or moved. |
| 1733 * |
| 1734 * @class released |
| 1735 */ |
| 1736 |
| 1737 (function(scope) { |
| 1738 var dispatcher = scope.dispatcher; |
| 1739 var eventFactory = scope.eventFactory; |
| 1740 var hold = { |
| 1741 // wait at least HOLD_DELAY ms between hold and pulse events |
| 1742 HOLD_DELAY: 200, |
| 1743 // pointer can move WIGGLE_THRESHOLD pixels before not counting as a hold |
| 1744 WIGGLE_THRESHOLD: 16, |
| 1745 events: [ |
| 1746 'down', |
| 1747 'move', |
| 1748 'up', |
| 1749 ], |
| 1750 heldPointer: null, |
| 1751 holdJob: null, |
| 1752 pulse: function() { |
| 1753 var hold = Date.now() - this.heldPointer.timeStamp; |
| 1754 var type = this.held ? 'holdpulse' : 'hold'; |
| 1755 this.fireHold(type, hold); |
| 1756 this.held = true; |
| 1757 }, |
| 1758 cancel: function() { |
| 1759 clearInterval(this.holdJob); |
| 1760 if (this.held) { |
| 1761 this.fireHold('release'); |
| 1762 } |
| 1763 this.held = false; |
| 1764 this.heldPointer = null; |
| 1765 this.target = null; |
| 1766 this.holdJob = null; |
| 1767 }, |
| 1768 down: function(inEvent) { |
| 1769 if (inEvent.isPrimary && !this.heldPointer) { |
| 1770 this.heldPointer = inEvent; |
| 1771 this.target = inEvent.target; |
| 1772 this.holdJob = setInterval(this.pulse.bind(this), this.HOLD_DELAY); |
| 1773 } |
| 1774 }, |
| 1775 up: function(inEvent) { |
| 1776 if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId)
{ |
| 1777 this.cancel(); |
| 1778 } |
| 1779 }, |
| 1780 move: function(inEvent) { |
| 1781 if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId)
{ |
| 1782 var x = inEvent.clientX - this.heldPointer.clientX; |
| 1783 var y = inEvent.clientY - this.heldPointer.clientY; |
| 1784 if ((x * x + y * y) > this.WIGGLE_THRESHOLD) { |
| 1785 this.cancel(); |
| 1786 } |
| 1787 } |
| 1788 }, |
| 1789 fireHold: function(inType, inHoldTime) { |
| 1790 var p = { |
| 1791 bubbles: true, |
| 1792 cancelable: true, |
| 1793 pointerType: this.heldPointer.pointerType, |
| 1794 pointerId: this.heldPointer.pointerId, |
| 1795 x: this.heldPointer.clientX, |
| 1796 y: this.heldPointer.clientY |
| 1797 }; |
| 1798 if (inHoldTime) { |
| 1799 p.holdTime = inHoldTime; |
| 1800 } |
| 1801 var e = eventFactory.makeGestureEvent(inType, p); |
| 1802 this.target.dispatchEvent(e); |
| 1803 } |
| 1804 }; |
| 1805 dispatcher.registerGesture('hold', hold); |
| 1806 })(window.PolymerGestures); |
| 1807 |
| 1808 /* |
| 1809 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 1810 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 1811 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 1812 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 1813 * Code distributed by Google as part of the polymer project is also |
| 1814 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 1815 */ |
| 1816 |
| 1817 /** |
| 1818 * This event is fired when a pointer quickly goes down and up, and is used to |
| 1819 * denote activation. |
| 1820 * |
| 1821 * Any gesture event can prevent the tap event from being created by calling |
| 1822 * `event.preventTap`. |
| 1823 * |
| 1824 * Any pointer event can prevent the tap by setting the `tapPrevented` property |
| 1825 * on itself. |
| 1826 * |
| 1827 * @module PointerGestures |
| 1828 * @submodule Events |
| 1829 * @class tap |
| 1830 */ |
| 1831 /** |
| 1832 * X axis position of the tap. |
| 1833 * @property x |
| 1834 * @type Number |
| 1835 */ |
| 1836 /** |
| 1837 * Y axis position of the tap. |
| 1838 * @property y |
| 1839 * @type Number |
| 1840 */ |
| 1841 /** |
| 1842 * Type of the pointer that made the tap. |
| 1843 * @property pointerType |
| 1844 * @type String |
| 1845 */ |
| 1846 (function(scope) { |
| 1847 var dispatcher = scope.dispatcher; |
| 1848 var eventFactory = scope.eventFactory; |
| 1849 var pointermap = new scope.PointerMap(); |
| 1850 var tap = { |
| 1851 events: [ |
| 1852 'down', |
| 1853 'up' |
| 1854 ], |
| 1855 down: function(inEvent) { |
| 1856 if (inEvent.isPrimary && !inEvent.tapPrevented) { |
| 1857 pointermap.set(inEvent.pointerId, { |
| 1858 target: inEvent.target, |
| 1859 buttons: inEvent.buttons, |
| 1860 x: inEvent.clientX, |
| 1861 y: inEvent.clientY |
| 1862 }); |
| 1863 } |
| 1864 }, |
| 1865 shouldTap: function(e, downState) { |
| 1866 if (e.pointerType === 'mouse') { |
| 1867 // only allow left click to tap for mouse |
| 1868 return downState.buttons === 1; |
| 1869 } |
| 1870 return !e.tapPrevented; |
| 1871 }, |
| 1872 up: function(inEvent) { |
| 1873 var start = pointermap.get(inEvent.pointerId); |
| 1874 if (start && this.shouldTap(inEvent, start)) { |
| 1875 // up.relatedTarget is target currently under finger |
| 1876 var t = scope.targetFinding.LCA(start.target, inEvent.relatedTarget); |
| 1877 if (t) { |
| 1878 var e = eventFactory.makeGestureEvent('tap', { |
| 1879 bubbles: true, |
| 1880 cancelable: true, |
| 1881 x: inEvent.clientX, |
| 1882 y: inEvent.clientY, |
| 1883 detail: inEvent.detail, |
| 1884 pointerType: inEvent.pointerType, |
| 1885 pointerId: inEvent.pointerId, |
| 1886 altKey: inEvent.altKey, |
| 1887 ctrlKey: inEvent.ctrlKey, |
| 1888 metaKey: inEvent.metaKey, |
| 1889 shiftKey: inEvent.shiftKey |
| 1890 }); |
| 1891 t.dispatchEvent(e); |
| 1892 } |
| 1893 } |
| 1894 pointermap.delete(inEvent.pointerId); |
| 1895 } |
| 1896 }; |
| 1897 // patch eventFactory to remove id from tap's pointermap for preventTap calls |
| 1898 eventFactory.preventTap = function(e) { |
| 1899 return function() { |
| 1900 e.tapPrevented = true; |
| 1901 pointermap.delete(e.pointerId); |
| 1902 }; |
| 1903 }; |
| 1904 dispatcher.registerGesture('tap', tap); |
| 1905 })(window.PolymerGestures); |
| 1906 |
| 1907 /* |
| 1908 Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com> |
| 1909 Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com> |
| 1910 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> |
| 1911 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be> |
| 1912 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl> |
| 1913 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com> |
| 1914 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com> |
| 1915 Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com> |
| 1916 Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com> |
| 1917 |
| 1918 Redistribution and use in source and binary forms, with or without |
| 1919 modification, are permitted provided that the following conditions are met: |
| 1920 |
| 1921 * Redistributions of source code must retain the above copyright |
| 1922 notice, this list of conditions and the following disclaimer. |
| 1923 * Redistributions in binary form must reproduce the above copyright |
| 1924 notice, this list of conditions and the following disclaimer in the |
| 1925 documentation and/or other materials provided with the distribution. |
| 1926 |
| 1927 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 1928 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 1929 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 1930 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY |
| 1931 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 1932 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 1933 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 1934 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 1935 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 1936 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 1937 */ |
| 1938 |
| 1939 (function (global) { |
| 1940 'use strict'; |
| 1941 |
| 1942 var Token, |
| 1943 TokenName, |
| 1944 Syntax, |
| 1945 Messages, |
| 1946 source, |
| 1947 index, |
| 1948 length, |
| 1949 delegate, |
| 1950 lookahead, |
| 1951 state; |
| 1952 |
| 1953 Token = { |
| 1954 BooleanLiteral: 1, |
| 1955 EOF: 2, |
| 1956 Identifier: 3, |
| 1957 Keyword: 4, |
| 1958 NullLiteral: 5, |
| 1959 NumericLiteral: 6, |
| 1960 Punctuator: 7, |
| 1961 StringLiteral: 8 |
| 1962 }; |
| 1963 |
| 1964 TokenName = {}; |
| 1965 TokenName[Token.BooleanLiteral] = 'Boolean'; |
| 1966 TokenName[Token.EOF] = '<end>'; |
| 1967 TokenName[Token.Identifier] = 'Identifier'; |
| 1968 TokenName[Token.Keyword] = 'Keyword'; |
| 1969 TokenName[Token.NullLiteral] = 'Null'; |
| 1970 TokenName[Token.NumericLiteral] = 'Numeric'; |
| 1971 TokenName[Token.Punctuator] = 'Punctuator'; |
| 1972 TokenName[Token.StringLiteral] = 'String'; |
| 1973 |
| 1974 Syntax = { |
| 1975 ArrayExpression: 'ArrayExpression', |
| 1976 BinaryExpression: 'BinaryExpression', |
| 1977 CallExpression: 'CallExpression', |
| 1978 ConditionalExpression: 'ConditionalExpression', |
| 1979 EmptyStatement: 'EmptyStatement', |
| 1980 ExpressionStatement: 'ExpressionStatement', |
| 1981 Identifier: 'Identifier', |
| 1982 Literal: 'Literal', |
| 1983 LabeledStatement: 'LabeledStatement', |
| 1984 LogicalExpression: 'LogicalExpression', |
| 1985 MemberExpression: 'MemberExpression', |
| 1986 ObjectExpression: 'ObjectExpression', |
| 1987 Program: 'Program', |
| 1988 Property: 'Property', |
| 1989 ThisExpression: 'ThisExpression', |
| 1990 UnaryExpression: 'UnaryExpression' |
| 1991 }; |
| 1992 |
| 1993 // Error messages should be identical to V8. |
| 1994 Messages = { |
| 1995 UnexpectedToken: 'Unexpected token %0', |
| 1996 UnknownLabel: 'Undefined label \'%0\'', |
| 1997 Redeclaration: '%0 \'%1\' has already been declared' |
| 1998 }; |
| 1999 |
| 2000 // Ensure the condition is true, otherwise throw an error. |
| 2001 // This is only to have a better contract semantic, i.e. another safety net |
| 2002 // to catch a logic error. The condition shall be fulfilled in normal case. |
| 2003 // Do NOT use this to enforce a certain condition on any user input. |
| 2004 |
| 2005 function assert(condition, message) { |
| 2006 if (!condition) { |
| 2007 throw new Error('ASSERT: ' + message); |
| 2008 } |
| 2009 } |
| 2010 |
| 2011 function isDecimalDigit(ch) { |
| 2012 return (ch >= 48 && ch <= 57); // 0..9 |
| 2013 } |
| 2014 |
| 2015 |
| 2016 // 7.2 White Space |
| 2017 |
| 2018 function isWhiteSpace(ch) { |
| 2019 return (ch === 32) || // space |
| 2020 (ch === 9) || // tab |
| 2021 (ch === 0xB) || |
| 2022 (ch === 0xC) || |
| 2023 (ch === 0xA0) || |
| 2024 (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u
2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCod
e(ch)) > 0); |
| 2025 } |
| 2026 |
| 2027 // 7.3 Line Terminators |
| 2028 |
| 2029 function isLineTerminator(ch) { |
| 2030 return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029); |
| 2031 } |
| 2032 |
| 2033 // 7.6 Identifier Names and Identifiers |
| 2034 |
| 2035 function isIdentifierStart(ch) { |
| 2036 return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) |
| 2037 (ch >= 65 && ch <= 90) || // A..Z |
| 2038 (ch >= 97 && ch <= 122); // a..z |
| 2039 } |
| 2040 |
| 2041 function isIdentifierPart(ch) { |
| 2042 return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) |
| 2043 (ch >= 65 && ch <= 90) || // A..Z |
| 2044 (ch >= 97 && ch <= 122) || // a..z |
| 2045 (ch >= 48 && ch <= 57); // 0..9 |
| 2046 } |
| 2047 |
| 2048 // 7.6.1.1 Keywords |
| 2049 |
| 2050 function isKeyword(id) { |
| 2051 return (id === 'this') |
| 2052 } |
| 2053 |
| 2054 // 7.4 Comments |
| 2055 |
| 2056 function skipWhitespace() { |
| 2057 while (index < length && isWhiteSpace(source.charCodeAt(index))) { |
| 2058 ++index; |
| 2059 } |
| 2060 } |
| 2061 |
| 2062 function getIdentifier() { |
| 2063 var start, ch; |
| 2064 |
| 2065 start = index++; |
| 2066 while (index < length) { |
| 2067 ch = source.charCodeAt(index); |
| 2068 if (isIdentifierPart(ch)) { |
| 2069 ++index; |
| 2070 } else { |
| 2071 break; |
| 2072 } |
| 2073 } |
| 2074 |
| 2075 return source.slice(start, index); |
| 2076 } |
| 2077 |
| 2078 function scanIdentifier() { |
| 2079 var start, id, type; |
| 2080 |
| 2081 start = index; |
| 2082 |
| 2083 id = getIdentifier(); |
| 2084 |
| 2085 // There is no keyword or literal with only one character. |
| 2086 // Thus, it must be an identifier. |
| 2087 if (id.length === 1) { |
| 2088 type = Token.Identifier; |
| 2089 } else if (isKeyword(id)) { |
| 2090 type = Token.Keyword; |
| 2091 } else if (id === 'null') { |
| 2092 type = Token.NullLiteral; |
| 2093 } else if (id === 'true' || id === 'false') { |
| 2094 type = Token.BooleanLiteral; |
| 2095 } else { |
| 2096 type = Token.Identifier; |
| 2097 } |
| 2098 |
| 2099 return { |
| 2100 type: type, |
| 2101 value: id, |
| 2102 range: [start, index] |
| 2103 }; |
| 2104 } |
| 2105 |
| 2106 |
| 2107 // 7.7 Punctuators |
| 2108 |
| 2109 function scanPunctuator() { |
| 2110 var start = index, |
| 2111 code = source.charCodeAt(index), |
| 2112 code2, |
| 2113 ch1 = source[index], |
| 2114 ch2; |
| 2115 |
| 2116 switch (code) { |
| 2117 |
| 2118 // Check for most common single-character punctuators. |
| 2119 case 46: // . dot |
| 2120 case 40: // ( open bracket |
| 2121 case 41: // ) close bracket |
| 2122 case 59: // ; semicolon |
| 2123 case 44: // , comma |
| 2124 case 123: // { open curly brace |
| 2125 case 125: // } close curly brace |
| 2126 case 91: // [ |
| 2127 case 93: // ] |
| 2128 case 58: // : |
| 2129 case 63: // ? |
| 2130 ++index; |
| 2131 return { |
| 2132 type: Token.Punctuator, |
| 2133 value: String.fromCharCode(code), |
| 2134 range: [start, index] |
| 2135 }; |
| 2136 |
| 2137 default: |
| 2138 code2 = source.charCodeAt(index + 1); |
| 2139 |
| 2140 // '=' (char #61) marks an assignment or comparison operator. |
| 2141 if (code2 === 61) { |
| 2142 switch (code) { |
| 2143 case 37: // % |
| 2144 case 38: // & |
| 2145 case 42: // *: |
| 2146 case 43: // + |
| 2147 case 45: // - |
| 2148 case 47: // / |
| 2149 case 60: // < |
| 2150 case 62: // > |
| 2151 case 124: // | |
| 2152 index += 2; |
| 2153 return { |
| 2154 type: Token.Punctuator, |
| 2155 value: String.fromCharCode(code) + String.fromCharCode(c
ode2), |
| 2156 range: [start, index] |
| 2157 }; |
| 2158 |
| 2159 case 33: // ! |
| 2160 case 61: // = |
| 2161 index += 2; |
| 2162 |
| 2163 // !== and === |
| 2164 if (source.charCodeAt(index) === 61) { |
| 2165 ++index; |
| 2166 } |
| 2167 return { |
| 2168 type: Token.Punctuator, |
| 2169 value: source.slice(start, index), |
| 2170 range: [start, index] |
| 2171 }; |
| 2172 default: |
| 2173 break; |
| 2174 } |
| 2175 } |
| 2176 break; |
| 2177 } |
| 2178 |
| 2179 // Peek more characters. |
| 2180 |
| 2181 ch2 = source[index + 1]; |
| 2182 |
| 2183 // Other 2-character punctuators: && || |
| 2184 |
| 2185 if (ch1 === ch2 && ('&|'.indexOf(ch1) >= 0)) { |
| 2186 index += 2; |
| 2187 return { |
| 2188 type: Token.Punctuator, |
| 2189 value: ch1 + ch2, |
| 2190 range: [start, index] |
| 2191 }; |
| 2192 } |
| 2193 |
| 2194 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { |
| 2195 ++index; |
| 2196 return { |
| 2197 type: Token.Punctuator, |
| 2198 value: ch1, |
| 2199 range: [start, index] |
| 2200 }; |
| 2201 } |
| 2202 |
| 2203 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); |
| 2204 } |
| 2205 |
| 2206 // 7.8.3 Numeric Literals |
| 2207 function scanNumericLiteral() { |
| 2208 var number, start, ch; |
| 2209 |
| 2210 ch = source[index]; |
| 2211 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), |
| 2212 'Numeric literal must start with a decimal digit or a decimal point'
); |
| 2213 |
| 2214 start = index; |
| 2215 number = ''; |
| 2216 if (ch !== '.') { |
| 2217 number = source[index++]; |
| 2218 ch = source[index]; |
| 2219 |
| 2220 // Hex number starts with '0x'. |
| 2221 // Octal number starts with '0'. |
| 2222 if (number === '0') { |
| 2223 // decimal number starts with '0' such as '09' is illegal. |
| 2224 if (ch && isDecimalDigit(ch.charCodeAt(0))) { |
| 2225 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); |
| 2226 } |
| 2227 } |
| 2228 |
| 2229 while (isDecimalDigit(source.charCodeAt(index))) { |
| 2230 number += source[index++]; |
| 2231 } |
| 2232 ch = source[index]; |
| 2233 } |
| 2234 |
| 2235 if (ch === '.') { |
| 2236 number += source[index++]; |
| 2237 while (isDecimalDigit(source.charCodeAt(index))) { |
| 2238 number += source[index++]; |
| 2239 } |
| 2240 ch = source[index]; |
| 2241 } |
| 2242 |
| 2243 if (ch === 'e' || ch === 'E') { |
| 2244 number += source[index++]; |
| 2245 |
| 2246 ch = source[index]; |
| 2247 if (ch === '+' || ch === '-') { |
| 2248 number += source[index++]; |
| 2249 } |
| 2250 if (isDecimalDigit(source.charCodeAt(index))) { |
| 2251 while (isDecimalDigit(source.charCodeAt(index))) { |
| 2252 number += source[index++]; |
| 2253 } |
| 2254 } else { |
| 2255 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); |
| 2256 } |
| 2257 } |
| 2258 |
| 2259 if (isIdentifierStart(source.charCodeAt(index))) { |
| 2260 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); |
| 2261 } |
| 2262 |
| 2263 return { |
| 2264 type: Token.NumericLiteral, |
| 2265 value: parseFloat(number), |
| 2266 range: [start, index] |
| 2267 }; |
| 2268 } |
| 2269 |
| 2270 // 7.8.4 String Literals |
| 2271 |
| 2272 function scanStringLiteral() { |
| 2273 var str = '', quote, start, ch, octal = false; |
| 2274 |
| 2275 quote = source[index]; |
| 2276 assert((quote === '\'' || quote === '"'), |
| 2277 'String literal must starts with a quote'); |
| 2278 |
| 2279 start = index; |
| 2280 ++index; |
| 2281 |
| 2282 while (index < length) { |
| 2283 ch = source[index++]; |
| 2284 |
| 2285 if (ch === quote) { |
| 2286 quote = ''; |
| 2287 break; |
| 2288 } else if (ch === '\\') { |
| 2289 ch = source[index++]; |
| 2290 if (!ch || !isLineTerminator(ch.charCodeAt(0))) { |
| 2291 switch (ch) { |
| 2292 case 'n': |
| 2293 str += '\n'; |
| 2294 break; |
| 2295 case 'r': |
| 2296 str += '\r'; |
| 2297 break; |
| 2298 case 't': |
| 2299 str += '\t'; |
| 2300 break; |
| 2301 case 'b': |
| 2302 str += '\b'; |
| 2303 break; |
| 2304 case 'f': |
| 2305 str += '\f'; |
| 2306 break; |
| 2307 case 'v': |
| 2308 str += '\x0B'; |
| 2309 break; |
| 2310 |
| 2311 default: |
| 2312 str += ch; |
| 2313 break; |
| 2314 } |
| 2315 } else { |
| 2316 if (ch === '\r' && source[index] === '\n') { |
| 2317 ++index; |
| 2318 } |
| 2319 } |
| 2320 } else if (isLineTerminator(ch.charCodeAt(0))) { |
| 2321 break; |
| 2322 } else { |
| 2323 str += ch; |
| 2324 } |
| 2325 } |
| 2326 |
| 2327 if (quote !== '') { |
| 2328 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); |
| 2329 } |
| 2330 |
| 2331 return { |
| 2332 type: Token.StringLiteral, |
| 2333 value: str, |
| 2334 octal: octal, |
| 2335 range: [start, index] |
| 2336 }; |
| 2337 } |
| 2338 |
| 2339 function isIdentifierName(token) { |
| 2340 return token.type === Token.Identifier || |
| 2341 token.type === Token.Keyword || |
| 2342 token.type === Token.BooleanLiteral || |
| 2343 token.type === Token.NullLiteral; |
| 2344 } |
| 2345 |
| 2346 function advance() { |
| 2347 var ch; |
| 2348 |
| 2349 skipWhitespace(); |
| 2350 |
| 2351 if (index >= length) { |
| 2352 return { |
| 2353 type: Token.EOF, |
| 2354 range: [index, index] |
| 2355 }; |
| 2356 } |
| 2357 |
| 2358 ch = source.charCodeAt(index); |
| 2359 |
| 2360 // Very common: ( and ) and ; |
| 2361 if (ch === 40 || ch === 41 || ch === 58) { |
| 2362 return scanPunctuator(); |
| 2363 } |
| 2364 |
| 2365 // String literal starts with single quote (#39) or double quote (#34). |
| 2366 if (ch === 39 || ch === 34) { |
| 2367 return scanStringLiteral(); |
| 2368 } |
| 2369 |
| 2370 if (isIdentifierStart(ch)) { |
| 2371 return scanIdentifier(); |
| 2372 } |
| 2373 |
| 2374 // Dot (.) char #46 can also start a floating-point number, hence the ne
ed |
| 2375 // to check the next character. |
| 2376 if (ch === 46) { |
| 2377 if (isDecimalDigit(source.charCodeAt(index + 1))) { |
| 2378 return scanNumericLiteral(); |
| 2379 } |
| 2380 return scanPunctuator(); |
| 2381 } |
| 2382 |
| 2383 if (isDecimalDigit(ch)) { |
| 2384 return scanNumericLiteral(); |
| 2385 } |
| 2386 |
| 2387 return scanPunctuator(); |
| 2388 } |
| 2389 |
| 2390 function lex() { |
| 2391 var token; |
| 2392 |
| 2393 token = lookahead; |
| 2394 index = token.range[1]; |
| 2395 |
| 2396 lookahead = advance(); |
| 2397 |
| 2398 index = token.range[1]; |
| 2399 |
| 2400 return token; |
| 2401 } |
| 2402 |
| 2403 function peek() { |
| 2404 var pos; |
| 2405 |
| 2406 pos = index; |
| 2407 lookahead = advance(); |
| 2408 index = pos; |
| 2409 } |
| 2410 |
| 2411 // Throw an exception |
| 2412 |
| 2413 function throwError(token, messageFormat) { |
| 2414 var error, |
| 2415 args = Array.prototype.slice.call(arguments, 2), |
| 2416 msg = messageFormat.replace( |
| 2417 /%(\d)/g, |
| 2418 function (whole, index) { |
| 2419 assert(index < args.length, 'Message reference must be in ra
nge'); |
| 2420 return args[index]; |
| 2421 } |
| 2422 ); |
| 2423 |
| 2424 error = new Error(msg); |
| 2425 error.index = index; |
| 2426 error.description = msg; |
| 2427 throw error; |
| 2428 } |
| 2429 |
| 2430 // Throw an exception because of the token. |
| 2431 |
| 2432 function throwUnexpected(token) { |
| 2433 throwError(token, Messages.UnexpectedToken, token.value); |
| 2434 } |
| 2435 |
| 2436 // Expect the next token to match the specified punctuator. |
| 2437 // If not, an exception will be thrown. |
| 2438 |
| 2439 function expect(value) { |
| 2440 var token = lex(); |
| 2441 if (token.type !== Token.Punctuator || token.value !== value) { |
| 2442 throwUnexpected(token); |
| 2443 } |
| 2444 } |
| 2445 |
| 2446 // Return true if the next token matches the specified punctuator. |
| 2447 |
| 2448 function match(value) { |
| 2449 return lookahead.type === Token.Punctuator && lookahead.value === value; |
| 2450 } |
| 2451 |
| 2452 // Return true if the next token matches the specified keyword |
| 2453 |
| 2454 function matchKeyword(keyword) { |
| 2455 return lookahead.type === Token.Keyword && lookahead.value === keyword; |
| 2456 } |
| 2457 |
| 2458 function consumeSemicolon() { |
| 2459 // Catch the very common case first: immediately a semicolon (char #59). |
| 2460 if (source.charCodeAt(index) === 59) { |
| 2461 lex(); |
| 2462 return; |
| 2463 } |
| 2464 |
| 2465 skipWhitespace(); |
| 2466 |
| 2467 if (match(';')) { |
| 2468 lex(); |
| 2469 return; |
| 2470 } |
| 2471 |
| 2472 if (lookahead.type !== Token.EOF && !match('}')) { |
| 2473 throwUnexpected(lookahead); |
| 2474 } |
| 2475 } |
| 2476 |
| 2477 // 11.1.4 Array Initialiser |
| 2478 |
| 2479 function parseArrayInitialiser() { |
| 2480 var elements = []; |
| 2481 |
| 2482 expect('['); |
| 2483 |
| 2484 while (!match(']')) { |
| 2485 if (match(',')) { |
| 2486 lex(); |
| 2487 elements.push(null); |
| 2488 } else { |
| 2489 elements.push(parseExpression()); |
| 2490 |
| 2491 if (!match(']')) { |
| 2492 expect(','); |
| 2493 } |
| 2494 } |
| 2495 } |
| 2496 |
| 2497 expect(']'); |
| 2498 |
| 2499 return delegate.createArrayExpression(elements); |
| 2500 } |
| 2501 |
| 2502 // 11.1.5 Object Initialiser |
| 2503 |
| 2504 function parseObjectPropertyKey() { |
| 2505 var token; |
| 2506 |
| 2507 skipWhitespace(); |
| 2508 token = lex(); |
| 2509 |
| 2510 // Note: This function is called only from parseObjectProperty(), where |
| 2511 // EOF and Punctuator tokens are already filtered out. |
| 2512 if (token.type === Token.StringLiteral || token.type === Token.NumericLi
teral) { |
| 2513 return delegate.createLiteral(token); |
| 2514 } |
| 2515 |
| 2516 return delegate.createIdentifier(token.value); |
| 2517 } |
| 2518 |
| 2519 function parseObjectProperty() { |
| 2520 var token, key; |
| 2521 |
| 2522 token = lookahead; |
| 2523 skipWhitespace(); |
| 2524 |
| 2525 if (token.type === Token.EOF || token.type === Token.Punctuator) { |
| 2526 throwUnexpected(token); |
| 2527 } |
| 2528 |
| 2529 key = parseObjectPropertyKey(); |
| 2530 expect(':'); |
| 2531 return delegate.createProperty('init', key, parseExpression()); |
| 2532 } |
| 2533 |
| 2534 function parseObjectInitialiser() { |
| 2535 var properties = []; |
| 2536 |
| 2537 expect('{'); |
| 2538 |
| 2539 while (!match('}')) { |
| 2540 properties.push(parseObjectProperty()); |
| 2541 |
| 2542 if (!match('}')) { |
| 2543 expect(','); |
| 2544 } |
| 2545 } |
| 2546 |
| 2547 expect('}'); |
| 2548 |
| 2549 return delegate.createObjectExpression(properties); |
| 2550 } |
| 2551 |
| 2552 // 11.1.6 The Grouping Operator |
| 2553 |
| 2554 function parseGroupExpression() { |
| 2555 var expr; |
| 2556 |
| 2557 expect('('); |
| 2558 |
| 2559 expr = parseExpression(); |
| 2560 |
| 2561 expect(')'); |
| 2562 |
| 2563 return expr; |
| 2564 } |
| 2565 |
| 2566 |
| 2567 // 11.1 Primary Expressions |
| 2568 |
| 2569 function parsePrimaryExpression() { |
| 2570 var type, token, expr; |
| 2571 |
| 2572 if (match('(')) { |
| 2573 return parseGroupExpression(); |
| 2574 } |
| 2575 |
| 2576 type = lookahead.type; |
| 2577 |
| 2578 if (type === Token.Identifier) { |
| 2579 expr = delegate.createIdentifier(lex().value); |
| 2580 } else if (type === Token.StringLiteral || type === Token.NumericLiteral
) { |
| 2581 expr = delegate.createLiteral(lex()); |
| 2582 } else if (type === Token.Keyword) { |
| 2583 if (matchKeyword('this')) { |
| 2584 lex(); |
| 2585 expr = delegate.createThisExpression(); |
| 2586 } |
| 2587 } else if (type === Token.BooleanLiteral) { |
| 2588 token = lex(); |
| 2589 token.value = (token.value === 'true'); |
| 2590 expr = delegate.createLiteral(token); |
| 2591 } else if (type === Token.NullLiteral) { |
| 2592 token = lex(); |
| 2593 token.value = null; |
| 2594 expr = delegate.createLiteral(token); |
| 2595 } else if (match('[')) { |
| 2596 expr = parseArrayInitialiser(); |
| 2597 } else if (match('{')) { |
| 2598 expr = parseObjectInitialiser(); |
| 2599 } |
| 2600 |
| 2601 if (expr) { |
| 2602 return expr; |
| 2603 } |
| 2604 |
| 2605 throwUnexpected(lex()); |
| 2606 } |
| 2607 |
| 2608 // 11.2 Left-Hand-Side Expressions |
| 2609 |
| 2610 function parseArguments() { |
| 2611 var args = []; |
| 2612 |
| 2613 expect('('); |
| 2614 |
| 2615 if (!match(')')) { |
| 2616 while (index < length) { |
| 2617 args.push(parseExpression()); |
| 2618 if (match(')')) { |
| 2619 break; |
| 2620 } |
| 2621 expect(','); |
| 2622 } |
| 2623 } |
| 2624 |
| 2625 expect(')'); |
| 2626 |
| 2627 return args; |
| 2628 } |
| 2629 |
| 2630 function parseNonComputedProperty() { |
| 2631 var token; |
| 2632 |
| 2633 token = lex(); |
| 2634 |
| 2635 if (!isIdentifierName(token)) { |
| 2636 throwUnexpected(token); |
| 2637 } |
| 2638 |
| 2639 return delegate.createIdentifier(token.value); |
| 2640 } |
| 2641 |
| 2642 function parseNonComputedMember() { |
| 2643 expect('.'); |
| 2644 |
| 2645 return parseNonComputedProperty(); |
| 2646 } |
| 2647 |
| 2648 function parseComputedMember() { |
| 2649 var expr; |
| 2650 |
| 2651 expect('['); |
| 2652 |
| 2653 expr = parseExpression(); |
| 2654 |
| 2655 expect(']'); |
| 2656 |
| 2657 return expr; |
| 2658 } |
| 2659 |
| 2660 function parseLeftHandSideExpression() { |
| 2661 var expr, property; |
| 2662 |
| 2663 expr = parsePrimaryExpression(); |
| 2664 |
| 2665 while (match('.') || match('[')) { |
| 2666 if (match('[')) { |
| 2667 property = parseComputedMember(); |
| 2668 expr = delegate.createMemberExpression('[', expr, property); |
| 2669 } else { |
| 2670 property = parseNonComputedMember(); |
| 2671 expr = delegate.createMemberExpression('.', expr, property); |
| 2672 } |
| 2673 } |
| 2674 |
| 2675 return expr; |
| 2676 } |
| 2677 |
| 2678 // 11.3 Postfix Expressions |
| 2679 |
| 2680 var parsePostfixExpression = parseLeftHandSideExpression; |
| 2681 |
| 2682 // 11.4 Unary Operators |
| 2683 |
| 2684 function parseUnaryExpression() { |
| 2685 var token, expr; |
| 2686 |
| 2687 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyw
ord) { |
| 2688 expr = parsePostfixExpression(); |
| 2689 } else if (match('+') || match('-') || match('!')) { |
| 2690 token = lex(); |
| 2691 expr = parseUnaryExpression(); |
| 2692 expr = delegate.createUnaryExpression(token.value, expr); |
| 2693 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeywor
d('typeof')) { |
| 2694 throwError({}, Messages.UnexpectedToken); |
| 2695 } else { |
| 2696 expr = parsePostfixExpression(); |
| 2697 } |
| 2698 |
| 2699 return expr; |
| 2700 } |
| 2701 |
| 2702 function binaryPrecedence(token) { |
| 2703 var prec = 0; |
| 2704 |
| 2705 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { |
| 2706 return 0; |
| 2707 } |
| 2708 |
| 2709 switch (token.value) { |
| 2710 case '||': |
| 2711 prec = 1; |
| 2712 break; |
| 2713 |
| 2714 case '&&': |
| 2715 prec = 2; |
| 2716 break; |
| 2717 |
| 2718 case '==': |
| 2719 case '!=': |
| 2720 case '===': |
| 2721 case '!==': |
| 2722 prec = 6; |
| 2723 break; |
| 2724 |
| 2725 case '<': |
| 2726 case '>': |
| 2727 case '<=': |
| 2728 case '>=': |
| 2729 case 'instanceof': |
| 2730 prec = 7; |
| 2731 break; |
| 2732 |
| 2733 case 'in': |
| 2734 prec = 7; |
| 2735 break; |
| 2736 |
| 2737 case '+': |
| 2738 case '-': |
| 2739 prec = 9; |
| 2740 break; |
| 2741 |
| 2742 case '*': |
| 2743 case '/': |
| 2744 case '%': |
| 2745 prec = 11; |
| 2746 break; |
| 2747 |
| 2748 default: |
| 2749 break; |
| 2750 } |
| 2751 |
| 2752 return prec; |
| 2753 } |
| 2754 |
| 2755 // 11.5 Multiplicative Operators |
| 2756 // 11.6 Additive Operators |
| 2757 // 11.7 Bitwise Shift Operators |
| 2758 // 11.8 Relational Operators |
| 2759 // 11.9 Equality Operators |
| 2760 // 11.10 Binary Bitwise Operators |
| 2761 // 11.11 Binary Logical Operators |
| 2762 |
| 2763 function parseBinaryExpression() { |
| 2764 var expr, token, prec, stack, right, operator, left, i; |
| 2765 |
| 2766 left = parseUnaryExpression(); |
| 2767 |
| 2768 token = lookahead; |
| 2769 prec = binaryPrecedence(token); |
| 2770 if (prec === 0) { |
| 2771 return left; |
| 2772 } |
| 2773 token.prec = prec; |
| 2774 lex(); |
| 2775 |
| 2776 right = parseUnaryExpression(); |
| 2777 |
| 2778 stack = [left, token, right]; |
| 2779 |
| 2780 while ((prec = binaryPrecedence(lookahead)) > 0) { |
| 2781 |
| 2782 // Reduce: make a binary expression from the three topmost entries. |
| 2783 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec))
{ |
| 2784 right = stack.pop(); |
| 2785 operator = stack.pop().value; |
| 2786 left = stack.pop(); |
| 2787 expr = delegate.createBinaryExpression(operator, left, right); |
| 2788 stack.push(expr); |
| 2789 } |
| 2790 |
| 2791 // Shift. |
| 2792 token = lex(); |
| 2793 token.prec = prec; |
| 2794 stack.push(token); |
| 2795 expr = parseUnaryExpression(); |
| 2796 stack.push(expr); |
| 2797 } |
| 2798 |
| 2799 // Final reduce to clean-up the stack. |
| 2800 i = stack.length - 1; |
| 2801 expr = stack[i]; |
| 2802 while (i > 1) { |
| 2803 expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i -
2], expr); |
| 2804 i -= 2; |
| 2805 } |
| 2806 |
| 2807 return expr; |
| 2808 } |
| 2809 |
| 2810 |
| 2811 // 11.12 Conditional Operator |
| 2812 |
| 2813 function parseConditionalExpression() { |
| 2814 var expr, consequent, alternate; |
| 2815 |
| 2816 expr = parseBinaryExpression(); |
| 2817 |
| 2818 if (match('?')) { |
| 2819 lex(); |
| 2820 consequent = parseConditionalExpression(); |
| 2821 expect(':'); |
| 2822 alternate = parseConditionalExpression(); |
| 2823 |
| 2824 expr = delegate.createConditionalExpression(expr, consequent, altern
ate); |
| 2825 } |
| 2826 |
| 2827 return expr; |
| 2828 } |
| 2829 |
| 2830 // Simplification since we do not support AssignmentExpression. |
| 2831 var parseExpression = parseConditionalExpression; |
| 2832 |
| 2833 // Polymer Syntax extensions |
| 2834 |
| 2835 // Filter :: |
| 2836 // Identifier |
| 2837 // Identifier "(" ")" |
| 2838 // Identifier "(" FilterArguments ")" |
| 2839 |
| 2840 function parseFilter() { |
| 2841 var identifier, args; |
| 2842 |
| 2843 identifier = lex(); |
| 2844 |
| 2845 if (identifier.type !== Token.Identifier) { |
| 2846 throwUnexpected(identifier); |
| 2847 } |
| 2848 |
| 2849 args = match('(') ? parseArguments() : []; |
| 2850 |
| 2851 return delegate.createFilter(identifier.value, args); |
| 2852 } |
| 2853 |
| 2854 // Filters :: |
| 2855 // "|" Filter |
| 2856 // Filters "|" Filter |
| 2857 |
| 2858 function parseFilters() { |
| 2859 while (match('|')) { |
| 2860 lex(); |
| 2861 parseFilter(); |
| 2862 } |
| 2863 } |
| 2864 |
| 2865 // TopLevel :: |
| 2866 // LabelledExpressions |
| 2867 // AsExpression |
| 2868 // InExpression |
| 2869 // FilterExpression |
| 2870 |
| 2871 // AsExpression :: |
| 2872 // FilterExpression as Identifier |
| 2873 |
| 2874 // InExpression :: |
| 2875 // Identifier, Identifier in FilterExpression |
| 2876 // Identifier in FilterExpression |
| 2877 |
| 2878 // FilterExpression :: |
| 2879 // Expression |
| 2880 // Expression Filters |
| 2881 |
| 2882 function parseTopLevel() { |
| 2883 skipWhitespace(); |
| 2884 peek(); |
| 2885 |
| 2886 var expr = parseExpression(); |
| 2887 if (expr) { |
| 2888 if (lookahead.value === ',' || lookahead.value == 'in' && |
| 2889 expr.type === Syntax.Identifier) { |
| 2890 parseInExpression(expr); |
| 2891 } else { |
| 2892 parseFilters(); |
| 2893 if (lookahead.value === 'as') { |
| 2894 parseAsExpression(expr); |
| 2895 } else { |
| 2896 delegate.createTopLevel(expr); |
| 2897 } |
| 2898 } |
| 2899 } |
| 2900 |
| 2901 if (lookahead.type !== Token.EOF) { |
| 2902 throwUnexpected(lookahead); |
| 2903 } |
| 2904 } |
| 2905 |
| 2906 function parseAsExpression(expr) { |
| 2907 lex(); // as |
| 2908 var identifier = lex().value; |
| 2909 delegate.createAsExpression(expr, identifier); |
| 2910 } |
| 2911 |
| 2912 function parseInExpression(identifier) { |
| 2913 var indexName; |
| 2914 if (lookahead.value === ',') { |
| 2915 lex(); |
| 2916 if (lookahead.type !== Token.Identifier) |
| 2917 throwUnexpected(lookahead); |
| 2918 indexName = lex().value; |
| 2919 } |
| 2920 |
| 2921 lex(); // in |
| 2922 var expr = parseExpression(); |
| 2923 parseFilters(); |
| 2924 delegate.createInExpression(identifier.name, indexName, expr); |
| 2925 } |
| 2926 |
| 2927 function parse(code, inDelegate) { |
| 2928 delegate = inDelegate; |
| 2929 source = code; |
| 2930 index = 0; |
| 2931 length = source.length; |
| 2932 lookahead = null; |
| 2933 state = { |
| 2934 labelSet: {} |
| 2935 }; |
| 2936 |
| 2937 return parseTopLevel(); |
| 2938 } |
| 2939 |
| 2940 global.esprima = { |
| 2941 parse: parse |
| 2942 }; |
| 2943 })(this); |
| 2944 |
| 2945 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 2946 // This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 2947 // The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 2948 // The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 2949 // Code distributed by Google as part of the polymer project is also |
| 2950 // subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 2951 |
| 2952 (function (global) { |
| 2953 'use strict'; |
| 2954 |
| 2955 function prepareBinding(expressionText, name, node, filterRegistry) { |
| 2956 var expression; |
| 2957 try { |
| 2958 expression = getExpression(expressionText); |
| 2959 if (expression.scopeIdent && |
| 2960 (node.nodeType !== Node.ELEMENT_NODE || |
| 2961 node.tagName !== 'TEMPLATE' || |
| 2962 (name !== 'bind' && name !== 'repeat'))) { |
| 2963 throw Error('as and in can only be used within <template bind/repeat>'); |
| 2964 } |
| 2965 } catch (ex) { |
| 2966 console.error('Invalid expression syntax: ' + expressionText, ex); |
| 2967 return; |
| 2968 } |
| 2969 |
| 2970 return function(model, node, oneTime) { |
| 2971 var binding = expression.getBinding(model, filterRegistry, oneTime); |
| 2972 if (expression.scopeIdent && binding) { |
| 2973 node.polymerExpressionScopeIdent_ = expression.scopeIdent; |
| 2974 if (expression.indexIdent) |
| 2975 node.polymerExpressionIndexIdent_ = expression.indexIdent; |
| 2976 } |
| 2977 |
| 2978 return binding; |
| 2979 } |
| 2980 } |
| 2981 |
| 2982 // TODO(rafaelw): Implement simple LRU. |
| 2983 var expressionParseCache = Object.create(null); |
| 2984 |
| 2985 function getExpression(expressionText) { |
| 2986 var expression = expressionParseCache[expressionText]; |
| 2987 if (!expression) { |
| 2988 var delegate = new ASTDelegate(); |
| 2989 esprima.parse(expressionText, delegate); |
| 2990 expression = new Expression(delegate); |
| 2991 expressionParseCache[expressionText] = expression; |
| 2992 } |
| 2993 return expression; |
| 2994 } |
| 2995 |
| 2996 function Literal(value) { |
| 2997 this.value = value; |
| 2998 this.valueFn_ = undefined; |
| 2999 } |
| 3000 |
| 3001 Literal.prototype = { |
| 3002 valueFn: function() { |
| 3003 if (!this.valueFn_) { |
| 3004 var value = this.value; |
| 3005 this.valueFn_ = function() { |
| 3006 return value; |
| 3007 } |
| 3008 } |
| 3009 |
| 3010 return this.valueFn_; |
| 3011 } |
| 3012 } |
| 3013 |
| 3014 function IdentPath(name) { |
| 3015 this.name = name; |
| 3016 this.path = Path.get(name); |
| 3017 } |
| 3018 |
| 3019 IdentPath.prototype = { |
| 3020 valueFn: function() { |
| 3021 if (!this.valueFn_) { |
| 3022 var name = this.name; |
| 3023 var path = this.path; |
| 3024 this.valueFn_ = function(model, observer) { |
| 3025 if (observer) |
| 3026 observer.addPath(model, path); |
| 3027 |
| 3028 return path.getValueFrom(model); |
| 3029 } |
| 3030 } |
| 3031 |
| 3032 return this.valueFn_; |
| 3033 }, |
| 3034 |
| 3035 setValue: function(model, newValue) { |
| 3036 if (this.path.length == 1); |
| 3037 model = findScope(model, this.path[0]); |
| 3038 |
| 3039 return this.path.setValueFrom(model, newValue); |
| 3040 } |
| 3041 }; |
| 3042 |
| 3043 function MemberExpression(object, property, accessor) { |
| 3044 this.dynamicDeps = typeof object == 'function' || |
| 3045 object.dynamicDeps || |
| 3046 (accessor == '[' && !(property instanceof Literal)); |
| 3047 |
| 3048 // convert literal computed property access where literal value is a value |
| 3049 // path to ident dot-access. |
| 3050 if (accessor == '[' && |
| 3051 property instanceof Literal && |
| 3052 Path.get(property.value).valid) { |
| 3053 accessor = '.'; |
| 3054 property = new IdentPath(property.value); |
| 3055 } |
| 3056 |
| 3057 this.simplePath = |
| 3058 !this.dynamicDeps && |
| 3059 property instanceof IdentPath && |
| 3060 (object instanceof MemberExpression || object instanceof IdentPath); |
| 3061 |
| 3062 this.object = this.simplePath ? object : getFn(object); |
| 3063 this.property = accessor == '.' ? property : getFn(property); |
| 3064 } |
| 3065 |
| 3066 MemberExpression.prototype = { |
| 3067 get fullPath() { |
| 3068 if (!this.fullPath_) { |
| 3069 var last = this.object instanceof IdentPath ? |
| 3070 this.object.name : this.object.fullPath; |
| 3071 this.fullPath_ = Path.get(last + '.' + this.property.name); |
| 3072 } |
| 3073 |
| 3074 return this.fullPath_; |
| 3075 }, |
| 3076 |
| 3077 valueFn: function() { |
| 3078 if (!this.valueFn_) { |
| 3079 var object = this.object; |
| 3080 |
| 3081 if (this.simplePath) { |
| 3082 var path = this.fullPath; |
| 3083 |
| 3084 this.valueFn_ = function(model, observer) { |
| 3085 if (observer) |
| 3086 observer.addPath(model, path); |
| 3087 |
| 3088 return path.getValueFrom(model); |
| 3089 }; |
| 3090 } else if (this.property instanceof IdentPath) { |
| 3091 var path = Path.get(this.property.name); |
| 3092 |
| 3093 this.valueFn_ = function(model, observer) { |
| 3094 var context = object(model, observer); |
| 3095 |
| 3096 if (observer) |
| 3097 observer.addPath(context, path); |
| 3098 |
| 3099 return path.getValueFrom(context); |
| 3100 } |
| 3101 } else { |
| 3102 // Computed property. |
| 3103 var property = this.property; |
| 3104 |
| 3105 this.valueFn_ = function(model, observer) { |
| 3106 var context = object(model, observer); |
| 3107 var propName = property(model, observer); |
| 3108 if (observer) |
| 3109 observer.addPath(context, propName); |
| 3110 |
| 3111 return context ? context[propName] : undefined; |
| 3112 }; |
| 3113 } |
| 3114 } |
| 3115 return this.valueFn_; |
| 3116 }, |
| 3117 |
| 3118 setValue: function(model, newValue) { |
| 3119 if (this.simplePath) { |
| 3120 this.fullPath.setValueFrom(model, newValue); |
| 3121 return newValue; |
| 3122 } |
| 3123 |
| 3124 var object = this.object(model); |
| 3125 var propName = this.property instanceof IdentPath ? this.property.name : |
| 3126 this.property(model); |
| 3127 return object[propName] = newValue; |
| 3128 } |
| 3129 }; |
| 3130 |
| 3131 function Filter(name, args) { |
| 3132 this.name = name; |
| 3133 this.args = []; |
| 3134 for (var i = 0; i < args.length; i++) { |
| 3135 this.args[i] = getFn(args[i]); |
| 3136 } |
| 3137 } |
| 3138 |
| 3139 Filter.prototype = { |
| 3140 transform: function(value, toModelDirection, filterRegistry, model, |
| 3141 observer) { |
| 3142 var fn = filterRegistry[this.name]; |
| 3143 var context = model; |
| 3144 if (fn) { |
| 3145 context = undefined; |
| 3146 } else { |
| 3147 fn = context[this.name]; |
| 3148 if (!fn) { |
| 3149 console.error('Cannot find filter: ' + this.name); |
| 3150 return; |
| 3151 } |
| 3152 } |
| 3153 |
| 3154 // If toModelDirection is falsey, then the "normal" (dom-bound) direction |
| 3155 // is used. Otherwise, it looks for a 'toModel' property function on the |
| 3156 // object. |
| 3157 if (toModelDirection) { |
| 3158 fn = fn.toModel; |
| 3159 } else if (typeof fn.toDOM == 'function') { |
| 3160 fn = fn.toDOM; |
| 3161 } |
| 3162 |
| 3163 if (typeof fn != 'function') { |
| 3164 console.error('No ' + (toModelDirection ? 'toModel' : 'toDOM') + |
| 3165 ' found on' + this.name); |
| 3166 return; |
| 3167 } |
| 3168 |
| 3169 var args = [value]; |
| 3170 for (var i = 0; i < this.args.length; i++) { |
| 3171 args[i + 1] = getFn(this.args[i])(model, observer); |
| 3172 } |
| 3173 |
| 3174 return fn.apply(context, args); |
| 3175 } |
| 3176 }; |
| 3177 |
| 3178 function notImplemented() { throw Error('Not Implemented'); } |
| 3179 |
| 3180 var unaryOperators = { |
| 3181 '+': function(v) { return +v; }, |
| 3182 '-': function(v) { return -v; }, |
| 3183 '!': function(v) { return !v; } |
| 3184 }; |
| 3185 |
| 3186 var binaryOperators = { |
| 3187 '+': function(l, r) { return l+r; }, |
| 3188 '-': function(l, r) { return l-r; }, |
| 3189 '*': function(l, r) { return l*r; }, |
| 3190 '/': function(l, r) { return l/r; }, |
| 3191 '%': function(l, r) { return l%r; }, |
| 3192 '<': function(l, r) { return l<r; }, |
| 3193 '>': function(l, r) { return l>r; }, |
| 3194 '<=': function(l, r) { return l<=r; }, |
| 3195 '>=': function(l, r) { return l>=r; }, |
| 3196 '==': function(l, r) { return l==r; }, |
| 3197 '!=': function(l, r) { return l!=r; }, |
| 3198 '===': function(l, r) { return l===r; }, |
| 3199 '!==': function(l, r) { return l!==r; }, |
| 3200 '&&': function(l, r) { return l&&r; }, |
| 3201 '||': function(l, r) { return l||r; }, |
| 3202 }; |
| 3203 |
| 3204 function getFn(arg) { |
| 3205 return typeof arg == 'function' ? arg : arg.valueFn(); |
| 3206 } |
| 3207 |
| 3208 function ASTDelegate() { |
| 3209 this.expression = null; |
| 3210 this.filters = []; |
| 3211 this.deps = {}; |
| 3212 this.currentPath = undefined; |
| 3213 this.scopeIdent = undefined; |
| 3214 this.indexIdent = undefined; |
| 3215 this.dynamicDeps = false; |
| 3216 } |
| 3217 |
| 3218 ASTDelegate.prototype = { |
| 3219 createUnaryExpression: function(op, argument) { |
| 3220 if (!unaryOperators[op]) |
| 3221 throw Error('Disallowed operator: ' + op); |
| 3222 |
| 3223 argument = getFn(argument); |
| 3224 |
| 3225 return function(model, observer) { |
| 3226 return unaryOperators[op](argument(model, observer)); |
| 3227 }; |
| 3228 }, |
| 3229 |
| 3230 createBinaryExpression: function(op, left, right) { |
| 3231 if (!binaryOperators[op]) |
| 3232 throw Error('Disallowed operator: ' + op); |
| 3233 |
| 3234 left = getFn(left); |
| 3235 right = getFn(right); |
| 3236 |
| 3237 return function(model, observer) { |
| 3238 return binaryOperators[op](left(model, observer), |
| 3239 right(model, observer)); |
| 3240 }; |
| 3241 }, |
| 3242 |
| 3243 createConditionalExpression: function(test, consequent, alternate) { |
| 3244 test = getFn(test); |
| 3245 consequent = getFn(consequent); |
| 3246 alternate = getFn(alternate); |
| 3247 |
| 3248 return function(model, observer) { |
| 3249 return test(model, observer) ? |
| 3250 consequent(model, observer) : alternate(model, observer); |
| 3251 } |
| 3252 }, |
| 3253 |
| 3254 createIdentifier: function(name) { |
| 3255 var ident = new IdentPath(name); |
| 3256 ident.type = 'Identifier'; |
| 3257 return ident; |
| 3258 }, |
| 3259 |
| 3260 createMemberExpression: function(accessor, object, property) { |
| 3261 var ex = new MemberExpression(object, property, accessor); |
| 3262 if (ex.dynamicDeps) |
| 3263 this.dynamicDeps = true; |
| 3264 return ex; |
| 3265 }, |
| 3266 |
| 3267 createLiteral: function(token) { |
| 3268 return new Literal(token.value); |
| 3269 }, |
| 3270 |
| 3271 createArrayExpression: function(elements) { |
| 3272 for (var i = 0; i < elements.length; i++) |
| 3273 elements[i] = getFn(elements[i]); |
| 3274 |
| 3275 return function(model, observer) { |
| 3276 var arr = [] |
| 3277 for (var i = 0; i < elements.length; i++) |
| 3278 arr.push(elements[i](model, observer)); |
| 3279 return arr; |
| 3280 } |
| 3281 }, |
| 3282 |
| 3283 createProperty: function(kind, key, value) { |
| 3284 return { |
| 3285 key: key instanceof IdentPath ? key.name : key.value, |
| 3286 value: value |
| 3287 }; |
| 3288 }, |
| 3289 |
| 3290 createObjectExpression: function(properties) { |
| 3291 for (var i = 0; i < properties.length; i++) |
| 3292 properties[i].value = getFn(properties[i].value); |
| 3293 |
| 3294 return function(model, observer) { |
| 3295 var obj = {}; |
| 3296 for (var i = 0; i < properties.length; i++) |
| 3297 obj[properties[i].key] = properties[i].value(model, observer); |
| 3298 return obj; |
| 3299 } |
| 3300 }, |
| 3301 |
| 3302 createFilter: function(name, args) { |
| 3303 this.filters.push(new Filter(name, args)); |
| 3304 }, |
| 3305 |
| 3306 createAsExpression: function(expression, scopeIdent) { |
| 3307 this.expression = expression; |
| 3308 this.scopeIdent = scopeIdent; |
| 3309 }, |
| 3310 |
| 3311 createInExpression: function(scopeIdent, indexIdent, expression) { |
| 3312 this.expression = expression; |
| 3313 this.scopeIdent = scopeIdent; |
| 3314 this.indexIdent = indexIdent; |
| 3315 }, |
| 3316 |
| 3317 createTopLevel: function(expression) { |
| 3318 this.expression = expression; |
| 3319 }, |
| 3320 |
| 3321 createThisExpression: notImplemented |
| 3322 } |
| 3323 |
| 3324 function ConstantObservable(value) { |
| 3325 this.value_ = value; |
| 3326 } |
| 3327 |
| 3328 ConstantObservable.prototype = { |
| 3329 open: function() { return this.value_; }, |
| 3330 discardChanges: function() { return this.value_; }, |
| 3331 deliver: function() {}, |
| 3332 close: function() {}, |
| 3333 } |
| 3334 |
| 3335 function Expression(delegate) { |
| 3336 this.scopeIdent = delegate.scopeIdent; |
| 3337 this.indexIdent = delegate.indexIdent; |
| 3338 |
| 3339 if (!delegate.expression) |
| 3340 throw Error('No expression found.'); |
| 3341 |
| 3342 this.expression = delegate.expression; |
| 3343 getFn(this.expression); // forces enumeration of path dependencies |
| 3344 |
| 3345 this.filters = delegate.filters; |
| 3346 this.dynamicDeps = delegate.dynamicDeps; |
| 3347 } |
| 3348 |
| 3349 Expression.prototype = { |
| 3350 getBinding: function(model, filterRegistry, oneTime) { |
| 3351 if (oneTime) |
| 3352 return this.getValue(model, undefined, filterRegistry); |
| 3353 |
| 3354 var observer = new CompoundObserver(); |
| 3355 // captures deps. |
| 3356 var firstValue = this.getValue(model, observer, filterRegistry); |
| 3357 var firstTime = true; |
| 3358 var self = this; |
| 3359 |
| 3360 function valueFn() { |
| 3361 // deps cannot have changed on first value retrieval. |
| 3362 if (firstTime) { |
| 3363 firstTime = false; |
| 3364 return firstValue; |
| 3365 } |
| 3366 |
| 3367 if (self.dynamicDeps) |
| 3368 observer.startReset(); |
| 3369 |
| 3370 var value = self.getValue(model, |
| 3371 self.dynamicDeps ? observer : undefined, |
| 3372 filterRegistry); |
| 3373 if (self.dynamicDeps) |
| 3374 observer.finishReset(); |
| 3375 |
| 3376 return value; |
| 3377 } |
| 3378 |
| 3379 function setValueFn(newValue) { |
| 3380 self.setValue(model, newValue, filterRegistry); |
| 3381 return newValue; |
| 3382 } |
| 3383 |
| 3384 return new ObserverTransform(observer, valueFn, setValueFn, true); |
| 3385 }, |
| 3386 |
| 3387 getValue: function(model, observer, filterRegistry) { |
| 3388 var value = getFn(this.expression)(model, observer); |
| 3389 for (var i = 0; i < this.filters.length; i++) { |
| 3390 value = this.filters[i].transform(value, false, filterRegistry, model, |
| 3391 observer); |
| 3392 } |
| 3393 |
| 3394 return value; |
| 3395 }, |
| 3396 |
| 3397 setValue: function(model, newValue, filterRegistry) { |
| 3398 var count = this.filters ? this.filters.length : 0; |
| 3399 while (count-- > 0) { |
| 3400 newValue = this.filters[count].transform(newValue, true, filterRegistry, |
| 3401 model); |
| 3402 } |
| 3403 |
| 3404 if (this.expression.setValue) |
| 3405 return this.expression.setValue(model, newValue); |
| 3406 } |
| 3407 } |
| 3408 |
| 3409 /** |
| 3410 * Converts a style property name to a css property name. For example: |
| 3411 * "WebkitUserSelect" to "-webkit-user-select" |
| 3412 */ |
| 3413 function convertStylePropertyName(name) { |
| 3414 return String(name).replace(/[A-Z]/g, function(c) { |
| 3415 return '-' + c.toLowerCase(); |
| 3416 }); |
| 3417 } |
| 3418 |
| 3419 var parentScopeName = '@' + Math.random().toString(36).slice(2); |
| 3420 |
| 3421 // Single ident paths must bind directly to the appropriate scope object. |
| 3422 // I.e. Pushed values in two-bindings need to be assigned to the actual model |
| 3423 // object. |
| 3424 function findScope(model, prop) { |
| 3425 while (model[parentScopeName] && |
| 3426 !Object.prototype.hasOwnProperty.call(model, prop)) { |
| 3427 model = model[parentScopeName]; |
| 3428 } |
| 3429 |
| 3430 return model; |
| 3431 } |
| 3432 |
| 3433 function isLiteralExpression(pathString) { |
| 3434 switch (pathString) { |
| 3435 case '': |
| 3436 return false; |
| 3437 |
| 3438 case 'false': |
| 3439 case 'null': |
| 3440 case 'true': |
| 3441 return true; |
| 3442 } |
| 3443 |
| 3444 if (!isNaN(Number(pathString))) |
| 3445 return true; |
| 3446 |
| 3447 return false; |
| 3448 }; |
| 3449 |
| 3450 function PolymerExpressions() {} |
| 3451 |
| 3452 PolymerExpressions.prototype = { |
| 3453 // "built-in" filters |
| 3454 styleObject: function(value) { |
| 3455 var parts = []; |
| 3456 for (var key in value) { |
| 3457 parts.push(convertStylePropertyName(key) + ': ' + value[key]); |
| 3458 } |
| 3459 return parts.join('; '); |
| 3460 }, |
| 3461 |
| 3462 tokenList: function(value) { |
| 3463 var tokens = []; |
| 3464 for (var key in value) { |
| 3465 if (value[key]) |
| 3466 tokens.push(key); |
| 3467 } |
| 3468 return tokens.join(' '); |
| 3469 }, |
| 3470 |
| 3471 // binding delegate API |
| 3472 prepareInstancePositionChanged: function(template) { |
| 3473 var indexIdent = template.polymerExpressionIndexIdent_; |
| 3474 if (!indexIdent) |
| 3475 return; |
| 3476 |
| 3477 return function(templateInstance, index) { |
| 3478 templateInstance.model[indexIdent] = index; |
| 3479 }; |
| 3480 }, |
| 3481 |
| 3482 prepareBinding: function(pathString, name, node) { |
| 3483 var path = Path.get(pathString); |
| 3484 |
| 3485 if (!isLiteralExpression(pathString) && path.valid) { |
| 3486 if (path.length == 1) { |
| 3487 return function(model, node, oneTime) { |
| 3488 if (oneTime) |
| 3489 return path.getValueFrom(model); |
| 3490 |
| 3491 var scope = findScope(model, path[0]); |
| 3492 return new PathObserver(scope, path); |
| 3493 }; |
| 3494 } |
| 3495 return; // bail out early if pathString is simple path. |
| 3496 } |
| 3497 |
| 3498 return prepareBinding(pathString, name, node, this); |
| 3499 }, |
| 3500 |
| 3501 prepareInstanceModel: function(template) { |
| 3502 var scopeName = template.polymerExpressionScopeIdent_; |
| 3503 if (!scopeName) |
| 3504 return; |
| 3505 |
| 3506 var parentScope = template.templateInstance ? |
| 3507 template.templateInstance.model : |
| 3508 template.model; |
| 3509 |
| 3510 var indexName = template.polymerExpressionIndexIdent_; |
| 3511 |
| 3512 return function(model) { |
| 3513 var scope = Object.create(parentScope); |
| 3514 scope[scopeName] = model; |
| 3515 scope[indexName] = undefined; |
| 3516 scope[parentScopeName] = parentScope; |
| 3517 return scope; |
| 3518 }; |
| 3519 } |
| 3520 }; |
| 3521 |
| 3522 global.PolymerExpressions = PolymerExpressions; |
| 3523 if (global.exposeGetExpression) |
| 3524 global.getExpression_ = getExpression; |
| 3525 |
| 3526 })(this); |
| 3527 |
| 3528 /* |
| 3529 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 3530 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 3531 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3532 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3533 * Code distributed by Google as part of the polymer project is also |
| 3534 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 3535 */ |
| 3536 Polymer = { |
| 3537 version: '0.3.1-604ba08' |
| 3538 }; |
| 3539 |
| 3540 /* |
| 3541 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 3542 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 3543 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3544 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3545 * Code distributed by Google as part of the polymer project is also |
| 3546 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
12 */ | 3547 */ |
13 | 3548 |
14 // TODO(sorvell): this ensures Polymer is an object and not a function | 3549 // TODO(sorvell): this ensures Polymer is an object and not a function |
15 // Platform is currently defining it as a function to allow for async loading | 3550 // Platform is currently defining it as a function to allow for async loading |
16 // of polymer; once we refine the loading process this likely goes away. | 3551 // of polymer; once we refine the loading process this likely goes away. |
17 if (typeof window.Polymer === 'function') { | 3552 if (typeof window.Polymer === 'function') { |
18 Polymer = {}; | 3553 Polymer = {}; |
19 } | 3554 } |
20 | 3555 |
21 | 3556 |
22 /* | 3557 /* |
23 * Copyright 2013 The Polymer Authors. All rights reserved. | 3558 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
24 * Use of this source code is governed by a BSD-style | 3559 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
25 * license that can be found in the LICENSE file. | 3560 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3561 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3562 * Code distributed by Google as part of the polymer project is also |
| 3563 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
26 */ | 3564 */ |
| 3565 |
27 (function(scope) { | 3566 (function(scope) { |
28 | 3567 |
29 // copy own properties from 'api' to 'prototype, with name hinting for 'super' | 3568 // copy own properties from 'api' to 'prototype, with name hinting for 'super' |
30 function extend(prototype, api) { | 3569 function extend(prototype, api) { |
31 if (prototype && api) { | 3570 if (prototype && api) { |
32 // use only own properties of 'api' | 3571 // use only own properties of 'api' |
33 Object.getOwnPropertyNames(api).forEach(function(n) { | 3572 Object.getOwnPropertyNames(api).forEach(function(n) { |
34 // acquire property descriptor | 3573 // acquire property descriptor |
35 var pd = Object.getOwnPropertyDescriptor(api, n); | 3574 var pd = Object.getOwnPropertyDescriptor(api, n); |
36 if (pd) { | 3575 if (pd) { |
37 // clone property via descriptor | 3576 // clone property via descriptor |
38 Object.defineProperty(prototype, n, pd); | 3577 Object.defineProperty(prototype, n, pd); |
39 // cache name-of-method for 'super' engine | 3578 // cache name-of-method for 'super' engine |
40 if (typeof pd.value == 'function') { | 3579 if (typeof pd.value == 'function') { |
41 // hint the 'super' engine | 3580 // hint the 'super' engine |
42 pd.value.nom = n; | 3581 pd.value.nom = n; |
43 } | 3582 } |
44 } | 3583 } |
45 }); | 3584 }); |
46 } | 3585 } |
47 return prototype; | 3586 return prototype; |
48 } | 3587 } |
49 | 3588 |
50 // exports | 3589 // exports |
51 | 3590 |
52 scope.extend = extend; | 3591 scope.extend = extend; |
53 | 3592 |
54 })(Polymer); | 3593 })(Polymer); |
55 | 3594 |
56 /* | 3595 /* |
57 * Copyright 2013 The Polymer Authors. All rights reserved. | 3596 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
58 * Use of this source code is governed by a BSD-style | 3597 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
59 * license that can be found in the LICENSE file. | 3598 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3599 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3600 * Code distributed by Google as part of the polymer project is also |
| 3601 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
60 */ | 3602 */ |
61 | 3603 |
62 (function(scope) { | 3604 (function(scope) { |
63 | 3605 |
64 // usage | 3606 // usage |
65 | 3607 |
66 // invoke cb.call(this) in 100ms, unless the job is re-registered, | 3608 // invoke cb.call(this) in 100ms, unless the job is re-registered, |
67 // which resets the timer | 3609 // which resets the timer |
68 // | 3610 // |
69 // this.myJob = this.job(this.myJob, cb, 100) | 3611 // this.myJob = this.job(this.myJob, cb, 100) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 return job; | 3656 return job; |
115 } | 3657 } |
116 | 3658 |
117 // exports | 3659 // exports |
118 | 3660 |
119 scope.job = job; | 3661 scope.job = job; |
120 | 3662 |
121 })(Polymer); | 3663 })(Polymer); |
122 | 3664 |
123 /* | 3665 /* |
124 * Copyright 2013 The Polymer Authors. All rights reserved. | 3666 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
125 * Use of this source code is governed by a BSD-style | 3667 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
126 * license that can be found in the LICENSE file. | 3668 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3669 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3670 * Code distributed by Google as part of the polymer project is also |
| 3671 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
127 */ | 3672 */ |
| 3673 |
128 (function(scope) { | 3674 (function(scope) { |
129 | 3675 |
130 var registry = {}; | 3676 var registry = {}; |
131 | 3677 |
132 HTMLElement.register = function(tag, prototype) { | 3678 HTMLElement.register = function(tag, prototype) { |
133 registry[tag] = prototype; | 3679 registry[tag] = prototype; |
134 } | 3680 } |
135 | 3681 |
136 // get prototype mapped to node <tag> | 3682 // get prototype mapped to node <tag> |
137 HTMLElement.getPrototypeForTag = function(tag) { | 3683 HTMLElement.getPrototypeForTag = function(tag) { |
(...skipping 11 matching lines...) Expand all Loading... |
149 | 3695 |
150 // TODO(sorvell): remove when we're sure imports does not need | 3696 // TODO(sorvell): remove when we're sure imports does not need |
151 // to load stylesheets | 3697 // to load stylesheets |
152 /* | 3698 /* |
153 HTMLImports.importer.preloadSelectors += | 3699 HTMLImports.importer.preloadSelectors += |
154 ', polymer-element link[rel=stylesheet]'; | 3700 ', polymer-element link[rel=stylesheet]'; |
155 */ | 3701 */ |
156 })(Polymer); | 3702 })(Polymer); |
157 | 3703 |
158 /* | 3704 /* |
159 * Copyright 2013 The Polymer Authors. All rights reserved. | 3705 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
160 * Use of this source code is governed by a BSD-style | 3706 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
161 * license that can be found in the LICENSE file. | 3707 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3708 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3709 * Code distributed by Google as part of the polymer project is also |
| 3710 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
162 */ | 3711 */ |
| 3712 |
163 (function(scope) { | 3713 (function(scope) { |
164 // super | 3714 // super |
165 | 3715 |
166 // `arrayOfArgs` is an optional array of args like one might pass | 3716 // `arrayOfArgs` is an optional array of args like one might pass |
167 // to `Function.apply` | 3717 // to `Function.apply` |
168 | 3718 |
169 // TODO(sjmiles): | 3719 // TODO(sjmiles): |
170 // $super must be installed on an instance or prototype chain | 3720 // $super must be installed on an instance or prototype chain |
171 // as `super`, and invoked via `this`, e.g. | 3721 // as `super`, and invoked via `this`, e.g. |
172 // `this.super();` | 3722 // `this.super();` |
(...skipping 16 matching lines...) Expand all Loading... |
189 var _super = caller._super; | 3739 var _super = caller._super; |
190 if (!_super) { | 3740 if (!_super) { |
191 if (!nom) { | 3741 if (!nom) { |
192 nom = caller.nom = nameInThis.call(this, caller); | 3742 nom = caller.nom = nameInThis.call(this, caller); |
193 } | 3743 } |
194 if (!nom) { | 3744 if (!nom) { |
195 console.warn('called super() on a method not installed declaratively (
has no .nom property)'); | 3745 console.warn('called super() on a method not installed declaratively (
has no .nom property)'); |
196 } | 3746 } |
197 // super prototype is either cached or we have to find it | 3747 // super prototype is either cached or we have to find it |
198 // by searching __proto__ (at the 'top') | 3748 // by searching __proto__ (at the 'top') |
| 3749 // invariant: because we cache _super on fn below, we never reach |
| 3750 // here from inside a series of calls to super(), so it's ok to |
| 3751 // start searching from the prototype of 'this' (at the 'top') |
| 3752 // we must never memoize a null super for this reason |
199 _super = memoizeSuper(caller, nom, getPrototypeOf(this)); | 3753 _super = memoizeSuper(caller, nom, getPrototypeOf(this)); |
200 } | 3754 } |
201 if (!_super) { | 3755 // our super function |
202 // if _super is falsey, there is no super implementation | 3756 var fn = _super[nom]; |
203 //console.warn('called $super(' + nom + ') where there is no super imple
mentation'); | 3757 if (fn) { |
204 } else { | |
205 // our super function | |
206 var fn = _super[nom]; | |
207 // memoize information so 'fn' can call 'super' | 3758 // memoize information so 'fn' can call 'super' |
208 if (!fn._super) { | 3759 if (!fn._super) { |
| 3760 // must not memoize null, or we lose our invariant above |
209 memoizeSuper(fn, nom, _super); | 3761 memoizeSuper(fn, nom, _super); |
210 } | 3762 } |
211 // invoke the inherited method | 3763 // invoke the inherited method |
212 // if 'fn' is not function valued, this will throw | 3764 // if 'fn' is not function valued, this will throw |
213 return fn.apply(this, arrayOfArgs || []); | 3765 return fn.apply(this, arrayOfArgs || []); |
214 } | 3766 } |
215 } | 3767 } |
216 | 3768 |
217 function nextSuper(proto, name, caller) { | |
218 // look for an inherited prototype that implements name | |
219 while (proto) { | |
220 if ((proto[name] !== caller) && proto[name]) { | |
221 return proto; | |
222 } | |
223 proto = getPrototypeOf(proto); | |
224 } | |
225 } | |
226 | |
227 function memoizeSuper(method, name, proto) { | |
228 // find and cache next prototype containing `name` | |
229 // we need the prototype so we can do another lookup | |
230 // from here | |
231 method._super = nextSuper(proto, name, method); | |
232 if (method._super) { | |
233 // _super is a prototype, the actual method is _super[name] | |
234 // tag super method with it's name for further lookups | |
235 method._super[name].nom = name; | |
236 } | |
237 return method._super; | |
238 } | |
239 | |
240 function nameInThis(value) { | 3769 function nameInThis(value) { |
241 var p = this.__proto__; | 3770 var p = this.__proto__; |
242 while (p && p !== HTMLElement.prototype) { | 3771 while (p && p !== HTMLElement.prototype) { |
243 // TODO(sjmiles): getOwnPropertyNames is absurdly expensive | 3772 // TODO(sjmiles): getOwnPropertyNames is absurdly expensive |
244 var n$ = Object.getOwnPropertyNames(p); | 3773 var n$ = Object.getOwnPropertyNames(p); |
245 for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) { | 3774 for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) { |
246 var d = Object.getOwnPropertyDescriptor(p, n); | 3775 var d = Object.getOwnPropertyDescriptor(p, n); |
247 if (typeof d.value === 'function' && d.value === value) { | 3776 if (typeof d.value === 'function' && d.value === value) { |
248 return n; | 3777 return n; |
249 } | 3778 } |
250 } | 3779 } |
251 p = p.__proto__; | 3780 p = p.__proto__; |
252 } | 3781 } |
253 } | 3782 } |
254 | 3783 |
| 3784 function memoizeSuper(method, name, proto) { |
| 3785 // find and cache next prototype containing `name` |
| 3786 // we need the prototype so we can do another lookup |
| 3787 // from here |
| 3788 var s = nextSuper(proto, name, method); |
| 3789 if (s[name]) { |
| 3790 // `s` is a prototype, the actual method is `s[name]` |
| 3791 // tag super method with it's name for quicker lookups |
| 3792 s[name].nom = name; |
| 3793 } |
| 3794 return method._super = s; |
| 3795 } |
| 3796 |
| 3797 function nextSuper(proto, name, caller) { |
| 3798 // look for an inherited prototype that implements name |
| 3799 while (proto) { |
| 3800 if ((proto[name] !== caller) && proto[name]) { |
| 3801 return proto; |
| 3802 } |
| 3803 proto = getPrototypeOf(proto); |
| 3804 } |
| 3805 // must not return null, or we lose our invariant above |
| 3806 // in this case, a super() call was invoked where no superclass |
| 3807 // method exists |
| 3808 // TODO(sjmiles): thow an exception? |
| 3809 return Object; |
| 3810 } |
| 3811 |
255 // NOTE: In some platforms (IE10) the prototype chain is faked via | 3812 // NOTE: In some platforms (IE10) the prototype chain is faked via |
256 // __proto__. Therefore, always get prototype via __proto__ instead of | 3813 // __proto__. Therefore, always get prototype via __proto__ instead of |
257 // the more standard Object.getPrototypeOf. | 3814 // the more standard Object.getPrototypeOf. |
258 function getPrototypeOf(prototype) { | 3815 function getPrototypeOf(prototype) { |
259 return prototype.__proto__; | 3816 return prototype.__proto__; |
260 } | 3817 } |
261 | 3818 |
262 // utility function to precompute name tags for functions | 3819 // utility function to precompute name tags for functions |
263 // in a (unchained) prototype | 3820 // in a (unchained) prototype |
264 function hintSuper(prototype) { | 3821 function hintSuper(prototype) { |
265 // tag functions with their prototype name to optimize | 3822 // tag functions with their prototype name to optimize |
266 // super call invocations | 3823 // super call invocations |
267 for (var n in prototype) { | 3824 for (var n in prototype) { |
268 var pd = Object.getOwnPropertyDescriptor(prototype, n); | 3825 var pd = Object.getOwnPropertyDescriptor(prototype, n); |
269 if (pd && typeof pd.value === 'function') { | 3826 if (pd && typeof pd.value === 'function') { |
270 pd.value.nom = n; | 3827 pd.value.nom = n; |
271 } | 3828 } |
272 } | 3829 } |
273 } | 3830 } |
274 | 3831 |
275 // exports | 3832 // exports |
276 | 3833 |
277 scope.super = $super; | 3834 scope.super = $super; |
278 | 3835 |
279 })(Polymer); | 3836 })(Polymer); |
280 | 3837 |
281 /* | 3838 /* |
282 * Copyright 2013 The Polymer Authors. All rights reserved. | 3839 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
283 * Use of this source code is governed by a BSD-style | 3840 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
284 * license that can be found in the LICENSE file. | 3841 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3842 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3843 * Code distributed by Google as part of the polymer project is also |
| 3844 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
285 */ | 3845 */ |
286 | 3846 |
287 (function(scope) { | 3847 (function(scope) { |
288 | 3848 |
289 var typeHandlers = { | 3849 var typeHandlers = { |
290 string: function(value) { | 3850 string: function(value) { |
291 return value; | 3851 return value; |
292 }, | 3852 }, |
293 date: function(value) { | 3853 date: function(value) { |
294 return new Date(Date.parse(value) || Date.now()); | 3854 return new Date(Date.parse(value) || Date.now()); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 return typeHandlers[inferredType](value, currentValue); | 3901 return typeHandlers[inferredType](value, currentValue); |
342 } | 3902 } |
343 | 3903 |
344 // exports | 3904 // exports |
345 | 3905 |
346 scope.deserializeValue = deserializeValue; | 3906 scope.deserializeValue = deserializeValue; |
347 | 3907 |
348 })(Polymer); | 3908 })(Polymer); |
349 | 3909 |
350 /* | 3910 /* |
351 * Copyright 2013 The Polymer Authors. All rights reserved. | 3911 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
352 * Use of this source code is governed by a BSD-style | 3912 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
353 * license that can be found in the LICENSE file. | 3913 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3914 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3915 * Code distributed by Google as part of the polymer project is also |
| 3916 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
354 */ | 3917 */ |
355 (function(scope) { | 3918 (function(scope) { |
356 | 3919 |
357 // imports | 3920 // imports |
358 | 3921 |
359 var extend = scope.extend; | 3922 var extend = scope.extend; |
360 | 3923 |
361 // module | 3924 // module |
362 | 3925 |
363 var api = {}; | 3926 var api = {}; |
364 | 3927 |
365 api.declaration = {}; | 3928 api.declaration = {}; |
366 api.instance = {}; | 3929 api.instance = {}; |
367 | 3930 |
368 api.publish = function(apis, prototype) { | 3931 api.publish = function(apis, prototype) { |
369 for (var n in apis) { | 3932 for (var n in apis) { |
370 extend(prototype, apis[n]); | 3933 extend(prototype, apis[n]); |
371 } | 3934 } |
372 } | 3935 }; |
373 | 3936 |
374 // exports | 3937 // exports |
375 | 3938 |
376 scope.api = api; | 3939 scope.api = api; |
377 | 3940 |
378 })(Polymer); | 3941 })(Polymer); |
379 | 3942 |
380 /* | 3943 /* |
381 * Copyright 2013 The Polymer Authors. All rights reserved. | 3944 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
382 * Use of this source code is governed by a BSD-style | 3945 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
383 * license that can be found in the LICENSE file. | 3946 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 3947 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 3948 * Code distributed by Google as part of the polymer project is also |
| 3949 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
384 */ | 3950 */ |
| 3951 |
385 (function(scope) { | 3952 (function(scope) { |
386 | 3953 |
387 var utils = { | 3954 var utils = { |
388 /** | 3955 /** |
389 * Invokes a function asynchronously. The context of the callback | 3956 * Invokes a function asynchronously. The context of the callback |
390 * function is bound to 'this' automatically. | 3957 * function is bound to 'this' automatically. |
391 * @method async | 3958 * @method async |
392 * @param {Function|String} method | 3959 * @param {Function|String} method |
393 * @param {any|Array} args | 3960 * @param {any|Array} args |
394 * @param {number} timeout | 3961 * @param {number} timeout |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 | 4041 |
475 // exports | 4042 // exports |
476 | 4043 |
477 scope.api.instance.utils = utils; | 4044 scope.api.instance.utils = utils; |
478 scope.nop = nop; | 4045 scope.nop = nop; |
479 scope.nob = nob; | 4046 scope.nob = nob; |
480 | 4047 |
481 })(Polymer); | 4048 })(Polymer); |
482 | 4049 |
483 /* | 4050 /* |
484 * Copyright 2013 The Polymer Authors. All rights reserved. | 4051 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
485 * Use of this source code is governed by a BSD-style | 4052 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
486 * license that can be found in the LICENSE file. | 4053 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4054 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4055 * Code distributed by Google as part of the polymer project is also |
| 4056 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
487 */ | 4057 */ |
488 | 4058 |
489 (function(scope) { | 4059 (function(scope) { |
490 | 4060 |
491 // imports | 4061 // imports |
492 | 4062 |
493 var log = window.logFlags || {}; | 4063 var log = window.logFlags || {}; |
494 var EVENT_PREFIX = 'on-'; | 4064 var EVENT_PREFIX = 'on-'; |
495 | 4065 |
496 // instance events api | 4066 // instance events api |
497 var events = { | 4067 var events = { |
498 // read-only | 4068 // read-only |
499 EVENT_PREFIX: EVENT_PREFIX, | 4069 EVENT_PREFIX: EVENT_PREFIX, |
500 // event listeners on host | 4070 // event listeners on host |
501 addHostListeners: function() { | 4071 addHostListeners: function() { |
502 var events = this.eventDelegates; | 4072 var events = this.eventDelegates; |
503 log.events && (Object.keys(events).length > 0) && console.log('[%s] addHos
tListeners:', this.localName, events); | 4073 log.events && (Object.keys(events).length > 0) && console.log('[%s] addHos
tListeners:', this.localName, events); |
504 // NOTE: host events look like bindings but really are not; | 4074 // NOTE: host events look like bindings but really are not; |
505 // (1) we don't want the attribute to be set and (2) we want to support | 4075 // (1) we don't want the attribute to be set and (2) we want to support |
506 // multiple event listeners ('host' and 'instance') and Node.bind | 4076 // multiple event listeners ('host' and 'instance') and Node.bind |
507 // by default supports 1 thing being bound. | 4077 // by default supports 1 thing being bound. |
508 // We do, however, leverage the event hookup code in PolymerExpressions | 4078 for (var type in events) { |
509 // so that we have a common code path for handling declarative events. | 4079 var methodName = events[type]; |
510 var self = this, bindable, eventName; | 4080 this.addEventListener(type, this.element.getEventHandler(this, this, |
511 for (var n in events) { | 4081 methodName)); |
512 eventName = EVENT_PREFIX + n; | |
513 bindable = PolymerExpressions.prepareEventBinding( | |
514 Path.get(events[n]), | |
515 eventName, | |
516 { | |
517 resolveEventHandler: function(model, path, node) { | |
518 var fn = path.getValueFrom(self); | |
519 if (fn) { | |
520 return fn.bind(self); | |
521 } | |
522 } | |
523 } | |
524 ); | |
525 bindable(this, this, false); | |
526 } | 4082 } |
527 }, | 4083 }, |
528 // call 'method' or function method on 'obj' with 'args', if the method exis
ts | 4084 // call 'method' or function method on 'obj' with 'args', if the method exis
ts |
529 dispatchMethod: function(obj, method, args) { | 4085 dispatchMethod: function(obj, method, args) { |
530 if (obj) { | 4086 if (obj) { |
531 log.events && console.group('[%s] dispatch [%s]', obj.localName, method)
; | 4087 log.events && console.group('[%s] dispatch [%s]', obj.localName, method)
; |
532 var fn = typeof method === 'function' ? method : obj[method]; | 4088 var fn = typeof method === 'function' ? method : obj[method]; |
533 if (fn) { | 4089 if (fn) { |
534 fn[args ? 'apply' : 'call'](obj, args); | 4090 fn[args ? 'apply' : 'call'](obj, args); |
535 } | 4091 } |
536 log.events && console.groupEnd(); | 4092 log.events && console.groupEnd(); |
537 Platform.flush(); | 4093 Platform.flush(); |
538 } | 4094 } |
539 } | 4095 } |
540 }; | 4096 }; |
541 | 4097 |
542 // exports | 4098 // exports |
543 | 4099 |
544 scope.api.instance.events = events; | 4100 scope.api.instance.events = events; |
545 | 4101 |
546 })(Polymer); | 4102 })(Polymer); |
547 | 4103 |
548 /* | 4104 /* |
549 * Copyright 2013 The Polymer Authors. All rights reserved. | 4105 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
550 * Use of this source code is governed by a BSD-style | 4106 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
551 * license that can be found in the LICENSE file. | 4107 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4108 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4109 * Code distributed by Google as part of the polymer project is also |
| 4110 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
552 */ | 4111 */ |
| 4112 |
553 (function(scope) { | 4113 (function(scope) { |
554 | 4114 |
555 // instance api for attributes | 4115 // instance api for attributes |
556 | 4116 |
557 var attributes = { | 4117 var attributes = { |
558 copyInstanceAttributes: function () { | 4118 copyInstanceAttributes: function () { |
559 var a$ = this._instanceAttributes; | 4119 var a$ = this._instanceAttributes; |
560 for (var k in a$) { | 4120 for (var k in a$) { |
561 if (!this.hasAttribute(k)) { | 4121 if (!this.hasAttribute(k)) { |
562 this.setAttribute(k, a$[k]); | 4122 this.setAttribute(k, a$[k]); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
633 } | 4193 } |
634 }; | 4194 }; |
635 | 4195 |
636 // exports | 4196 // exports |
637 | 4197 |
638 scope.api.instance.attributes = attributes; | 4198 scope.api.instance.attributes = attributes; |
639 | 4199 |
640 })(Polymer); | 4200 })(Polymer); |
641 | 4201 |
642 /* | 4202 /* |
643 * Copyright 2013 The Polymer Authors. All rights reserved. | 4203 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
644 * Use of this source code is governed by a BSD-style | 4204 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
645 * license that can be found in the LICENSE file. | 4205 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4206 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4207 * Code distributed by Google as part of the polymer project is also |
| 4208 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
646 */ | 4209 */ |
| 4210 |
647 (function(scope) { | 4211 (function(scope) { |
648 | 4212 |
649 // imports | 4213 // imports |
650 | 4214 |
651 var log = window.logFlags || {}; | 4215 var log = window.logFlags || {}; |
652 | 4216 |
653 // magic words | 4217 // magic words |
654 | 4218 |
655 var OBSERVE_SUFFIX = 'Changed'; | 4219 var OBSERVE_SUFFIX = 'Changed'; |
656 | 4220 |
657 // element api | 4221 // element api |
658 | 4222 |
659 var empty = []; | 4223 var empty = []; |
660 | 4224 |
661 var properties = { | 4225 var properties = { |
662 observeProperties: function() { | 4226 createPropertyObserver: function() { |
663 var n$ = this._observeNames, pn$ = this._publishNames; | 4227 var n$ = this._observeNames; |
664 if ((n$ && n$.length) || (pn$ && pn$.length)) { | 4228 if (n$ && n$.length) { |
665 var self = this; | 4229 var o = this._propertyObserver = new CompoundObserver(true); |
666 var o = this._propertyObserver = new CompoundObserver(); | |
667 // keep track of property observer so we can shut it down | |
668 this.registerObservers([o]); | 4230 this.registerObservers([o]); |
| 4231 // TODO(sorvell): may not be kosher to access the value here (this[n]); |
| 4232 // previously we looked at the descriptor on the prototype |
| 4233 // this doesn't work for inheritance and not for accessors without |
| 4234 // a value property |
669 for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) { | 4235 for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) { |
670 o.addPath(this, n); | 4236 o.addPath(this, n); |
671 // observer array properties | 4237 this.observeArrayValue(n, this[n], null); |
672 var pd = Object.getOwnPropertyDescriptor(this.__proto__, n); | |
673 if (pd && pd.value) { | |
674 this.observeArrayValue(n, pd.value, null); | |
675 } | |
676 } | 4238 } |
677 for (var i=0, l=pn$.length, n; (i<l) && (n=pn$[i]); i++) { | 4239 } |
678 if (!this.observe || (this.observe[n] === undefined)) { | 4240 }, |
679 o.addPath(this, n); | 4241 openPropertyObserver: function() { |
680 } | 4242 if (this._propertyObserver) { |
681 } | 4243 this._propertyObserver.open(this.notifyPropertyChanges, this); |
682 o.open(this.notifyPropertyChanges, this); | |
683 } | 4244 } |
684 }, | 4245 }, |
685 notifyPropertyChanges: function(newValues, oldValues, paths) { | 4246 notifyPropertyChanges: function(newValues, oldValues, paths) { |
686 var name, method, called = {}; | 4247 var name, method, called = {}; |
687 for (var i in oldValues) { | 4248 for (var i in oldValues) { |
688 // note: paths is of form [object, path, object, path] | 4249 // note: paths is of form [object, path, object, path] |
689 name = paths[2 * i + 1]; | 4250 name = paths[2 * i + 1]; |
690 if (this.publish[name] !== undefined) { | |
691 this.reflectPropertyToAttribute(name); | |
692 } | |
693 method = this.observe[name]; | 4251 method = this.observe[name]; |
694 if (method) { | 4252 if (method) { |
695 this.observeArrayValue(name, newValues[i], oldValues[i]); | 4253 var ov = oldValues[i], nv = newValues[i]; |
| 4254 // observes the value if it is an array |
| 4255 this.observeArrayValue(name, nv, ov); |
696 if (!called[method]) { | 4256 if (!called[method]) { |
697 called[method] = true; | 4257 // only invoke change method if one of ov or nv is not (undefined |
null) |
698 // observes the value if it is an array | 4258 if ((ov !== undefined && ov !== null) || (nv !== undefined && nv !==
null)) { |
699 this.invokeMethod(method, [oldValues[i], newValues[i], arguments]); | 4259 called[method] = true; |
| 4260 // TODO(sorvell): call method with the set of values it's expectin
g; |
| 4261 // e.g. 'foo bar': 'invalidate' expects the new and old values for |
| 4262 // foo and bar. Currently we give only one of these and then |
| 4263 // deliver all the arguments. |
| 4264 this.invokeMethod(method, [ov, nv, arguments]); |
| 4265 } |
700 } | 4266 } |
701 } | 4267 } |
702 } | 4268 } |
703 }, | 4269 }, |
| 4270 deliverChanges: function() { |
| 4271 if (this._propertyObserver) { |
| 4272 this._propertyObserver.deliver(); |
| 4273 } |
| 4274 }, |
| 4275 propertyChanged_: function(name, value, oldValue) { |
| 4276 if (this.reflect[name]) { |
| 4277 this.reflectPropertyToAttribute(name); |
| 4278 } |
| 4279 }, |
704 observeArrayValue: function(name, value, old) { | 4280 observeArrayValue: function(name, value, old) { |
705 // we only care if there are registered side-effects | 4281 // we only care if there are registered side-effects |
706 var callbackName = this.observe[name]; | 4282 var callbackName = this.observe[name]; |
707 if (callbackName) { | 4283 if (callbackName) { |
708 // if we are observing the previous value, stop | 4284 // if we are observing the previous value, stop |
709 if (Array.isArray(old)) { | 4285 if (Array.isArray(old)) { |
710 log.observe && console.log('[%s] observeArrayValue: unregister observe
r [%s]', this.localName, name); | 4286 log.observe && console.log('[%s] observeArrayValue: unregister observe
r [%s]', this.localName, name); |
711 this.closeNamedObserver(name + '__array'); | 4287 this.closeNamedObserver(name + '__array'); |
712 } | 4288 } |
713 // if the new value is an array, being observing it | 4289 // if the new value is an array, being observing it |
714 if (Array.isArray(value)) { | 4290 if (Array.isArray(value)) { |
715 log.observe && console.log('[%s] observeArrayValue: register observer
[%s]', this.localName, name, value); | 4291 log.observe && console.log('[%s] observeArrayValue: register observer
[%s]', this.localName, name, value); |
716 var observer = new ArrayObserver(value); | 4292 var observer = new ArrayObserver(value); |
717 observer.open(function(value, old) { | 4293 observer.open(function(value, old) { |
718 this.invokeMethod(callbackName, [old]); | 4294 this.invokeMethod(callbackName, [old]); |
719 }, this); | 4295 }, this); |
720 this.registerNamedObserver(name + '__array', observer); | 4296 this.registerNamedObserver(name + '__array', observer); |
721 } | 4297 } |
722 } | 4298 } |
723 }, | 4299 }, |
724 bindProperty: function(property, observable) { | 4300 bindProperty: function(property, observable, oneTime) { |
725 // apply Polymer two-way reference binding | 4301 if (oneTime) { |
| 4302 this[property] = observable; |
| 4303 return; |
| 4304 } |
726 return bindProperties(this, property, observable); | 4305 return bindProperties(this, property, observable); |
727 }, | 4306 }, |
728 invokeMethod: function(method, args) { | 4307 invokeMethod: function(method, args) { |
729 var fn = this[method] || method; | 4308 var fn = this[method] || method; |
730 if (typeof fn === 'function') { | 4309 if (typeof fn === 'function') { |
731 fn.apply(this, args); | 4310 fn.apply(this, args); |
732 } | 4311 } |
733 }, | 4312 }, |
734 registerObservers: function(observers) { | 4313 registerObservers: function(observers) { |
| 4314 this._observers = this._observers || []; |
735 this._observers.push(observers); | 4315 this._observers.push(observers); |
736 }, | 4316 }, |
737 // observer array items are arrays of observers. | 4317 // observer array items are arrays of observers. |
738 closeObservers: function() { | 4318 closeObservers: function() { |
| 4319 if (!this._observers) { |
| 4320 return; |
| 4321 } |
739 for (var i=0, l=this._observers.length; i<l; i++) { | 4322 for (var i=0, l=this._observers.length; i<l; i++) { |
740 this.closeObserverArray(this._observers[i]); | 4323 this.closeObserverArray(this._observers[i]); |
741 } | 4324 } |
742 this._observers = []; | 4325 this._observers = []; |
743 }, | 4326 }, |
744 closeObserverArray: function(observerArray) { | 4327 closeObserverArray: function(observerArray) { |
745 for (var i=0, l=observerArray.length, o; i<l; i++) { | 4328 for (var i=0, l=observerArray.length, o; i<l; i++) { |
746 o = observerArray[i]; | 4329 o = observerArray[i]; |
747 if (o && o.close) { | 4330 if (o && o.close) { |
748 o.close(); | 4331 o.close(); |
749 } | 4332 } |
750 } | 4333 } |
751 }, | 4334 }, |
752 // bookkeeping observers for memory management | 4335 // bookkeeping observers for memory management |
753 registerNamedObserver: function(name, observer) { | 4336 registerNamedObserver: function(name, observer) { |
754 var o$ = this._namedObservers || (this._namedObservers = {}); | 4337 var o$ = this._namedObservers || (this._namedObservers = {}); |
755 o$[name] = observer; | 4338 o$[name] = observer; |
756 }, | 4339 }, |
757 closeNamedObserver: function(name) { | 4340 closeNamedObserver: function(name) { |
758 var o$ = this._namedObservers; | 4341 var o$ = this._namedObservers; |
759 if (o$ && o$[name]) { | 4342 if (o$ && o$[name]) { |
760 o$[name].close(); | 4343 o$[name].close(); |
761 o$[name] = null; | 4344 o$[name] = null; |
762 return true; | 4345 return true; |
763 } | 4346 } |
764 }, | 4347 }, |
765 closeNamedObservers: function() { | 4348 closeNamedObservers: function() { |
766 if (this._namedObservers) { | 4349 if (this._namedObservers) { |
767 var keys=Object.keys(this._namedObservers); | 4350 for (var i in this._namedObservers) { |
768 for (var i=0, l=keys.length, k, o; (i < l) && (k=keys[i]); i++) { | 4351 this.closeNamedObserver(i); |
769 o = this._namedObservers[k]; | |
770 o.close(); | |
771 } | 4352 } |
772 this._namedObservers = {}; | 4353 this._namedObservers = {}; |
773 } | 4354 } |
774 } | 4355 } |
775 }; | 4356 }; |
776 | 4357 |
777 // property binding | 4358 // property binding |
778 // bind a property in A to a path in B by converting A[property] to a | 4359 // bind a property in A to a path in B by converting A[property] to a |
779 // getter/setter pair that accesses B[...path...] | 4360 // getter/setter pair that accesses B[...path...] |
780 function bindProperties(inA, inProperty, observable) { | 4361 function bindProperties(a, property, observable) { |
781 log.bind && console.log(LOG_BIND_PROPS, inB.localName || 'object', inPath, i
nA.localName, inProperty); | 4362 // apply Polymer two-way reference binding |
782 // capture A's value if B's value is null or undefined, | 4363 return Observer.bindToInstance(a, property, observable, resolveBindingValue)
; |
783 // otherwise use B's value | 4364 } |
784 // TODO(sorvell): need to review, can do with ObserverTransform | 4365 |
785 var v = observable.discardChanges(); | 4366 // capture A's value if B's value is null or undefined, |
786 if (v === null || v === undefined) { | 4367 // otherwise use B's value |
787 observable.setValue(inA[inProperty]); | 4368 function resolveBindingValue(oldValue, value) { |
| 4369 if (value === undefined && oldValue === null) { |
| 4370 return value; |
788 } | 4371 } |
789 return Observer.defineComputedProperty(inA, inProperty, observable); | 4372 return (value === null || value === undefined) ? oldValue : value; |
790 } | 4373 } |
791 | 4374 |
792 // logging | 4375 // logging |
793 var LOG_OBSERVE = '[%s] watching [%s]'; | 4376 var LOG_OBSERVE = '[%s] watching [%s]'; |
794 var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]'; | 4377 var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]'; |
795 var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]'; | 4378 var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]'; |
796 var LOG_BIND_PROPS = "[%s]: bindProperties: [%s] to [%s].[%s]"; | |
797 | 4379 |
798 // exports | 4380 // exports |
799 | 4381 |
800 scope.api.instance.properties = properties; | 4382 scope.api.instance.properties = properties; |
801 | 4383 |
802 })(Polymer); | 4384 })(Polymer); |
803 | 4385 |
804 /* | 4386 /* |
805 * Copyright 2013 The Polymer Authors. All rights reserved. | 4387 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
806 * Use of this source code is governed by a BSD-style | 4388 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
807 * license that can be found in the LICENSE file. | 4389 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4390 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4391 * Code distributed by Google as part of the polymer project is also |
| 4392 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
808 */ | 4393 */ |
| 4394 |
809 (function(scope) { | 4395 (function(scope) { |
810 | 4396 |
811 // imports | 4397 // imports |
812 | 4398 |
813 var log = window.logFlags || 0; | 4399 var log = window.logFlags || 0; |
814 var events = scope.api.instance.events; | |
815 | |
816 var syntax = new PolymerExpressions(); | |
817 syntax.resolveEventHandler = function(model, path, node) { | |
818 var ctlr = findEventController(node); | |
819 if (ctlr) { | |
820 var fn = path.getValueFrom(ctlr); | |
821 if (fn) { | |
822 return fn.bind(ctlr); | |
823 } | |
824 } | |
825 } | |
826 | |
827 // An event controller is the host element for the shadowRoot in which | |
828 // the node exists, or the first ancestor with a 'lightDomController' | |
829 // property. | |
830 function findEventController(node) { | |
831 while (node.parentNode) { | |
832 if (node.lightDomController) { | |
833 return node; | |
834 } | |
835 node = node.parentNode; | |
836 } | |
837 return node.host; | |
838 }; | |
839 | 4400 |
840 // element api supporting mdv | 4401 // element api supporting mdv |
841 | |
842 var mdv = { | 4402 var mdv = { |
843 syntax: syntax, | |
844 instanceTemplate: function(template) { | 4403 instanceTemplate: function(template) { |
845 var dom = template.createInstance(this, this.syntax); | 4404 // ensure a default bindingDelegate |
| 4405 var syntax = this.syntax || (!template.bindingDelegate && |
| 4406 this.element.syntax); |
| 4407 var dom = template.createInstance(this, syntax); |
846 this.registerObservers(dom.bindings_); | 4408 this.registerObservers(dom.bindings_); |
847 return dom; | 4409 return dom; |
848 }, | 4410 }, |
849 bind: function(name, observable, oneTime) { | 4411 bind: function(name, observable, oneTime) { |
850 var property = this.propertyForAttribute(name); | 4412 var property = this.propertyForAttribute(name); |
851 if (!property) { | 4413 if (!property) { |
852 // TODO(sjmiles): this mixin method must use the special form | 4414 // TODO(sjmiles): this mixin method must use the special form |
853 // of `super` installed by `mixinMethod` in declaration/prototype.js | 4415 // of `super` installed by `mixinMethod` in declaration/prototype.js |
854 return this.mixinSuper(arguments); | 4416 return this.mixinSuper(arguments); |
855 } else { | 4417 } else { |
856 // use n-way Polymer binding | 4418 // use n-way Polymer binding |
857 var observer = this.bindProperty(property, observable); | 4419 var observer = this.bindProperty(property, observable, oneTime); |
858 this.reflectPropertyToAttribute(property); | |
859 // NOTE: reflecting binding information is typically required only for | 4420 // NOTE: reflecting binding information is typically required only for |
860 // tooling. It has a performance cost so it's opt-in in Node.bind. | 4421 // tooling. It has a performance cost so it's opt-in in Node.bind. |
861 if (Platform.enableBindingsReflection) { | 4422 if (Platform.enableBindingsReflection && observer) { |
862 observer.path = observable.path_; | 4423 observer.path = observable.path_; |
863 this.bindings_ = this.bindings_ || {}; | 4424 this._recordBinding(property, observer); |
864 this.bindings_[name] = observer; | 4425 } |
| 4426 if (this.reflect[property]) { |
| 4427 this.reflectPropertyToAttribute(property); |
865 } | 4428 } |
866 return observer; | 4429 return observer; |
867 } | 4430 } |
868 }, | 4431 }, |
| 4432 bindFinished: function() { |
| 4433 this.makeElementReady(); |
| 4434 }, |
| 4435 _recordBinding: function(name, observer) { |
| 4436 this.bindings_ = this.bindings_ || {}; |
| 4437 this.bindings_[name] = observer; |
| 4438 }, |
869 // TODO(sorvell): unbind/unbindAll has been removed, as public api, from | 4439 // TODO(sorvell): unbind/unbindAll has been removed, as public api, from |
870 // TemplateBinding. We still need to close/dispose of observers but perhaps | 4440 // TemplateBinding. We still need to close/dispose of observers but perhaps |
871 // we should choose a more explicit name. | 4441 // we should choose a more explicit name. |
872 asyncUnbindAll: function() { | 4442 asyncUnbindAll: function() { |
873 if (!this._unbound) { | 4443 if (!this._unbound) { |
874 log.unbind && console.log('[%s] asyncUnbindAll', this.localName); | 4444 log.unbind && console.log('[%s] asyncUnbindAll', this.localName); |
875 this._unbindAllJob = this.job(this._unbindAllJob, this.unbindAll, 0); | 4445 this._unbindAllJob = this.job(this._unbindAllJob, this.unbindAll, 0); |
876 } | 4446 } |
877 }, | 4447 }, |
878 unbindAll: function() { | 4448 unbindAll: function() { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
914 var mustachePattern = /\{\{([^{}]*)}}/; | 4484 var mustachePattern = /\{\{([^{}]*)}}/; |
915 | 4485 |
916 // exports | 4486 // exports |
917 | 4487 |
918 scope.bindPattern = mustachePattern; | 4488 scope.bindPattern = mustachePattern; |
919 scope.api.instance.mdv = mdv; | 4489 scope.api.instance.mdv = mdv; |
920 | 4490 |
921 })(Polymer); | 4491 })(Polymer); |
922 | 4492 |
923 /* | 4493 /* |
924 * Copyright 2013 The Polymer Authors. All rights reserved. | 4494 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
925 * Use of this source code is governed by a BSD-style | 4495 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
926 * license that can be found in the LICENSE file. | 4496 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4497 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4498 * Code distributed by Google as part of the polymer project is also |
| 4499 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
927 */ | 4500 */ |
| 4501 |
928 (function(scope) { | 4502 (function(scope) { |
929 | 4503 |
930 var base = { | 4504 var base = { |
931 PolymerBase: true, | 4505 PolymerBase: true, |
932 job: function(job, callback, wait) { | 4506 job: function(job, callback, wait) { |
933 if (typeof job === 'string') { | 4507 if (typeof job === 'string') { |
934 var n = '___' + job; | 4508 var n = '___' + job; |
935 this[n] = Polymer.job.call(this, this[n], callback, wait); | 4509 this[n] = Polymer.job.call(this, this[n], callback, wait); |
936 } else { | 4510 } else { |
937 return Polymer.job.call(this, job, callback, wait); | 4511 return Polymer.job.call(this, job, callback, wait); |
938 } | 4512 } |
939 }, | 4513 }, |
940 super: Polymer.super, | 4514 super: Polymer.super, |
941 // user entry point for element has had its createdCallback called | 4515 // user entry point for element has had its createdCallback called |
942 created: function() { | 4516 created: function() { |
943 }, | 4517 }, |
944 // user entry point for element has shadowRoot and is ready for | 4518 // user entry point for element has shadowRoot and is ready for |
945 // api interaction | 4519 // api interaction |
946 ready: function() { | 4520 ready: function() { |
947 }, | 4521 }, |
948 createdCallback: function() { | 4522 createdCallback: function() { |
949 if (this.templateInstance && this.templateInstance.model) { | 4523 if (this.templateInstance && this.templateInstance.model) { |
950 console.warn('Attributes on ' + this.localName + ' were data bound ' + | 4524 console.warn('Attributes on ' + this.localName + ' were data bound ' + |
951 'prior to Polymer upgrading the element. This may result in ' + | 4525 'prior to Polymer upgrading the element. This may result in ' + |
952 'incorrect binding types.'); | 4526 'incorrect binding types.'); |
953 } | 4527 } |
954 this.created(); | 4528 this.created(); |
955 this.prepareElement(); | 4529 this.prepareElement(); |
| 4530 // TODO(sorvell): replace when ShadowDOMPolyfill issue is corrected |
| 4531 // https://github.com/Polymer/ShadowDOM/issues/420 |
| 4532 if (!this.ownerDocument.isStagingDocument || window.ShadowDOMPolyfill) { |
| 4533 this.makeElementReady(); |
| 4534 } |
956 }, | 4535 }, |
957 // system entry point, do not override | 4536 // system entry point, do not override |
958 prepareElement: function() { | 4537 prepareElement: function() { |
| 4538 if (this._elementPrepared) { |
| 4539 console.warn('Element already prepared', this.localName); |
| 4540 return; |
| 4541 } |
959 this._elementPrepared = true; | 4542 this._elementPrepared = true; |
960 // install shadowRoots storage | 4543 // storage for shadowRoots info |
961 this.shadowRoots = {}; | 4544 this.shadowRoots = {}; |
962 // storage for closeable observers. | |
963 this._observers = []; | |
964 // install property observers | 4545 // install property observers |
965 this.observeProperties(); | 4546 this.createPropertyObserver(); |
| 4547 // TODO (sorvell): temporarily open observer when created |
| 4548 this.openPropertyObserver(); |
966 // install boilerplate attributes | 4549 // install boilerplate attributes |
967 this.copyInstanceAttributes(); | 4550 this.copyInstanceAttributes(); |
968 // process input attributes | 4551 // process input attributes |
969 this.takeAttributes(); | 4552 this.takeAttributes(); |
970 // add event listeners | 4553 // add event listeners |
971 this.addHostListeners(); | 4554 this.addHostListeners(); |
| 4555 }, |
| 4556 makeElementReady: function() { |
| 4557 if (this._readied) { |
| 4558 return; |
| 4559 } |
| 4560 this._readied = true; |
| 4561 // TODO(sorvell): We could create an entry point here |
| 4562 // for the user to compute property values. |
972 // process declarative resources | 4563 // process declarative resources |
973 this.parseDeclarations(this.__proto__); | 4564 this.parseDeclarations(this.__proto__); |
974 // TODO(sorvell): CE polyfill uses unresolved attribute to simulate | 4565 // TODO(sorvell): CE polyfill uses unresolved attribute to simulate |
975 // :unresolved; remove this attribute to be compatible with native | 4566 // :unresolved; remove this attribute to be compatible with native |
976 // CE. | 4567 // CE. |
977 this.removeAttribute('unresolved'); | 4568 this.removeAttribute('unresolved'); |
978 // user entry point | 4569 // user entry point |
979 this.ready(); | 4570 this.ready(); |
| 4571 // TODO (sorvell): temporarily open observer when created |
| 4572 // turn on property observation and take any initial changes |
| 4573 //this.openPropertyObserver(); |
980 }, | 4574 }, |
981 attachedCallback: function() { | 4575 attachedCallback: function() { |
982 this.cancelUnbindAll(); | 4576 this.cancelUnbindAll(); |
983 // invoke user action | 4577 // invoke user action |
984 if (this.attached) { | 4578 if (this.attached) { |
985 this.attached(); | 4579 this.attached(); |
986 } | 4580 } |
987 // TODO(sorvell): bc | 4581 // TODO(sorvell): bc |
988 if (this.enteredView) { | 4582 if (this.enteredView) { |
989 this.enteredView(); | 4583 this.enteredView(); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1061 root.appendChild(dom); | 4655 root.appendChild(dom); |
1062 // perform post-construction initialization tasks on shadow root | 4656 // perform post-construction initialization tasks on shadow root |
1063 this.shadowRootReady(root, template); | 4657 this.shadowRootReady(root, template); |
1064 // return the created shadow root | 4658 // return the created shadow root |
1065 return root; | 4659 return root; |
1066 } | 4660 } |
1067 }, | 4661 }, |
1068 // utility function that stamps a <template> into light-dom | 4662 // utility function that stamps a <template> into light-dom |
1069 lightFromTemplate: function(template, refNode) { | 4663 lightFromTemplate: function(template, refNode) { |
1070 if (template) { | 4664 if (template) { |
1071 // TODO(sorvell): mark this element as a lightDOMController so that | 4665 // TODO(sorvell): mark this element as an eventController so that |
1072 // event listeners on bound nodes inside it will be called on it. | 4666 // event listeners on bound nodes inside it will be called on it. |
1073 // Note, the expectation here is that events on all descendants | 4667 // Note, the expectation here is that events on all descendants |
1074 // should be handled by this element. | 4668 // should be handled by this element. |
1075 this.lightDomController = true; | 4669 this.eventController = this; |
1076 // stamp template | 4670 // stamp template |
1077 // which includes parsing and applying MDV bindings before being | 4671 // which includes parsing and applying MDV bindings before being |
1078 // inserted (to avoid {{}} in attribute values) | 4672 // inserted (to avoid {{}} in attribute values) |
1079 // e.g. to prevent <img src="images/{{icon}}"> from generating a 404. | 4673 // e.g. to prevent <img src="images/{{icon}}"> from generating a 404. |
1080 var dom = this.instanceTemplate(template); | 4674 var dom = this.instanceTemplate(template); |
1081 // append to shadow dom | 4675 // append to shadow dom |
1082 if (refNode) { | 4676 if (refNode) { |
1083 this.insertBefore(dom, refNode); | 4677 this.insertBefore(dom, refNode); |
1084 } else { | 4678 } else { |
1085 this.appendChild(dom); | 4679 this.appendChild(dom); |
1086 } | 4680 } |
1087 // perform post-construction initialization tasks on ahem, light root | 4681 // perform post-construction initialization tasks on ahem, light root |
1088 this.shadowRootReady(this); | 4682 this.shadowRootReady(this); |
1089 // return the created shadow root | 4683 // return the created shadow root |
1090 return dom; | 4684 return dom; |
1091 } | 4685 } |
1092 }, | 4686 }, |
1093 shadowRootReady: function(root) { | 4687 shadowRootReady: function(root) { |
1094 // locate nodes with id and store references to them in this.$ hash | 4688 // locate nodes with id and store references to them in this.$ hash |
1095 this.marshalNodeReferences(root); | 4689 this.marshalNodeReferences(root); |
1096 // set up pointer gestures | 4690 // set up polymer gestures |
1097 PointerGestures.register(root); | 4691 PolymerGestures.register(root); |
1098 }, | 4692 }, |
1099 // locate nodes with id and store references to them in this.$ hash | 4693 // locate nodes with id and store references to them in this.$ hash |
1100 marshalNodeReferences: function(root) { | 4694 marshalNodeReferences: function(root) { |
1101 // establish $ instance variable | 4695 // establish $ instance variable |
1102 var $ = this.$ = this.$ || {}; | 4696 var $ = this.$ = this.$ || {}; |
1103 // populate $ from nodes with ID from the LOCAL tree | 4697 // populate $ from nodes with ID from the LOCAL tree |
1104 if (root) { | 4698 if (root) { |
1105 var n$ = root.querySelectorAll("[id]"); | 4699 var n$ = root.querySelectorAll("[id]"); |
1106 for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) { | 4700 for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) { |
1107 $[n.id] = n; | 4701 $[n.id] = n; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 | 4733 |
1140 // exports | 4734 // exports |
1141 | 4735 |
1142 scope.Base = PolymerBase; | 4736 scope.Base = PolymerBase; |
1143 scope.isBase = isBase; | 4737 scope.isBase = isBase; |
1144 scope.api.instance.base = base; | 4738 scope.api.instance.base = base; |
1145 | 4739 |
1146 })(Polymer); | 4740 })(Polymer); |
1147 | 4741 |
1148 /* | 4742 /* |
1149 * Copyright 2013 The Polymer Authors. All rights reserved. | 4743 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1150 * Use of this source code is governed by a BSD-style | 4744 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1151 * license that can be found in the LICENSE file. | 4745 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4746 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4747 * Code distributed by Google as part of the polymer project is also |
| 4748 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1152 */ | 4749 */ |
| 4750 |
1153 (function(scope) { | 4751 (function(scope) { |
1154 | 4752 |
1155 // imports | 4753 // imports |
1156 | 4754 |
1157 var log = window.logFlags || {}; | 4755 var log = window.logFlags || {}; |
1158 | 4756 |
1159 // magic words | 4757 // magic words |
1160 | 4758 |
1161 var STYLE_SCOPE_ATTRIBUTE = 'element'; | 4759 var STYLE_SCOPE_ATTRIBUTE = 'element'; |
1162 var STYLE_CONTROLLER_SCOPE = 'controller'; | 4760 var STYLE_CONTROLLER_SCOPE = 'controller'; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1242 return Platform.ShadowCSS.shimCssText(cssText, selector); | 4840 return Platform.ShadowCSS.shimCssText(cssText, selector); |
1243 } | 4841 } |
1244 | 4842 |
1245 // exports | 4843 // exports |
1246 | 4844 |
1247 scope.api.instance.styles = styles; | 4845 scope.api.instance.styles = styles; |
1248 | 4846 |
1249 })(Polymer); | 4847 })(Polymer); |
1250 | 4848 |
1251 /* | 4849 /* |
1252 * Copyright 2013 The Polymer Authors. All rights reserved. | 4850 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1253 * Use of this source code is governed by a BSD-style | 4851 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1254 * license that can be found in the LICENSE file. | 4852 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4853 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4854 * Code distributed by Google as part of the polymer project is also |
| 4855 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1255 */ | 4856 */ |
| 4857 |
1256 (function(scope) { | 4858 (function(scope) { |
1257 | 4859 |
1258 // imports | 4860 // imports |
1259 | 4861 |
1260 var extend = scope.extend; | 4862 var extend = scope.extend; |
1261 var api = scope.api; | 4863 var api = scope.api; |
1262 | 4864 |
1263 // imperative implementation: Polymer() | 4865 // imperative implementation: Polymer() |
1264 | 4866 |
1265 // specify an 'own' prototype for tag `name` | 4867 // specify an 'own' prototype for tag `name` |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1341 | 4943 |
1342 var declarations = Platform.deliverDeclarations(); | 4944 var declarations = Platform.deliverDeclarations(); |
1343 if (declarations) { | 4945 if (declarations) { |
1344 for (var i=0, l=declarations.length, d; (i<l) && (d=declarations[i]); i++) { | 4946 for (var i=0, l=declarations.length, d; (i<l) && (d=declarations[i]); i++) { |
1345 element.apply(null, d); | 4947 element.apply(null, d); |
1346 } | 4948 } |
1347 } | 4949 } |
1348 | 4950 |
1349 })(Polymer); | 4951 })(Polymer); |
1350 | 4952 |
1351 /* | 4953 /* |
1352 * Copyright 2013 The Polymer Authors. All rights reserved. | 4954 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1353 * Use of this source code is governed by a BSD-style | 4955 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1354 * license that can be found in the LICENSE file. | 4956 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4957 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4958 * Code distributed by Google as part of the polymer project is also |
| 4959 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1355 */ | 4960 */ |
1356 | 4961 |
1357 (function(scope) { | 4962 (function(scope) { |
1358 | 4963 |
1359 var path = { | 4964 var path = { |
1360 resolveElementPaths: function(node) { | 4965 resolveElementPaths: function(node) { |
1361 Platform.urlResolver.resolveDom(node); | 4966 Platform.urlResolver.resolveDom(node); |
1362 }, | 4967 }, |
1363 addResolvePathApi: function() { | 4968 addResolvePathApi: function() { |
1364 // let assetpath attribute modify the resolve path | 4969 // let assetpath attribute modify the resolve path |
1365 var assetPath = this.getAttribute('assetpath') || ''; | 4970 var assetPath = this.getAttribute('assetpath') || ''; |
1366 var root = new URL(assetPath, this.ownerDocument.baseURI); | 4971 var root = new URL(assetPath, this.ownerDocument.baseURI); |
1367 this.prototype.resolvePath = function(urlPath, base) { | 4972 this.prototype.resolvePath = function(urlPath, base) { |
1368 var u = new URL(urlPath, base || root); | 4973 var u = new URL(urlPath, base || root); |
1369 return u.href; | 4974 return u.href; |
1370 }; | 4975 }; |
1371 } | 4976 } |
1372 }; | 4977 }; |
1373 | 4978 |
1374 // exports | 4979 // exports |
1375 scope.api.declaration.path = path; | 4980 scope.api.declaration.path = path; |
1376 | 4981 |
1377 })(Polymer); | 4982 })(Polymer); |
1378 | 4983 |
1379 /* | 4984 /* |
1380 * Copyright 2013 The Polymer Authors. All rights reserved. | 4985 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1381 * Use of this source code is governed by a BSD-style | 4986 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1382 * license that can be found in the LICENSE file. | 4987 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 4988 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 4989 * Code distributed by Google as part of the polymer project is also |
| 4990 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1383 */ | 4991 */ |
| 4992 |
1384 (function(scope) { | 4993 (function(scope) { |
1385 | 4994 |
1386 // imports | 4995 // imports |
1387 | 4996 |
1388 var log = window.logFlags || {}; | 4997 var log = window.logFlags || {}; |
1389 var api = scope.api.instance.styles; | 4998 var api = scope.api.instance.styles; |
1390 var STYLE_SCOPE_ATTRIBUTE = api.STYLE_SCOPE_ATTRIBUTE; | 4999 var STYLE_SCOPE_ATTRIBUTE = api.STYLE_SCOPE_ATTRIBUTE; |
1391 | 5000 |
1392 // magic words | 5001 // magic words |
1393 | 5002 |
1394 var STYLE_SELECTOR = 'style'; | 5003 var STYLE_SELECTOR = 'style'; |
1395 var STYLE_LOADABLE_MATCH = '@import'; | 5004 var STYLE_LOADABLE_MATCH = '@import'; |
1396 var SHEET_SELECTOR = 'link[rel=stylesheet]'; | 5005 var SHEET_SELECTOR = 'link[rel=stylesheet]'; |
1397 var STYLE_GLOBAL_SCOPE = 'global'; | 5006 var STYLE_GLOBAL_SCOPE = 'global'; |
1398 var SCOPE_ATTR = 'polymer-scope'; | 5007 var SCOPE_ATTR = 'polymer-scope'; |
1399 | 5008 |
1400 var styles = { | 5009 var styles = { |
1401 // returns true if resources are loading | 5010 // returns true if resources are loading |
1402 loadStyles: function(callback) { | 5011 loadStyles: function(callback) { |
1403 var content = this.templateContent(); | 5012 var template = this.fetchTemplate(); |
| 5013 var content = template && this.templateContent(); |
1404 if (content) { | 5014 if (content) { |
1405 this.convertSheetsToStyles(content); | 5015 this.convertSheetsToStyles(content); |
| 5016 var styles = this.findLoadableStyles(content); |
| 5017 if (styles.length) { |
| 5018 var templateUrl = template.ownerDocument.baseURI; |
| 5019 return Platform.styleResolver.loadStyles(styles, templateUrl, callback
); |
| 5020 } |
1406 } | 5021 } |
1407 var styles = this.findLoadableStyles(content); | 5022 if (callback) { |
1408 if (styles.length) { | |
1409 Platform.styleResolver.loadStyles(styles, callback); | |
1410 } else if (callback) { | |
1411 callback(); | 5023 callback(); |
1412 } | 5024 } |
1413 }, | 5025 }, |
1414 convertSheetsToStyles: function(root) { | 5026 convertSheetsToStyles: function(root) { |
1415 var s$ = root.querySelectorAll(SHEET_SELECTOR); | 5027 var s$ = root.querySelectorAll(SHEET_SELECTOR); |
1416 for (var i=0, l=s$.length, s, c; (i<l) && (s=s$[i]); i++) { | 5028 for (var i=0, l=s$.length, s, c; (i<l) && (s=s$[i]); i++) { |
1417 c = createStyleElement(importRuleForSheet(s, this.ownerDocument.baseURI)
, | 5029 c = createStyleElement(importRuleForSheet(s, this.ownerDocument.baseURI)
, |
1418 this.ownerDocument); | 5030 this.ownerDocument); |
1419 this.copySheetAttributes(c, s); | 5031 this.copySheetAttributes(c, s); |
1420 s.parentNode.replaceChild(c, s); | 5032 s.parentNode.replaceChild(c, s); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1496 }, | 5108 }, |
1497 findNodes: function(selector, matcher) { | 5109 findNodes: function(selector, matcher) { |
1498 var nodes = this.querySelectorAll(selector).array(); | 5110 var nodes = this.querySelectorAll(selector).array(); |
1499 var content = this.templateContent(); | 5111 var content = this.templateContent(); |
1500 if (content) { | 5112 if (content) { |
1501 var templateNodes = content.querySelectorAll(selector).array(); | 5113 var templateNodes = content.querySelectorAll(selector).array(); |
1502 nodes = nodes.concat(templateNodes); | 5114 nodes = nodes.concat(templateNodes); |
1503 } | 5115 } |
1504 return matcher ? nodes.filter(matcher) : nodes; | 5116 return matcher ? nodes.filter(matcher) : nodes; |
1505 }, | 5117 }, |
1506 templateContent: function() { | |
1507 var template = this.querySelector('template'); | |
1508 return template && templateContent(template); | |
1509 }, | |
1510 /** | 5118 /** |
1511 * Promotes external stylesheets and <style> elements with the attribute | 5119 * Promotes external stylesheets and <style> elements with the attribute |
1512 * polymer-scope='global' into global scope. | 5120 * polymer-scope='global' into global scope. |
1513 * This is particularly useful for defining @keyframe rules which | 5121 * This is particularly useful for defining @keyframe rules which |
1514 * currently do not function in scoped or shadow style elements. | 5122 * currently do not function in scoped or shadow style elements. |
1515 * (See wkb.ug/72462) | 5123 * (See wkb.ug/72462) |
1516 * @param elementElement The <element> element to style. | 5124 * @param elementElement The <element> element to style. |
1517 */ | 5125 */ |
1518 // TODO(sorvell): remove when wkb.ug/72462 is addressed. | 5126 // TODO(sorvell): remove when wkb.ug/72462 is addressed. |
1519 installGlobalStyles: function() { | 5127 installGlobalStyles: function() { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1611 || p.mozMatchesSelector; | 5219 || p.mozMatchesSelector; |
1612 | 5220 |
1613 // exports | 5221 // exports |
1614 | 5222 |
1615 scope.api.declaration.styles = styles; | 5223 scope.api.declaration.styles = styles; |
1616 scope.applyStyleToScope = applyStyleToScope; | 5224 scope.applyStyleToScope = applyStyleToScope; |
1617 | 5225 |
1618 })(Polymer); | 5226 })(Polymer); |
1619 | 5227 |
1620 /* | 5228 /* |
1621 * Copyright 2013 The Polymer Authors. All rights reserved. | 5229 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1622 * Use of this source code is governed by a BSD-style | 5230 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1623 * license that can be found in the LICENSE file. | 5231 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 5232 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 5233 * Code distributed by Google as part of the polymer project is also |
| 5234 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1624 */ | 5235 */ |
1625 | 5236 |
1626 (function(scope) { | 5237 (function(scope) { |
1627 | 5238 |
1628 // imports | 5239 // imports |
1629 | 5240 |
1630 var log = window.logFlags || {}; | 5241 var log = window.logFlags || {}; |
1631 var api = scope.api.instance.events; | 5242 var api = scope.api.instance.events; |
1632 var EVENT_PREFIX = api.EVENT_PREFIX; | 5243 var EVENT_PREFIX = api.EVENT_PREFIX; |
1633 // polymer-element declarative api: events feature | 5244 // polymer-element declarative api: events feature |
1634 | 5245 |
1635 var events = { | 5246 var mixedCaseEventTypes = {}; |
| 5247 [ |
| 5248 'webkitAnimationStart', |
| 5249 'webkitAnimationEnd', |
| 5250 'webkitTransitionEnd', |
| 5251 'DOMFocusOut', |
| 5252 'DOMFocusIn', |
| 5253 'DOMMouseScroll' |
| 5254 ].forEach(function(e) { |
| 5255 mixedCaseEventTypes[e.toLowerCase()] = e; |
| 5256 }); |
| 5257 |
| 5258 var events = { |
1636 parseHostEvents: function() { | 5259 parseHostEvents: function() { |
1637 // our delegates map | 5260 // our delegates map |
1638 var delegates = this.prototype.eventDelegates; | 5261 var delegates = this.prototype.eventDelegates; |
1639 // extract data from attributes into delegates | 5262 // extract data from attributes into delegates |
1640 this.addAttributeDelegates(delegates); | 5263 this.addAttributeDelegates(delegates); |
1641 }, | 5264 }, |
1642 addAttributeDelegates: function(delegates) { | 5265 addAttributeDelegates: function(delegates) { |
1643 // for each attribute | 5266 // for each attribute |
1644 for (var i=0, a; a=this.attributes[i]; i++) { | 5267 for (var i=0, a; a=this.attributes[i]; i++) { |
1645 // does it have magic marker identifying it as an event delegate? | 5268 // does it have magic marker identifying it as an event delegate? |
1646 if (this.hasEventPrefix(a.name)) { | 5269 if (this.hasEventPrefix(a.name)) { |
1647 // if so, add the info to delegates | 5270 // if so, add the info to delegates |
1648 delegates[this.removeEventPrefix(a.name)] = a.value.replace('{{', '') | 5271 delegates[this.removeEventPrefix(a.name)] = a.value.replace('{{', '') |
1649 .replace('}}', '').trim(); | 5272 .replace('}}', '').trim(); |
1650 } | 5273 } |
1651 } | 5274 } |
1652 }, | 5275 }, |
1653 // starts with 'on-' | 5276 // starts with 'on-' |
1654 hasEventPrefix: function (n) { | 5277 hasEventPrefix: function (n) { |
1655 return n && (n[0] === 'o') && (n[1] === 'n') && (n[2] === '-'); | 5278 return n && (n[0] === 'o') && (n[1] === 'n') && (n[2] === '-'); |
1656 }, | 5279 }, |
1657 removeEventPrefix: function(n) { | 5280 removeEventPrefix: function(n) { |
1658 return n.slice(prefixLength); | 5281 return n.slice(prefixLength); |
| 5282 }, |
| 5283 findController: function(node) { |
| 5284 while (node.parentNode) { |
| 5285 if (node.eventController) { |
| 5286 return node.eventController; |
| 5287 } |
| 5288 node = node.parentNode; |
| 5289 } |
| 5290 return node.host; |
| 5291 }, |
| 5292 getEventHandler: function(controller, target, method) { |
| 5293 var events = this; |
| 5294 return function(e) { |
| 5295 if (!controller || !controller.PolymerBase) { |
| 5296 controller = events.findController(target); |
| 5297 } |
| 5298 |
| 5299 var args = [e, e.detail, e.currentTarget]; |
| 5300 controller.dispatchMethod(controller, method, args); |
| 5301 }; |
| 5302 }, |
| 5303 prepareEventBinding: function(pathString, name, node) { |
| 5304 if (!this.hasEventPrefix(name)) |
| 5305 return; |
| 5306 |
| 5307 var eventType = this.removeEventPrefix(name); |
| 5308 eventType = mixedCaseEventTypes[eventType] || eventType; |
| 5309 |
| 5310 var events = this; |
| 5311 |
| 5312 return function(model, node, oneTime) { |
| 5313 var handler = events.getEventHandler(undefined, node, pathString); |
| 5314 node.addEventListener(eventType, handler); |
| 5315 |
| 5316 if (oneTime) |
| 5317 return; |
| 5318 |
| 5319 // TODO(rafaelw): This is really pointless work. Aside from the cost |
| 5320 // of these allocations, NodeBind is going to setAttribute back to its |
| 5321 // current value. Fixing this would mean changing the TemplateBinding |
| 5322 // binding delegate API. |
| 5323 function bindingValue() { |
| 5324 return '{{ ' + pathString + ' }}'; |
| 5325 } |
| 5326 |
| 5327 return { |
| 5328 open: bindingValue, |
| 5329 discardChanges: bindingValue, |
| 5330 close: function() { |
| 5331 node.removeEventListener(eventType, handler); |
| 5332 } |
| 5333 }; |
| 5334 }; |
1659 } | 5335 } |
1660 }; | 5336 }; |
1661 | 5337 |
1662 var prefixLength = EVENT_PREFIX.length; | 5338 var prefixLength = EVENT_PREFIX.length; |
1663 | 5339 |
1664 // exports | 5340 // exports |
1665 scope.api.declaration.events = events; | 5341 scope.api.declaration.events = events; |
1666 | 5342 |
1667 })(Polymer); | 5343 })(Polymer); |
| 5344 |
1668 /* | 5345 /* |
1669 * Copyright 2013 The Polymer Authors. All rights reserved. | 5346 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1670 * Use of this source code is governed by a BSD-style | 5347 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1671 * license that can be found in the LICENSE file. | 5348 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 5349 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 5350 * Code distributed by Google as part of the polymer project is also |
| 5351 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1672 */ | 5352 */ |
| 5353 |
1673 (function(scope) { | 5354 (function(scope) { |
1674 | 5355 |
1675 // element api | 5356 // element api |
1676 | 5357 |
1677 var properties = { | 5358 var properties = { |
1678 inferObservers: function(prototype) { | 5359 inferObservers: function(prototype) { |
1679 // called before prototype.observe is chained to inherited object | 5360 // called before prototype.observe is chained to inherited object |
1680 var observe = prototype.observe, property; | 5361 var observe = prototype.observe, property; |
1681 for (var n in prototype) { | 5362 for (var n in prototype) { |
1682 if (n.slice(-7) === 'Changed') { | 5363 if (n.slice(-7) === 'Changed') { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1724 publishProperties: function(prototype, base) { | 5405 publishProperties: function(prototype, base) { |
1725 // if we have any properties to publish | 5406 // if we have any properties to publish |
1726 var publish = prototype.publish; | 5407 var publish = prototype.publish; |
1727 if (publish) { | 5408 if (publish) { |
1728 // transcribe `publish` entries onto own prototype | 5409 // transcribe `publish` entries onto own prototype |
1729 this.requireProperties(publish, prototype, base); | 5410 this.requireProperties(publish, prototype, base); |
1730 // construct map of lower-cased property names | 5411 // construct map of lower-cased property names |
1731 prototype._publishLC = this.lowerCaseMap(publish); | 5412 prototype._publishLC = this.lowerCaseMap(publish); |
1732 } | 5413 } |
1733 }, | 5414 }, |
1734 requireProperties: function(properties, prototype, base) { | 5415 // sync prototype to property descriptors; |
| 5416 // desriptor format contains default value and optionally a |
| 5417 // hint for reflecting the property to an attribute. |
| 5418 // e.g. {foo: 5, bar: {value: true, reflect: true}} |
| 5419 // reflect: {foo: true} is also supported |
| 5420 // |
| 5421 requireProperties: function(propertyDescriptors, prototype, base) { |
| 5422 // reflected properties |
| 5423 prototype.reflect = prototype.reflect || {}; |
1735 // ensure a prototype value for each property | 5424 // ensure a prototype value for each property |
1736 for (var n in properties) { | 5425 // and update the property's reflect to attribute status |
1737 if (prototype[n] === undefined && base[n] === undefined) { | 5426 for (var n in propertyDescriptors) { |
1738 prototype[n] = properties[n]; | 5427 var propertyDescriptor = propertyDescriptors[n]; |
| 5428 var reflects = this.reflectHintForDescriptor(propertyDescriptor); |
| 5429 if (prototype.reflect[n] === undefined && reflects !== undefined) { |
| 5430 prototype.reflect[n] = reflects; |
1739 } | 5431 } |
| 5432 if (prototype[n] === undefined) { |
| 5433 prototype[n] = this.valueForDescriptor(propertyDescriptor); |
| 5434 } |
| 5435 } |
| 5436 }, |
| 5437 valueForDescriptor: function(propertyDescriptor) { |
| 5438 var value = typeof propertyDescriptor === 'object' && |
| 5439 propertyDescriptor ? propertyDescriptor.value : propertyDescriptor; |
| 5440 return value !== undefined ? value : null; |
| 5441 }, |
| 5442 // returns the value of the descriptor's 'reflect' property or undefined |
| 5443 reflectHintForDescriptor: function(propertyDescriptor) { |
| 5444 if (typeof propertyDescriptor === 'object' && |
| 5445 propertyDescriptor && propertyDescriptor.reflect !== undefined) { |
| 5446 return propertyDescriptor.reflect; |
1740 } | 5447 } |
1741 }, | 5448 }, |
1742 lowerCaseMap: function(properties) { | 5449 lowerCaseMap: function(properties) { |
1743 var map = {}; | 5450 var map = {}; |
1744 for (var n in properties) { | 5451 for (var n in properties) { |
1745 map[n.toLowerCase()] = n; | 5452 map[n.toLowerCase()] = n; |
1746 } | 5453 } |
1747 return map; | 5454 return map; |
| 5455 }, |
| 5456 createPropertyAccessors: function(prototype) { |
| 5457 var n$ = prototype._publishNames; |
| 5458 if (n$ && n$.length) { |
| 5459 for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) { |
| 5460 Observer.createBindablePrototypeAccessor(prototype, n); |
| 5461 } |
| 5462 } |
1748 } | 5463 } |
1749 }; | 5464 }; |
1750 | 5465 |
1751 // exports | 5466 // exports |
1752 | 5467 |
1753 scope.api.declaration.properties = properties; | 5468 scope.api.declaration.properties = properties; |
1754 | 5469 |
1755 })(Polymer); | 5470 })(Polymer); |
1756 | 5471 |
1757 /* | 5472 /* |
1758 * Copyright 2013 The Polymer Authors. All rights reserved. | 5473 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1759 * Use of this source code is governed by a BSD-style | 5474 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1760 * license that can be found in the LICENSE file. | 5475 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 5476 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 5477 * Code distributed by Google as part of the polymer project is also |
| 5478 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1761 */ | 5479 */ |
1762 (function(scope) { | 5480 (function(scope) { |
1763 | 5481 |
1764 // magic words | 5482 // magic words |
1765 | 5483 |
1766 var ATTRIBUTES_ATTRIBUTE = 'attributes'; | 5484 var ATTRIBUTES_ATTRIBUTE = 'attributes'; |
1767 var ATTRIBUTES_REGEX = /\s|,/; | 5485 var ATTRIBUTES_REGEX = /\s|,/; |
1768 | 5486 |
1769 // attributes api | 5487 // attributes api |
1770 | 5488 |
1771 var attributes = { | 5489 var attributes = { |
| 5490 |
1772 inheritAttributesObjects: function(prototype) { | 5491 inheritAttributesObjects: function(prototype) { |
1773 // chain our lower-cased publish map to the inherited version | 5492 // chain our lower-cased publish map to the inherited version |
1774 this.inheritObject(prototype, 'publishLC'); | 5493 this.inheritObject(prototype, 'publishLC'); |
1775 // chain our instance attributes map to the inherited version | 5494 // chain our instance attributes map to the inherited version |
1776 this.inheritObject(prototype, '_instanceAttributes'); | 5495 this.inheritObject(prototype, '_instanceAttributes'); |
1777 }, | 5496 }, |
| 5497 |
1778 publishAttributes: function(prototype, base) { | 5498 publishAttributes: function(prototype, base) { |
1779 // merge names from 'attributes' attribute | 5499 // merge names from 'attributes' attribute |
1780 var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE); | 5500 var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE); |
1781 if (attributes) { | 5501 if (attributes) { |
1782 // get properties to publish | 5502 // get properties to publish |
1783 var publish = prototype.publish || (prototype.publish = {}); | 5503 var publish = prototype.publish || (prototype.publish = {}); |
1784 // names='a b c' or names='a,b,c' | 5504 // names='a b c' or names='a,b,c' |
1785 var names = attributes.split(ATTRIBUTES_REGEX); | 5505 var names = attributes.split(ATTRIBUTES_REGEX); |
1786 // record each name for publishing | 5506 // record each name for publishing |
1787 for (var i=0, l=names.length, n; i<l; i++) { | 5507 for (var i=0, l=names.length, n; i<l; i++) { |
1788 // remove excess ws | 5508 // remove excess ws |
1789 n = names[i].trim(); | 5509 n = names[i].trim(); |
1790 // do not override explicit entries | 5510 // do not override explicit entries |
1791 if (n && publish[n] === undefined && base[n] === undefined) { | 5511 if (n && publish[n] === undefined && base[n] === undefined) { |
1792 publish[n] = null; | 5512 // supply an empty 'descriptor' object and let the publishProperties |
| 5513 // code determine a default |
| 5514 publish[n] = Polymer.nob; |
1793 } | 5515 } |
1794 } | 5516 } |
1795 } | 5517 } |
1796 }, | 5518 }, |
| 5519 |
1797 // record clonable attributes from <element> | 5520 // record clonable attributes from <element> |
1798 accumulateInstanceAttributes: function() { | 5521 accumulateInstanceAttributes: function() { |
1799 // inherit instance attributes | 5522 // inherit instance attributes |
1800 var clonable = this.prototype._instanceAttributes; | 5523 var clonable = this.prototype._instanceAttributes; |
1801 // merge attributes from element | 5524 // merge attributes from element |
1802 var a$ = this.attributes; | 5525 var a$ = this.attributes; |
1803 for (var i=0, l=a$.length, a; (i<l) && (a=a$[i]); i++) { | 5526 for (var i=0, l=a$.length, a; (i<l) && (a=a$[i]); i++) { |
1804 if (this.isInstanceAttribute(a.name)) { | 5527 if (this.isInstanceAttribute(a.name)) { |
1805 clonable[a.name] = a.value; | 5528 clonable[a.name] = a.value; |
1806 } | 5529 } |
1807 } | 5530 } |
1808 }, | 5531 }, |
| 5532 |
1809 isInstanceAttribute: function(name) { | 5533 isInstanceAttribute: function(name) { |
1810 return !this.blackList[name] && name.slice(0,3) !== 'on-'; | 5534 return !this.blackList[name] && name.slice(0,3) !== 'on-'; |
1811 }, | 5535 }, |
| 5536 |
1812 // do not clone these attributes onto instances | 5537 // do not clone these attributes onto instances |
1813 blackList: { | 5538 blackList: { |
1814 name: 1, | 5539 name: 1, |
1815 'extends': 1, | 5540 'extends': 1, |
1816 constructor: 1, | 5541 constructor: 1, |
1817 noscript: 1, | 5542 noscript: 1, |
1818 assetpath: 1, | 5543 assetpath: 1, |
1819 'cache-csstext': 1 | 5544 'cache-csstext': 1 |
1820 } | 5545 } |
| 5546 |
1821 }; | 5547 }; |
1822 | 5548 |
1823 // add ATTRIBUTES_ATTRIBUTE to the blacklist | 5549 // add ATTRIBUTES_ATTRIBUTE to the blacklist |
1824 attributes.blackList[ATTRIBUTES_ATTRIBUTE] = 1; | 5550 attributes.blackList[ATTRIBUTES_ATTRIBUTE] = 1; |
1825 | 5551 |
1826 // exports | 5552 // exports |
1827 | 5553 |
1828 scope.api.declaration.attributes = attributes; | 5554 scope.api.declaration.attributes = attributes; |
1829 | 5555 |
1830 })(Polymer); | 5556 })(Polymer); |
1831 | 5557 |
1832 /* | 5558 /* |
1833 * Copyright 2013 The Polymer Authors. All rights reserved. | 5559 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
1834 * Use of this source code is governed by a BSD-style | 5560 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
1835 * license that can be found in the LICENSE file. | 5561 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 5562 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 5563 * Code distributed by Google as part of the polymer project is also |
| 5564 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
1836 */ | 5565 */ |
| 5566 |
| 5567 (function(scope) { |
| 5568 |
| 5569 // imports |
| 5570 var events = scope.api.declaration.events; |
| 5571 |
| 5572 var syntax = new PolymerExpressions(); |
| 5573 var prepareBinding = syntax.prepareBinding; |
| 5574 |
| 5575 // Polymer takes a first crack at the binding to see if it's a declarative |
| 5576 // event handler. |
| 5577 syntax.prepareBinding = function(pathString, name, node) { |
| 5578 return events.prepareEventBinding(pathString, name, node) || |
| 5579 prepareBinding.call(syntax, pathString, name, node); |
| 5580 }; |
| 5581 |
| 5582 // declaration api supporting mdv |
| 5583 var mdv = { |
| 5584 syntax: syntax, |
| 5585 fetchTemplate: function() { |
| 5586 return this.querySelector('template'); |
| 5587 }, |
| 5588 templateContent: function() { |
| 5589 var template = this.fetchTemplate(); |
| 5590 return template && Platform.templateContent(template); |
| 5591 }, |
| 5592 installBindingDelegate: function(template) { |
| 5593 if (template) { |
| 5594 template.bindingDelegate = this.syntax; |
| 5595 } |
| 5596 } |
| 5597 }; |
| 5598 |
| 5599 // exports |
| 5600 scope.api.declaration.mdv = mdv; |
| 5601 |
| 5602 })(Polymer); |
| 5603 |
| 5604 /* |
| 5605 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 5606 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 5607 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 5608 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 5609 * Code distributed by Google as part of the polymer project is also |
| 5610 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 5611 */ |
| 5612 |
1837 (function(scope) { | 5613 (function(scope) { |
1838 | 5614 |
1839 // imports | 5615 // imports |
1840 | 5616 |
1841 var api = scope.api; | 5617 var api = scope.api; |
1842 var isBase = scope.isBase; | 5618 var isBase = scope.isBase; |
1843 var extend = scope.extend; | 5619 var extend = scope.extend; |
1844 | 5620 |
1845 // prototype api | 5621 // prototype api |
1846 | 5622 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1890 // x-platform fixup | 5666 // x-platform fixup |
1891 ensurePrototypeTraversal(chained); | 5667 ensurePrototypeTraversal(chained); |
1892 return chained; | 5668 return chained; |
1893 }, | 5669 }, |
1894 | 5670 |
1895 inheritMetaData: function(prototype, base) { | 5671 inheritMetaData: function(prototype, base) { |
1896 // chain observe object to inherited | 5672 // chain observe object to inherited |
1897 this.inheritObject('observe', prototype, base); | 5673 this.inheritObject('observe', prototype, base); |
1898 // chain publish object to inherited | 5674 // chain publish object to inherited |
1899 this.inheritObject('publish', prototype, base); | 5675 this.inheritObject('publish', prototype, base); |
| 5676 // chain reflect object to inherited |
| 5677 this.inheritObject('reflect', prototype, base); |
1900 // chain our lower-cased publish map to the inherited version | 5678 // chain our lower-cased publish map to the inherited version |
1901 this.inheritObject('_publishLC', prototype, base); | 5679 this.inheritObject('_publishLC', prototype, base); |
1902 // chain our instance attributes map to the inherited version | 5680 // chain our instance attributes map to the inherited version |
1903 this.inheritObject('_instanceAttributes', prototype, base); | 5681 this.inheritObject('_instanceAttributes', prototype, base); |
1904 // chain our event delegates map to the inherited version | 5682 // chain our event delegates map to the inherited version |
1905 this.inheritObject('eventDelegates', prototype, base); | 5683 this.inheritObject('eventDelegates', prototype, base); |
1906 }, | 5684 }, |
1907 | 5685 |
1908 // implement various declarative features | 5686 // implement various declarative features |
1909 desugarAfterChaining: function(name, extendee) { | 5687 desugarAfterChaining: function(name, extendee) { |
1910 // build side-chained lists to optimize iterations | 5688 // build side-chained lists to optimize iterations |
1911 this.optimizePropertyMaps(this.prototype); | 5689 this.optimizePropertyMaps(this.prototype); |
| 5690 this.createPropertyAccessors(this.prototype); |
| 5691 // install mdv delegate on template |
| 5692 this.installBindingDelegate(this.fetchTemplate()); |
1912 // install external stylesheets as if they are inline | 5693 // install external stylesheets as if they are inline |
1913 this.installSheets(); | 5694 this.installSheets(); |
1914 // adjust any paths in dom from imports | 5695 // adjust any paths in dom from imports |
1915 this.resolveElementPaths(this); | 5696 this.resolveElementPaths(this); |
1916 // compile list of attributes to copy to instances | 5697 // compile list of attributes to copy to instances |
1917 this.accumulateInstanceAttributes(); | 5698 this.accumulateInstanceAttributes(); |
1918 // parse on-* delegates declared on `this` element | 5699 // parse on-* delegates declared on `this` element |
1919 this.parseHostEvents(); | 5700 this.parseHostEvents(); |
1920 // | 5701 // |
1921 // install a helper method this.resolvePath to aid in | 5702 // install a helper method this.resolvePath to aid in |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2067 } | 5848 } |
2068 } | 5849 } |
2069 | 5850 |
2070 // exports | 5851 // exports |
2071 | 5852 |
2072 api.declaration.prototype = prototype; | 5853 api.declaration.prototype = prototype; |
2073 | 5854 |
2074 })(Polymer); | 5855 })(Polymer); |
2075 | 5856 |
2076 /* | 5857 /* |
2077 * Copyright 2013 The Polymer Authors. All rights reserved. | 5858 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
2078 * Use of this source code is governed by a BSD-style | 5859 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
2079 * license that can be found in the LICENSE file. | 5860 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 5861 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 5862 * Code distributed by Google as part of the polymer project is also |
| 5863 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
2080 */ | 5864 */ |
| 5865 |
2081 (function(scope) { | 5866 (function(scope) { |
2082 | 5867 |
| 5868 /* |
| 5869 |
| 5870 Elements are added to a registration queue so that they register in |
| 5871 the proper order at the appropriate time. We do this for a few reasons: |
| 5872 |
| 5873 * to enable elements to load resources (like stylesheets) |
| 5874 asynchronously. We need to do this until the platform provides an efficient |
| 5875 alternative. One issue is that remote @import stylesheets are |
| 5876 re-fetched whenever stamped into a shadowRoot. |
| 5877 |
| 5878 * to ensure elements loaded 'at the same time' (e.g. via some set of |
| 5879 imports) are registered as a batch. This allows elements to be enured from |
| 5880 upgrade ordering as long as they query the dom tree 1 task after |
| 5881 upgrade (aka domReady). This is a performance tradeoff. On the one hand, |
| 5882 elements that could register while imports are loading are prevented from |
| 5883 doing so. On the other, grouping upgrades into a single task means less |
| 5884 incremental work (for example style recalcs), Also, we can ensure the |
| 5885 document is in a known state at the single quantum of time when |
| 5886 elements upgrade. |
| 5887 |
| 5888 */ |
2083 var queue = { | 5889 var queue = { |
2084 // tell the queue to wait for an element to be ready | 5890 // tell the queue to wait for an element to be ready |
2085 wait: function(element, check, go) { | 5891 wait: function(element, check, go) { |
2086 if (this.indexOf(element) === -1) { | 5892 var shouldAdd = (this.indexOf(element) === -1 && |
| 5893 flushQueue.indexOf(element) === -1); |
| 5894 if (shouldAdd) { |
2087 this.add(element); | 5895 this.add(element); |
2088 element.__check = check; | 5896 element.__check = check; |
2089 element.__go = go; | 5897 element.__go = go; |
2090 } | 5898 } |
2091 return (this.indexOf(element) !== 0); | 5899 return (this.indexOf(element) !== 0); |
2092 }, | 5900 }, |
2093 add: function(element) { | 5901 add: function(element) { |
2094 //console.log('queueing', element.name); | 5902 //console.log('queueing', element.name); |
2095 queueForElement(element).push(element); | 5903 queueForElement(element).push(element); |
2096 }, | 5904 }, |
2097 indexOf: function(element) { | 5905 indexOf: function(element) { |
2098 var i = queueForElement(element).indexOf(element); | 5906 var i = queueForElement(element).indexOf(element); |
2099 if (i >= 0 && document.contains(element)) { | 5907 if (i >= 0 && document.contains(element)) { |
2100 i += (HTMLImports.useNative || HTMLImports.ready) ? | 5908 i += (HTMLImports.useNative || HTMLImports.ready) ? |
2101 importQueue.length : 1e9; | 5909 importQueue.length : 1e9; |
2102 } | 5910 } |
2103 return i; | 5911 return i; |
2104 }, | 5912 }, |
2105 // tell the queue an element is ready to be registered | 5913 // tell the queue an element is ready to be registered |
2106 go: function(element) { | 5914 go: function(element) { |
2107 var readied = this.remove(element); | 5915 var readied = this.remove(element); |
2108 if (readied) { | 5916 if (readied) { |
2109 readied.__go.call(readied); | 5917 this.addToFlushQueue(readied); |
2110 readied.__check = readied.__go = null; | |
2111 this.check(); | 5918 this.check(); |
2112 } | 5919 } |
2113 }, | 5920 }, |
2114 remove: function(element) { | 5921 remove: function(element) { |
2115 var i = this.indexOf(element); | 5922 var i = this.indexOf(element); |
2116 if (i !== 0) { | 5923 if (i !== 0) { |
2117 //console.warn('queue order wrong', i); | 5924 //console.warn('queue order wrong', i); |
2118 return; | 5925 return; |
2119 } | 5926 } |
2120 return queueForElement(element).shift(); | 5927 return queueForElement(element).shift(); |
(...skipping 11 matching lines...) Expand all Loading... |
2132 }, | 5939 }, |
2133 nextElement: function() { | 5940 nextElement: function() { |
2134 return nextQueued(); | 5941 return nextQueued(); |
2135 }, | 5942 }, |
2136 canReady: function() { | 5943 canReady: function() { |
2137 return !this.waitToReady && this.isEmpty(); | 5944 return !this.waitToReady && this.isEmpty(); |
2138 }, | 5945 }, |
2139 isEmpty: function() { | 5946 isEmpty: function() { |
2140 return !importQueue.length && !mainQueue.length; | 5947 return !importQueue.length && !mainQueue.length; |
2141 }, | 5948 }, |
| 5949 addToFlushQueue: function(element) { |
| 5950 flushQueue.push(element); |
| 5951 }, |
| 5952 flush: function() { |
| 5953 var element; |
| 5954 while (flushQueue.length) { |
| 5955 element = flushQueue.shift(); |
| 5956 element.__go.call(element); |
| 5957 element.__check = element.__go = null; |
| 5958 } |
| 5959 }, |
2142 ready: function() { | 5960 ready: function() { |
| 5961 this.flush(); |
2143 // TODO(sorvell): As an optimization, turn off CE polyfill upgrading | 5962 // TODO(sorvell): As an optimization, turn off CE polyfill upgrading |
2144 // while registering. This way we avoid having to upgrade each document | 5963 // while registering. This way we avoid having to upgrade each document |
2145 // piecemeal per registration and can instead register all elements | 5964 // piecemeal per registration and can instead register all elements |
2146 // and upgrade once in a batch. Without this optimization, upgrade time | 5965 // and upgrade once in a batch. Without this optimization, upgrade time |
2147 // degrades significantly when SD polyfill is used. This is mainly because | 5966 // degrades significantly when SD polyfill is used. This is mainly because |
2148 // querying the document tree for elements is slow under the SD polyfill. | 5967 // querying the document tree for elements is slow under the SD polyfill. |
2149 if (CustomElements.ready === false) { | 5968 if (CustomElements.ready === false) { |
2150 CustomElements.upgradeDocumentTree(document); | 5969 CustomElements.upgradeDocumentTree(document); |
2151 CustomElements.ready = true; | 5970 CustomElements.ready = true; |
2152 } | 5971 } |
| 5972 Platform.flush(); |
| 5973 requestAnimationFrame(this.flushReadyCallbacks); |
| 5974 }, |
| 5975 addReadyCallback: function(callback) { |
| 5976 if (callback) { |
| 5977 readyCallbacks.push(callback); |
| 5978 } |
| 5979 }, |
| 5980 flushReadyCallbacks: function() { |
2153 if (readyCallbacks) { | 5981 if (readyCallbacks) { |
2154 var fn; | 5982 var fn; |
2155 while (readyCallbacks.length) { | 5983 while (readyCallbacks.length) { |
2156 fn = readyCallbacks.shift(); | 5984 fn = readyCallbacks.shift(); |
2157 fn(); | 5985 fn(); |
2158 } | 5986 } |
2159 } | 5987 } |
2160 }, | 5988 }, |
2161 addReadyCallback: function(callback) { | |
2162 if (callback) { | |
2163 readyCallbacks.push(callback); | |
2164 } | |
2165 }, | |
2166 waitToReady: true | 5989 waitToReady: true |
2167 }; | 5990 }; |
2168 | 5991 |
| 5992 var flushQueue = []; |
| 5993 |
2169 var importQueue = []; | 5994 var importQueue = []; |
2170 var mainQueue = []; | 5995 var mainQueue = []; |
2171 var readyCallbacks = []; | 5996 var readyCallbacks = []; |
2172 | 5997 |
2173 function queueForElement(element) { | 5998 function queueForElement(element) { |
2174 return document.contains(element) ? mainQueue : importQueue; | 5999 return document.contains(element) ? mainQueue : importQueue; |
2175 } | 6000 } |
2176 | 6001 |
2177 function nextQueued() { | 6002 function nextQueued() { |
2178 return importQueue.length ? importQueue[0] : mainQueue[0]; | 6003 return importQueue.length ? importQueue[0] : mainQueue[0]; |
(...skipping 14 matching lines...) Expand all Loading... |
2193 queue.check(); | 6018 queue.check(); |
2194 }); | 6019 }); |
2195 } | 6020 } |
2196 | 6021 |
2197 // exports | 6022 // exports |
2198 scope.queue = queue; | 6023 scope.queue = queue; |
2199 scope.whenPolymerReady = whenPolymerReady; | 6024 scope.whenPolymerReady = whenPolymerReady; |
2200 })(Polymer); | 6025 })(Polymer); |
2201 | 6026 |
2202 /* | 6027 /* |
2203 * Copyright 2013 The Polymer Authors. All rights reserved. | 6028 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
2204 * Use of this source code is governed by a BSD-style | 6029 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
2205 * license that can be found in the LICENSE file. | 6030 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 6031 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 6032 * Code distributed by Google as part of the polymer project is also |
| 6033 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
2206 */ | 6034 */ |
| 6035 |
2207 (function(scope) { | 6036 (function(scope) { |
2208 | 6037 |
2209 var whenPolymerReady = scope.whenPolymerReady; | 6038 var whenPolymerReady = scope.whenPolymerReady; |
2210 | 6039 |
2211 function importElements(elementOrFragment, callback) { | 6040 function importElements(elementOrFragment, callback) { |
2212 if (elementOrFragment) { | 6041 if (elementOrFragment) { |
2213 document.head.appendChild(elementOrFragment); | 6042 document.head.appendChild(elementOrFragment); |
2214 whenPolymerReady(callback); | 6043 whenPolymerReady(callback); |
2215 } else if (callback) { | 6044 } else if (callback) { |
2216 callback(); | 6045 callback(); |
(...skipping 15 matching lines...) Expand all Loading... |
2232 } | 6061 } |
2233 } | 6062 } |
2234 | 6063 |
2235 // exports | 6064 // exports |
2236 scope.import = importUrls; | 6065 scope.import = importUrls; |
2237 scope.importElements = importElements; | 6066 scope.importElements = importElements; |
2238 | 6067 |
2239 })(Polymer); | 6068 })(Polymer); |
2240 | 6069 |
2241 /* | 6070 /* |
2242 * Copyright 2013 The Polymer Authors. All rights reserved. | 6071 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
2243 * Use of this source code is governed by a BSD-style | 6072 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
2244 * license that can be found in the LICENSE file. | 6073 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 6074 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 6075 * Code distributed by Google as part of the polymer project is also |
| 6076 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
2245 */ | 6077 */ |
| 6078 |
2246 (function(scope) { | 6079 (function(scope) { |
2247 | 6080 |
2248 // imports | 6081 // imports |
2249 | 6082 |
2250 var extend = scope.extend; | 6083 var extend = scope.extend; |
2251 var api = scope.api; | 6084 var api = scope.api; |
2252 var queue = scope.queue; | 6085 var queue = scope.queue; |
2253 var whenPolymerReady = scope.whenPolymerReady; | 6086 var whenPolymerReady = scope.whenPolymerReady; |
2254 var getRegisteredPrototype = scope.getRegisteredPrototype; | 6087 var getRegisteredPrototype = scope.getRegisteredPrototype; |
2255 var waitingForPrototype = scope.waitingForPrototype; | 6088 var waitingForPrototype = scope.waitingForPrototype; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2363 // utility and bookkeeping | 6196 // utility and bookkeeping |
2364 | 6197 |
2365 function isRegistered(name) { | 6198 function isRegistered(name) { |
2366 return Boolean(HTMLElement.getPrototypeForTag(name)); | 6199 return Boolean(HTMLElement.getPrototypeForTag(name)); |
2367 } | 6200 } |
2368 | 6201 |
2369 function isCustomTag(name) { | 6202 function isCustomTag(name) { |
2370 return (name && name.indexOf('-') >= 0); | 6203 return (name && name.indexOf('-') >= 0); |
2371 } | 6204 } |
2372 | 6205 |
2373 // exports | |
2374 | |
2375 scope.getRegisteredPrototype = getRegisteredPrototype; | |
2376 | |
2377 // boot tasks | 6206 // boot tasks |
2378 | 6207 |
2379 whenPolymerReady(function() { | 6208 whenPolymerReady(function() { |
2380 document.body.removeAttribute('unresolved'); | 6209 document.body.removeAttribute('unresolved'); |
2381 document.dispatchEvent( | 6210 document.dispatchEvent( |
2382 new CustomEvent('polymer-ready', {bubbles: true}) | 6211 new CustomEvent('polymer-ready', {bubbles: true}) |
2383 ); | 6212 ); |
2384 }); | 6213 }); |
2385 | 6214 |
2386 // register polymer-element with document | 6215 // register polymer-element with document |
2387 | 6216 |
2388 document.registerElement('polymer-element', {prototype: prototype}); | 6217 document.registerElement('polymer-element', {prototype: prototype}); |
2389 | 6218 |
2390 })(Polymer); | 6219 })(Polymer); |
2391 | 6220 |
| 6221 /* |
| 6222 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 6223 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 6224 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 6225 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 6226 * Code distributed by Google as part of the polymer project is also |
| 6227 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 6228 */ |
| 6229 |
| 6230 /** |
| 6231 * The `auto-binding` element extends the template element. It provides a quick |
| 6232 * and easy way to do data binding without the need to setup a model. |
| 6233 * The `auto-binding` element itself serves as the model and controller for the |
| 6234 * elements it contains. Both data and event handlers can be bound. |
| 6235 * |
| 6236 * The `auto-binding` element acts just like a template that is bound to |
| 6237 * a model. It stamps its content in the dom adjacent to itself. When the |
| 6238 * content is stamped, the `template-bound` event is fired. |
| 6239 * |
| 6240 * Example: |
| 6241 * |
| 6242 * <template is="auto-binding"> |
| 6243 * <div>Say something: <input value="{{value}}"></div> |
| 6244 * <div>You said: {{value}}</div> |
| 6245 * <button on-tap="{{buttonTap}}">Tap me!</button> |
| 6246 * </template> |
| 6247 * <script> |
| 6248 * var template = document.querySelector('template'); |
| 6249 * template.value = 'something'; |
| 6250 * template.buttonTap = function() { |
| 6251 * console.log('tap!'); |
| 6252 * }; |
| 6253 * </script> |
| 6254 * |
| 6255 * @module Polymer |
| 6256 * @status stable |
| 6257 */ |
| 6258 |
| 6259 (function() { |
| 6260 |
| 6261 var element = document.createElement('polymer-element'); |
| 6262 element.setAttribute('name', 'auto-binding'); |
| 6263 element.setAttribute('extends', 'template'); |
| 6264 element.init(); |
| 6265 |
| 6266 Polymer('auto-binding', { |
| 6267 |
| 6268 createdCallback: function() { |
| 6269 this.syntax = this.bindingDelegate = this.makeSyntax(); |
| 6270 // delay stamping until polymer-ready so that auto-binding is not |
| 6271 // required to load last. |
| 6272 Polymer.whenPolymerReady(function() { |
| 6273 this.model = this; |
| 6274 this.setAttribute('bind', ''); |
| 6275 // we don't bother with an explicit signal here, we could ust a MO |
| 6276 // if necessary |
| 6277 this.async(function() { |
| 6278 // note: this will marshall *all* the elements in the parentNode |
| 6279 // rather than just stamped ones. We'd need to use createInstance |
| 6280 // to fix this or something else fancier. |
| 6281 this.marshalNodeReferences(this.parentNode); |
| 6282 // template stamping is asynchronous so stamping isn't complete |
| 6283 // by polymer-ready; fire an event so users can use stamped elements |
| 6284 this.fire('template-bound'); |
| 6285 }); |
| 6286 }.bind(this)); |
| 6287 }, |
| 6288 |
| 6289 makeSyntax: function() { |
| 6290 var events = Object.create(Polymer.api.declaration.events); |
| 6291 var self = this; |
| 6292 events.findController = function() { return self.model; }; |
| 6293 |
| 6294 var syntax = new PolymerExpressions(); |
| 6295 var prepareBinding = syntax.prepareBinding; |
| 6296 syntax.prepareBinding = function(pathString, name, node) { |
| 6297 return events.prepareEventBinding(pathString, name, node) || |
| 6298 prepareBinding.call(syntax, pathString, name, node); |
| 6299 }; |
| 6300 return syntax; |
| 6301 } |
| 6302 |
| 6303 }); |
| 6304 |
| 6305 })(); |
| 6306 |
2392 //# sourceMappingURL=polymer.concat.js.map | 6307 //# sourceMappingURL=polymer.concat.js.map |
OLD | NEW |