OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 function assert(condition, opt_message) { |
| 5 if (!condition) { |
| 6 var message = 'Assertion failed'; |
| 7 if (opt_message) message = message + ': ' + opt_message; |
| 8 var error = new Error(message); |
| 9 var global = function() { |
| 10 return this; |
| 11 }(); |
| 12 if (global.traceAssertionsForTesting) console.warn(error.stack); |
| 13 throw error; |
| 14 } |
| 15 return condition; |
| 16 } |
| 17 |
| 18 function assertNotReached(opt_message) { |
| 19 assert(false, opt_message || 'Unreachable code hit'); |
| 20 } |
| 21 |
| 22 function assertInstanceof(value, type, opt_message) { |
| 23 if (!(value instanceof type)) { |
| 24 assertNotReached(opt_message || 'Value ' + value + ' is not a[n] ' + (type.n
ame || typeof type)); |
| 25 } |
| 26 return value; |
| 27 } |
| 28 |
| 29 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 30 // Use of this source code is governed by a BSD-style license that can be |
| 31 // found in the LICENSE file. |
| 32 function PromiseResolver() { |
| 33 this.resolve_; |
| 34 this.reject_; |
| 35 this.promise_ = new Promise(function(resolve, reject) { |
| 36 this.resolve_ = resolve; |
| 37 this.reject_ = reject; |
| 38 }.bind(this)); |
| 39 } |
| 40 |
| 41 PromiseResolver.prototype = { |
| 42 get promise() { |
| 43 return this.promise_; |
| 44 }, |
| 45 set promise(p) { |
| 46 assertNotReached(); |
| 47 }, |
| 48 get resolve() { |
| 49 return this.resolve_; |
| 50 }, |
| 51 set resolve(r) { |
| 52 assertNotReached(); |
| 53 }, |
| 54 get reject() { |
| 55 return this.reject_; |
| 56 }, |
| 57 set reject(s) { |
| 58 assertNotReached(); |
| 59 } |
| 60 }; |
| 61 |
| 62 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 63 // Use of this source code is governed by a BSD-style license that can be |
| 64 // found in the LICENSE file. |
| 65 var global = this; |
| 66 |
| 67 var WebUIListener; |
| 68 |
| 69 var cr = cr || function() { |
| 70 'use strict'; |
| 71 function exportPath(name, opt_object, opt_objectToExportTo) { |
| 72 var parts = name.split('.'); |
| 73 var cur = opt_objectToExportTo || global; |
| 74 for (var part; parts.length && (part = parts.shift()); ) { |
| 75 if (!parts.length && opt_object !== undefined) { |
| 76 cur[part] = opt_object; |
| 77 } else if (part in cur) { |
| 78 cur = cur[part]; |
| 79 } else { |
| 80 cur = cur[part] = {}; |
| 81 } |
| 82 } |
| 83 return cur; |
| 84 } |
| 85 function dispatchPropertyChange(target, propertyName, newValue, oldValue) { |
| 86 var e = new Event(propertyName + 'Change'); |
| 87 e.propertyName = propertyName; |
| 88 e.newValue = newValue; |
| 89 e.oldValue = oldValue; |
| 90 target.dispatchEvent(e); |
| 91 } |
| 92 function getAttributeName(jsName) { |
| 93 return jsName.replace(/([A-Z])/g, '-$1').toLowerCase(); |
| 94 } |
| 95 var PropertyKind = { |
| 96 JS: 'js', |
| 97 ATTR: 'attr', |
| 98 BOOL_ATTR: 'boolAttr' |
| 99 }; |
| 100 function getGetter(name, kind) { |
| 101 switch (kind) { |
| 102 case PropertyKind.JS: |
| 103 var privateName = name + '_'; |
| 104 return function() { |
| 105 return this[privateName]; |
| 106 }; |
| 107 |
| 108 case PropertyKind.ATTR: |
| 109 var attributeName = getAttributeName(name); |
| 110 return function() { |
| 111 return this.getAttribute(attributeName); |
| 112 }; |
| 113 |
| 114 case PropertyKind.BOOL_ATTR: |
| 115 var attributeName = getAttributeName(name); |
| 116 return function() { |
| 117 return this.hasAttribute(attributeName); |
| 118 }; |
| 119 } |
| 120 throw 'not reached'; |
| 121 } |
| 122 function getSetter(name, kind, opt_setHook) { |
| 123 switch (kind) { |
| 124 case PropertyKind.JS: |
| 125 var privateName = name + '_'; |
| 126 return function(value) { |
| 127 var oldValue = this[name]; |
| 128 if (value !== oldValue) { |
| 129 this[privateName] = value; |
| 130 if (opt_setHook) opt_setHook.call(this, value, oldValue); |
| 131 dispatchPropertyChange(this, name, value, oldValue); |
| 132 } |
| 133 }; |
| 134 |
| 135 case PropertyKind.ATTR: |
| 136 var attributeName = getAttributeName(name); |
| 137 return function(value) { |
| 138 var oldValue = this[name]; |
| 139 if (value !== oldValue) { |
| 140 if (value == undefined) this.removeAttribute(attributeName); else this
.setAttribute(attributeName, value); |
| 141 if (opt_setHook) opt_setHook.call(this, value, oldValue); |
| 142 dispatchPropertyChange(this, name, value, oldValue); |
| 143 } |
| 144 }; |
| 145 |
| 146 case PropertyKind.BOOL_ATTR: |
| 147 var attributeName = getAttributeName(name); |
| 148 return function(value) { |
| 149 var oldValue = this[name]; |
| 150 if (value !== oldValue) { |
| 151 if (value) this.setAttribute(attributeName, name); else this.removeAtt
ribute(attributeName); |
| 152 if (opt_setHook) opt_setHook.call(this, value, oldValue); |
| 153 dispatchPropertyChange(this, name, value, oldValue); |
| 154 } |
| 155 }; |
| 156 } |
| 157 throw 'not reached'; |
| 158 } |
| 159 function defineProperty(obj, name, opt_kind, opt_setHook) { |
| 160 if (typeof obj == 'function') obj = obj.prototype; |
| 161 var kind = opt_kind || PropertyKind.JS; |
| 162 if (!obj.__lookupGetter__(name)) obj.__defineGetter__(name, getGetter(name,
kind)); |
| 163 if (!obj.__lookupSetter__(name)) obj.__defineSetter__(name, getSetter(name,
kind, opt_setHook)); |
| 164 } |
| 165 var uidCounter = 1; |
| 166 function createUid() { |
| 167 return uidCounter++; |
| 168 } |
| 169 function getUid(item) { |
| 170 if (item.hasOwnProperty('uid')) return item.uid; |
| 171 return item.uid = createUid(); |
| 172 } |
| 173 function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) { |
| 174 var e = new Event(type, { |
| 175 bubbles: opt_bubbles, |
| 176 cancelable: opt_cancelable === undefined || opt_cancelable |
| 177 }); |
| 178 return target.dispatchEvent(e); |
| 179 } |
| 180 function define(name, fun) { |
| 181 var obj = exportPath(name); |
| 182 var exports = fun(); |
| 183 for (var propertyName in exports) { |
| 184 var propertyDescriptor = Object.getOwnPropertyDescriptor(exports, property
Name); |
| 185 if (propertyDescriptor) Object.defineProperty(obj, propertyName, propertyD
escriptor); |
| 186 } |
| 187 } |
| 188 function addSingletonGetter(ctor) { |
| 189 ctor.getInstance = function() { |
| 190 return ctor.instance_ || (ctor.instance_ = new ctor()); |
| 191 }; |
| 192 } |
| 193 function makePublic(ctor, methods, opt_target) { |
| 194 methods.forEach(function(method) { |
| 195 ctor[method] = function() { |
| 196 var target = opt_target ? document.getElementById(opt_target) : ctor.get
Instance(); |
| 197 return target[method + '_'].apply(target, arguments); |
| 198 }; |
| 199 }); |
| 200 } |
| 201 var chromeSendResolverMap = {}; |
| 202 function webUIResponse(id, isSuccess, response) { |
| 203 var resolver = chromeSendResolverMap[id]; |
| 204 delete chromeSendResolverMap[id]; |
| 205 if (isSuccess) resolver.resolve(response); else resolver.reject(response); |
| 206 } |
| 207 function sendWithPromise(methodName, var_args) { |
| 208 var args = Array.prototype.slice.call(arguments, 1); |
| 209 var promiseResolver = new PromiseResolver(); |
| 210 var id = methodName + '_' + createUid(); |
| 211 chromeSendResolverMap[id] = promiseResolver; |
| 212 chrome.send(methodName, [ id ].concat(args)); |
| 213 return promiseResolver.promise; |
| 214 } |
| 215 var webUIListenerMap = {}; |
| 216 function webUIListenerCallback(event, var_args) { |
| 217 var eventListenersMap = webUIListenerMap[event]; |
| 218 if (!eventListenersMap) { |
| 219 return; |
| 220 } |
| 221 var args = Array.prototype.slice.call(arguments, 1); |
| 222 for (var listenerId in eventListenersMap) { |
| 223 eventListenersMap[listenerId].apply(null, args); |
| 224 } |
| 225 } |
| 226 function addWebUIListener(eventName, callback) { |
| 227 webUIListenerMap[eventName] = webUIListenerMap[eventName] || {}; |
| 228 var uid = createUid(); |
| 229 webUIListenerMap[eventName][uid] = callback; |
| 230 return { |
| 231 eventName: eventName, |
| 232 uid: uid |
| 233 }; |
| 234 } |
| 235 function removeWebUIListener(listener) { |
| 236 var listenerExists = webUIListenerMap[listener.eventName] && webUIListenerMa
p[listener.eventName][listener.uid]; |
| 237 if (listenerExists) { |
| 238 delete webUIListenerMap[listener.eventName][listener.uid]; |
| 239 return true; |
| 240 } |
| 241 return false; |
| 242 } |
| 243 return { |
| 244 addSingletonGetter: addSingletonGetter, |
| 245 createUid: createUid, |
| 246 define: define, |
| 247 defineProperty: defineProperty, |
| 248 dispatchPropertyChange: dispatchPropertyChange, |
| 249 dispatchSimpleEvent: dispatchSimpleEvent, |
| 250 exportPath: exportPath, |
| 251 getUid: getUid, |
| 252 makePublic: makePublic, |
| 253 PropertyKind: PropertyKind, |
| 254 addWebUIListener: addWebUIListener, |
| 255 removeWebUIListener: removeWebUIListener, |
| 256 sendWithPromise: sendWithPromise, |
| 257 webUIListenerCallback: webUIListenerCallback, |
| 258 webUIResponse: webUIResponse, |
| 259 get doc() { |
| 260 return document; |
| 261 }, |
| 262 get isMac() { |
| 263 return /Mac/.test(navigator.platform); |
| 264 }, |
| 265 get isWindows() { |
| 266 return /Win/.test(navigator.platform); |
| 267 }, |
| 268 get isChromeOS() { |
| 269 return /CrOS/.test(navigator.userAgent); |
| 270 }, |
| 271 get isLinux() { |
| 272 return /Linux/.test(navigator.userAgent); |
| 273 }, |
| 274 get isAndroid() { |
| 275 return /Android/.test(navigator.userAgent); |
| 276 }, |
| 277 get isIOS() { |
| 278 return /iPad|iPhone|iPod/.test(navigator.platform); |
| 279 } |
| 280 }; |
| 281 }(); |
| 282 |
| 283 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 284 // Use of this source code is governed by a BSD-style license that can be |
| 285 // found in the LICENSE file. |
| 286 cr.define('cr.ui', function() { |
| 287 function decorate(source, constr) { |
| 288 var elements; |
| 289 if (typeof source == 'string') elements = cr.doc.querySelectorAll(source); e
lse elements = [ source ]; |
| 290 for (var i = 0, el; el = elements[i]; i++) { |
| 291 if (!(el instanceof constr)) constr.decorate(el); |
| 292 } |
| 293 } |
| 294 function createElementHelper(tagName, opt_bag) { |
| 295 var doc; |
| 296 if (opt_bag && opt_bag.ownerDocument) doc = opt_bag.ownerDocument; else doc
= cr.doc; |
| 297 return doc.createElement(tagName); |
| 298 } |
| 299 function define(tagNameOrFunction) { |
| 300 var createFunction, tagName; |
| 301 if (typeof tagNameOrFunction == 'function') { |
| 302 createFunction = tagNameOrFunction; |
| 303 tagName = ''; |
| 304 } else { |
| 305 createFunction = createElementHelper; |
| 306 tagName = tagNameOrFunction; |
| 307 } |
| 308 function f(opt_propertyBag) { |
| 309 var el = createFunction(tagName, opt_propertyBag); |
| 310 f.decorate(el); |
| 311 for (var propertyName in opt_propertyBag) { |
| 312 el[propertyName] = opt_propertyBag[propertyName]; |
| 313 } |
| 314 return el; |
| 315 } |
| 316 f.decorate = function(el) { |
| 317 el.__proto__ = f.prototype; |
| 318 el.decorate(); |
| 319 }; |
| 320 return f; |
| 321 } |
| 322 function limitInputWidth(el, parentEl, min, opt_scale) { |
| 323 el.style.width = '10px'; |
| 324 var doc = el.ownerDocument; |
| 325 var win = doc.defaultView; |
| 326 var computedStyle = win.getComputedStyle(el); |
| 327 var parentComputedStyle = win.getComputedStyle(parentEl); |
| 328 var rtl = computedStyle.direction == 'rtl'; |
| 329 var inputRect = el.getBoundingClientRect(); |
| 330 var parentRect = parentEl.getBoundingClientRect(); |
| 331 var startPos = rtl ? parentRect.right - inputRect.right : inputRect.left - p
arentRect.left; |
| 332 var inner = parseInt(computedStyle.borderLeftWidth, 10) + parseInt(computedS
tyle.paddingLeft, 10) + parseInt(computedStyle.paddingRight, 10) + parseInt(comp
utedStyle.borderRightWidth, 10); |
| 333 var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) : pa
rseInt(parentComputedStyle.paddingRight, 10); |
| 334 var max = parentEl.clientWidth - startPos - inner - parentPadding; |
| 335 if (opt_scale) max *= opt_scale; |
| 336 function limit() { |
| 337 if (el.scrollWidth > max) { |
| 338 el.style.width = max + 'px'; |
| 339 } else { |
| 340 el.style.width = 0; |
| 341 var sw = el.scrollWidth; |
| 342 if (sw < min) { |
| 343 el.style.width = min + 'px'; |
| 344 } else { |
| 345 el.style.width = sw + 'px'; |
| 346 } |
| 347 } |
| 348 } |
| 349 el.addEventListener('input', limit); |
| 350 limit(); |
| 351 } |
| 352 function toCssPx(pixels) { |
| 353 if (!window.isFinite(pixels)) console.error('Pixel value is not a number: '
+ pixels); |
| 354 return Math.round(pixels) + 'px'; |
| 355 } |
| 356 function swallowDoubleClick(e) { |
| 357 var doc = e.target.ownerDocument; |
| 358 var counter = Math.min(1, e.detail); |
| 359 function swallow(e) { |
| 360 e.stopPropagation(); |
| 361 e.preventDefault(); |
| 362 } |
| 363 function onclick(e) { |
| 364 if (e.detail > counter) { |
| 365 counter = e.detail; |
| 366 swallow(e); |
| 367 } else { |
| 368 doc.removeEventListener('dblclick', swallow, true); |
| 369 doc.removeEventListener('click', onclick, true); |
| 370 } |
| 371 } |
| 372 setTimeout(function() { |
| 373 doc.addEventListener('click', onclick, true); |
| 374 doc.addEventListener('dblclick', swallow, true); |
| 375 }, 0); |
| 376 } |
| 377 return { |
| 378 decorate: decorate, |
| 379 define: define, |
| 380 limitInputWidth: limitInputWidth, |
| 381 toCssPx: toCssPx, |
| 382 swallowDoubleClick: swallowDoubleClick |
| 383 }; |
| 384 }); |
| 385 |
| 386 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 387 // Use of this source code is governed by a BSD-style license that can be |
| 388 // found in the LICENSE file. |
| 389 cr.define('cr.ui', function() { |
| 390 function KeyboardShortcut(shortcut) { |
| 391 var mods = {}; |
| 392 var ident = ''; |
| 393 shortcut.split('|').forEach(function(part) { |
| 394 var partLc = part.toLowerCase(); |
| 395 switch (partLc) { |
| 396 case 'alt': |
| 397 case 'ctrl': |
| 398 case 'meta': |
| 399 case 'shift': |
| 400 mods[partLc + 'Key'] = true; |
| 401 break; |
| 402 |
| 403 default: |
| 404 if (ident) throw Error('Invalid shortcut'); |
| 405 ident = part; |
| 406 } |
| 407 }); |
| 408 this.ident_ = ident; |
| 409 this.mods_ = mods; |
| 410 } |
| 411 KeyboardShortcut.prototype = { |
| 412 matchesEvent: function(e) { |
| 413 if (e.key == this.ident_) { |
| 414 var mods = this.mods_; |
| 415 return [ 'altKey', 'ctrlKey', 'metaKey', 'shiftKey' ].every(function(k)
{ |
| 416 return e[k] == !!mods[k]; |
| 417 }); |
| 418 } |
| 419 return false; |
| 420 } |
| 421 }; |
| 422 var Command = cr.ui.define('command'); |
| 423 Command.prototype = { |
| 424 __proto__: HTMLElement.prototype, |
| 425 decorate: function() { |
| 426 CommandManager.init(assert(this.ownerDocument)); |
| 427 if (this.hasAttribute('shortcut')) this.shortcut = this.getAttribute('shor
tcut'); |
| 428 }, |
| 429 execute: function(opt_element) { |
| 430 if (this.disabled) return; |
| 431 var doc = this.ownerDocument; |
| 432 if (doc.activeElement) { |
| 433 var e = new Event('command', { |
| 434 bubbles: true |
| 435 }); |
| 436 e.command = this; |
| 437 (opt_element || doc.activeElement).dispatchEvent(e); |
| 438 } |
| 439 }, |
| 440 canExecuteChange: function(opt_node) { |
| 441 dispatchCanExecuteEvent(this, opt_node || this.ownerDocument.activeElement
); |
| 442 }, |
| 443 shortcut_: '', |
| 444 get shortcut() { |
| 445 return this.shortcut_; |
| 446 }, |
| 447 set shortcut(shortcut) { |
| 448 var oldShortcut = this.shortcut_; |
| 449 if (shortcut !== oldShortcut) { |
| 450 this.keyboardShortcuts_ = shortcut.split(/\s+/).map(function(shortcut) { |
| 451 return new KeyboardShortcut(shortcut); |
| 452 }); |
| 453 this.shortcut_ = shortcut; |
| 454 cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_, oldShortcut)
; |
| 455 } |
| 456 }, |
| 457 matchesEvent: function(e) { |
| 458 if (!this.keyboardShortcuts_) return false; |
| 459 return this.keyboardShortcuts_.some(function(keyboardShortcut) { |
| 460 return keyboardShortcut.matchesEvent(e); |
| 461 }); |
| 462 } |
| 463 }; |
| 464 cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR); |
| 465 cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR); |
| 466 cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR); |
| 467 cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR); |
| 468 cr.defineProperty(Command, 'hideShortcutText', cr.PropertyKind.BOOL_ATTR); |
| 469 function dispatchCanExecuteEvent(command, target) { |
| 470 var e = new CanExecuteEvent(command); |
| 471 target.dispatchEvent(e); |
| 472 command.disabled = !e.canExecute; |
| 473 } |
| 474 var commandManagers = {}; |
| 475 function CommandManager(doc) { |
| 476 doc.addEventListener('focus', this.handleFocus_.bind(this), true); |
| 477 doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false); |
| 478 } |
| 479 CommandManager.init = function(doc) { |
| 480 var uid = cr.getUid(doc); |
| 481 if (!(uid in commandManagers)) { |
| 482 commandManagers[uid] = new CommandManager(doc); |
| 483 } |
| 484 }; |
| 485 CommandManager.prototype = { |
| 486 handleFocus_: function(e) { |
| 487 var target = e.target; |
| 488 if (target.menu || target.command) return; |
| 489 var commands = Array.prototype.slice.call(target.ownerDocument.querySelect
orAll('command')); |
| 490 commands.forEach(function(command) { |
| 491 dispatchCanExecuteEvent(command, target); |
| 492 }); |
| 493 }, |
| 494 handleKeyDown_: function(e) { |
| 495 var target = e.target; |
| 496 var commands = Array.prototype.slice.call(target.ownerDocument.querySelect
orAll('command')); |
| 497 for (var i = 0, command; command = commands[i]; i++) { |
| 498 if (command.matchesEvent(e)) { |
| 499 command.canExecuteChange(); |
| 500 if (!command.disabled) { |
| 501 e.preventDefault(); |
| 502 e.stopPropagation(); |
| 503 command.execute(); |
| 504 return; |
| 505 } |
| 506 } |
| 507 } |
| 508 } |
| 509 }; |
| 510 function CanExecuteEvent(command) { |
| 511 var e = new Event('canExecute', { |
| 512 bubbles: true, |
| 513 cancelable: true |
| 514 }); |
| 515 e.__proto__ = CanExecuteEvent.prototype; |
| 516 e.command = command; |
| 517 return e; |
| 518 } |
| 519 CanExecuteEvent.prototype = { |
| 520 __proto__: Event.prototype, |
| 521 command: null, |
| 522 canExecute_: false, |
| 523 get canExecute() { |
| 524 return this.canExecute_; |
| 525 }, |
| 526 set canExecute(canExecute) { |
| 527 this.canExecute_ = !!canExecute; |
| 528 this.stopPropagation(); |
| 529 this.preventDefault(); |
| 530 } |
| 531 }; |
| 532 return { |
| 533 Command: Command, |
| 534 CanExecuteEvent: CanExecuteEvent |
| 535 }; |
| 536 }); |
| 537 |
| 538 Polymer({ |
| 539 is: 'app-drawer', |
| 540 properties: { |
| 541 opened: { |
| 542 type: Boolean, |
| 543 value: false, |
| 544 notify: true, |
| 545 reflectToAttribute: true |
| 546 }, |
| 547 persistent: { |
| 548 type: Boolean, |
| 549 value: false, |
| 550 reflectToAttribute: true |
| 551 }, |
| 552 align: { |
| 553 type: String, |
| 554 value: 'left' |
| 555 }, |
| 556 position: { |
| 557 type: String, |
| 558 readOnly: true, |
| 559 value: 'left', |
| 560 reflectToAttribute: true |
| 561 }, |
| 562 swipeOpen: { |
| 563 type: Boolean, |
| 564 value: false, |
| 565 reflectToAttribute: true |
| 566 }, |
| 567 noFocusTrap: { |
| 568 type: Boolean, |
| 569 value: false |
| 570 } |
| 571 }, |
| 572 observers: [ 'resetLayout(position)', '_resetPosition(align, isAttached)' ], |
| 573 _translateOffset: 0, |
| 574 _trackDetails: null, |
| 575 _drawerState: 0, |
| 576 _boundEscKeydownHandler: null, |
| 577 _firstTabStop: null, |
| 578 _lastTabStop: null, |
| 579 ready: function() { |
| 580 this.setScrollDirection('y'); |
| 581 this._setTransitionDuration('0s'); |
| 582 }, |
| 583 attached: function() { |
| 584 Polymer.RenderStatus.afterNextRender(this, function() { |
| 585 this._setTransitionDuration(''); |
| 586 this._boundEscKeydownHandler = this._escKeydownHandler.bind(this); |
| 587 this._resetDrawerState(); |
| 588 this.listen(this, 'track', '_track'); |
| 589 this.addEventListener('transitionend', this._transitionend.bind(this)); |
| 590 this.addEventListener('keydown', this._tabKeydownHandler.bind(this)); |
| 591 }); |
| 592 }, |
| 593 detached: function() { |
| 594 document.removeEventListener('keydown', this._boundEscKeydownHandler); |
| 595 }, |
| 596 open: function() { |
| 597 this.opened = true; |
| 598 }, |
| 599 close: function() { |
| 600 this.opened = false; |
| 601 }, |
| 602 toggle: function() { |
| 603 this.opened = !this.opened; |
| 604 }, |
| 605 getWidth: function() { |
| 606 return this.$.contentContainer.offsetWidth; |
| 607 }, |
| 608 resetLayout: function() { |
| 609 this.debounce('_resetLayout', function() { |
| 610 this.fire('app-drawer-reset-layout'); |
| 611 }, 1); |
| 612 }, |
| 613 _isRTL: function() { |
| 614 return window.getComputedStyle(this).direction === 'rtl'; |
| 615 }, |
| 616 _resetPosition: function() { |
| 617 switch (this.align) { |
| 618 case 'start': |
| 619 this._setPosition(this._isRTL() ? 'right' : 'left'); |
| 620 return; |
| 621 |
| 622 case 'end': |
| 623 this._setPosition(this._isRTL() ? 'left' : 'right'); |
| 624 return; |
| 625 } |
| 626 this._setPosition(this.align); |
| 627 }, |
| 628 _escKeydownHandler: function(event) { |
| 629 var ESC_KEYCODE = 27; |
| 630 if (event.keyCode === ESC_KEYCODE) { |
| 631 event.preventDefault(); |
| 632 this.close(); |
| 633 } |
| 634 }, |
| 635 _track: function(event) { |
| 636 if (this.persistent) { |
| 637 return; |
| 638 } |
| 639 event.preventDefault(); |
| 640 switch (event.detail.state) { |
| 641 case 'start': |
| 642 this._trackStart(event); |
| 643 break; |
| 644 |
| 645 case 'track': |
| 646 this._trackMove(event); |
| 647 break; |
| 648 |
| 649 case 'end': |
| 650 this._trackEnd(event); |
| 651 break; |
| 652 } |
| 653 }, |
| 654 _trackStart: function(event) { |
| 655 this._drawerState = this._DRAWER_STATE.TRACKING; |
| 656 this._setTransitionDuration('0s'); |
| 657 this.style.visibility = 'visible'; |
| 658 var rect = this.$.contentContainer.getBoundingClientRect(); |
| 659 if (this.position === 'left') { |
| 660 this._translateOffset = rect.left; |
| 661 } else { |
| 662 this._translateOffset = rect.right - window.innerWidth; |
| 663 } |
| 664 this._trackDetails = []; |
| 665 }, |
| 666 _trackMove: function(event) { |
| 667 this._translateDrawer(event.detail.dx + this._translateOffset); |
| 668 this._trackDetails.push({ |
| 669 dx: event.detail.dx, |
| 670 timeStamp: Date.now() |
| 671 }); |
| 672 }, |
| 673 _trackEnd: function(event) { |
| 674 var x = event.detail.dx + this._translateOffset; |
| 675 var drawerWidth = this.getWidth(); |
| 676 var isPositionLeft = this.position === 'left'; |
| 677 var isInEndState = isPositionLeft ? x >= 0 || x <= -drawerWidth : x <= 0 ||
x >= drawerWidth; |
| 678 if (!isInEndState) { |
| 679 var trackDetails = this._trackDetails; |
| 680 this._trackDetails = null; |
| 681 this._flingDrawer(event, trackDetails); |
| 682 if (this._drawerState === this._DRAWER_STATE.FLINGING) { |
| 683 return; |
| 684 } |
| 685 } |
| 686 var halfWidth = drawerWidth / 2; |
| 687 if (event.detail.dx < -halfWidth) { |
| 688 this.opened = this.position === 'right'; |
| 689 } else if (event.detail.dx > halfWidth) { |
| 690 this.opened = this.position === 'left'; |
| 691 } |
| 692 if (isInEndState) { |
| 693 this._resetDrawerState(); |
| 694 } |
| 695 this._setTransitionDuration(''); |
| 696 this._resetDrawerTranslate(); |
| 697 this.style.visibility = ''; |
| 698 }, |
| 699 _calculateVelocity: function(event, trackDetails) { |
| 700 var now = Date.now(); |
| 701 var timeLowerBound = now - 100; |
| 702 var trackDetail; |
| 703 var min = 0; |
| 704 var max = trackDetails.length - 1; |
| 705 while (min <= max) { |
| 706 var mid = min + max >> 1; |
| 707 var d = trackDetails[mid]; |
| 708 if (d.timeStamp >= timeLowerBound) { |
| 709 trackDetail = d; |
| 710 max = mid - 1; |
| 711 } else { |
| 712 min = mid + 1; |
| 713 } |
| 714 } |
| 715 if (trackDetail) { |
| 716 var dx = event.detail.dx - trackDetail.dx; |
| 717 var dt = now - trackDetail.timeStamp || 1; |
| 718 return dx / dt; |
| 719 } |
| 720 return 0; |
| 721 }, |
| 722 _flingDrawer: function(event, trackDetails) { |
| 723 var velocity = this._calculateVelocity(event, trackDetails); |
| 724 if (Math.abs(velocity) < this._MIN_FLING_THRESHOLD) { |
| 725 return; |
| 726 } |
| 727 this._drawerState = this._DRAWER_STATE.FLINGING; |
| 728 var x = event.detail.dx + this._translateOffset; |
| 729 var drawerWidth = this.getWidth(); |
| 730 var isPositionLeft = this.position === 'left'; |
| 731 var isVelocityPositive = velocity > 0; |
| 732 var isClosingLeft = !isVelocityPositive && isPositionLeft; |
| 733 var isClosingRight = isVelocityPositive && !isPositionLeft; |
| 734 var dx; |
| 735 if (isClosingLeft) { |
| 736 dx = -(x + drawerWidth); |
| 737 } else if (isClosingRight) { |
| 738 dx = drawerWidth - x; |
| 739 } else { |
| 740 dx = -x; |
| 741 } |
| 742 if (isVelocityPositive) { |
| 743 velocity = Math.max(velocity, this._MIN_TRANSITION_VELOCITY); |
| 744 this.opened = this.position === 'left'; |
| 745 } else { |
| 746 velocity = Math.min(velocity, -this._MIN_TRANSITION_VELOCITY); |
| 747 this.opened = this.position === 'right'; |
| 748 } |
| 749 this._setTransitionDuration(this._FLING_INITIAL_SLOPE * dx / velocity + 'ms'
); |
| 750 this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION); |
| 751 this._resetDrawerTranslate(); |
| 752 }, |
| 753 _transitionend: function(event) { |
| 754 var target = Polymer.dom(event).rootTarget; |
| 755 if (target === this.$.contentContainer || target === this.$.scrim) { |
| 756 if (this._drawerState === this._DRAWER_STATE.FLINGING) { |
| 757 this._setTransitionDuration(''); |
| 758 this._setTransitionTimingFunction(''); |
| 759 this.style.visibility = ''; |
| 760 } |
| 761 this._resetDrawerState(); |
| 762 } |
| 763 }, |
| 764 _setTransitionDuration: function(duration) { |
| 765 this.$.contentContainer.style.transitionDuration = duration; |
| 766 this.$.scrim.style.transitionDuration = duration; |
| 767 }, |
| 768 _setTransitionTimingFunction: function(timingFunction) { |
| 769 this.$.contentContainer.style.transitionTimingFunction = timingFunction; |
| 770 this.$.scrim.style.transitionTimingFunction = timingFunction; |
| 771 }, |
| 772 _translateDrawer: function(x) { |
| 773 var drawerWidth = this.getWidth(); |
| 774 if (this.position === 'left') { |
| 775 x = Math.max(-drawerWidth, Math.min(x, 0)); |
| 776 this.$.scrim.style.opacity = 1 + x / drawerWidth; |
| 777 } else { |
| 778 x = Math.max(0, Math.min(x, drawerWidth)); |
| 779 this.$.scrim.style.opacity = 1 - x / drawerWidth; |
| 780 } |
| 781 this.translate3d(x + 'px', '0', '0', this.$.contentContainer); |
| 782 }, |
| 783 _resetDrawerTranslate: function() { |
| 784 this.$.scrim.style.opacity = ''; |
| 785 this.transform('', this.$.contentContainer); |
| 786 }, |
| 787 _resetDrawerState: function() { |
| 788 var oldState = this._drawerState; |
| 789 if (this.opened) { |
| 790 this._drawerState = this.persistent ? this._DRAWER_STATE.OPENED_PERSISTENT
: this._DRAWER_STATE.OPENED; |
| 791 } else { |
| 792 this._drawerState = this._DRAWER_STATE.CLOSED; |
| 793 } |
| 794 if (oldState !== this._drawerState) { |
| 795 if (this._drawerState === this._DRAWER_STATE.OPENED) { |
| 796 this._setKeyboardFocusTrap(); |
| 797 document.addEventListener('keydown', this._boundEscKeydownHandler); |
| 798 document.body.style.overflow = 'hidden'; |
| 799 } else { |
| 800 document.removeEventListener('keydown', this._boundEscKeydownHandler); |
| 801 document.body.style.overflow = ''; |
| 802 } |
| 803 if (oldState !== this._DRAWER_STATE.INIT) { |
| 804 this.fire('app-drawer-transitioned'); |
| 805 } |
| 806 } |
| 807 }, |
| 808 _setKeyboardFocusTrap: function() { |
| 809 if (this.noFocusTrap) { |
| 810 return; |
| 811 } |
| 812 var focusableElementsSelector = [ 'a[href]:not([tabindex="-1"])', 'area[href
]:not([tabindex="-1"])', 'input:not([disabled]):not([tabindex="-1"])', 'select:n
ot([disabled]):not([tabindex="-1"])', 'textarea:not([disabled]):not([tabindex="-
1"])', 'button:not([disabled]):not([tabindex="-1"])', 'iframe:not([tabindex="-1"
])', '[tabindex]:not([tabindex="-1"])', '[contentEditable=true]:not([tabindex="-
1"])' ].join(','); |
| 813 var focusableElements = Polymer.dom(this).querySelectorAll(focusableElements
Selector); |
| 814 if (focusableElements.length > 0) { |
| 815 this._firstTabStop = focusableElements[0]; |
| 816 this._lastTabStop = focusableElements[focusableElements.length - 1]; |
| 817 } else { |
| 818 this._firstTabStop = null; |
| 819 this._lastTabStop = null; |
| 820 } |
| 821 var tabindex = this.getAttribute('tabindex'); |
| 822 if (tabindex && parseInt(tabindex, 10) > -1) { |
| 823 this.focus(); |
| 824 } else if (this._firstTabStop) { |
| 825 this._firstTabStop.focus(); |
| 826 } |
| 827 }, |
| 828 _tabKeydownHandler: function(event) { |
| 829 if (this.noFocusTrap) { |
| 830 return; |
| 831 } |
| 832 var TAB_KEYCODE = 9; |
| 833 if (this._drawerState === this._DRAWER_STATE.OPENED && event.keyCode === TAB
_KEYCODE) { |
| 834 if (event.shiftKey) { |
| 835 if (this._firstTabStop && Polymer.dom(event).localTarget === this._first
TabStop) { |
| 836 event.preventDefault(); |
| 837 this._lastTabStop.focus(); |
| 838 } |
| 839 } else { |
| 840 if (this._lastTabStop && Polymer.dom(event).localTarget === this._lastTa
bStop) { |
| 841 event.preventDefault(); |
| 842 this._firstTabStop.focus(); |
| 843 } |
| 844 } |
| 845 } |
| 846 }, |
| 847 _MIN_FLING_THRESHOLD: .2, |
| 848 _MIN_TRANSITION_VELOCITY: 1.2, |
| 849 _FLING_TIMING_FUNCTION: 'cubic-bezier(0.667, 1, 0.667, 1)', |
| 850 _FLING_INITIAL_SLOPE: 1.5, |
| 851 _DRAWER_STATE: { |
| 852 INIT: 0, |
| 853 OPENED: 1, |
| 854 OPENED_PERSISTENT: 2, |
| 855 CLOSED: 3, |
| 856 TRACKING: 4, |
| 857 FLINGING: 5 |
| 858 } |
| 859 }); |
| 860 |
| 861 (function() { |
| 862 'use strict'; |
| 863 Polymer({ |
| 864 is: 'iron-location', |
| 865 properties: { |
| 866 path: { |
| 867 type: String, |
| 868 notify: true, |
| 869 value: function() { |
| 870 return window.decodeURIComponent(window.location.pathname); |
| 871 } |
| 872 }, |
| 873 query: { |
| 874 type: String, |
| 875 notify: true, |
| 876 value: function() { |
| 877 return window.decodeURIComponent(window.location.search.slice(1)); |
| 878 } |
| 879 }, |
| 880 hash: { |
| 881 type: String, |
| 882 notify: true, |
| 883 value: function() { |
| 884 return window.decodeURIComponent(window.location.hash.slice(1)); |
| 885 } |
| 886 }, |
| 887 dwellTime: { |
| 888 type: Number, |
| 889 value: 2e3 |
| 890 }, |
| 891 urlSpaceRegex: { |
| 892 type: String, |
| 893 value: '' |
| 894 }, |
| 895 _urlSpaceRegExp: { |
| 896 computed: '_makeRegExp(urlSpaceRegex)' |
| 897 }, |
| 898 _lastChangedAt: { |
| 899 type: Number |
| 900 }, |
| 901 _initialized: { |
| 902 type: Boolean, |
| 903 value: false |
| 904 } |
| 905 }, |
| 906 hostAttributes: { |
| 907 hidden: true |
| 908 }, |
| 909 observers: [ '_updateUrl(path, query, hash)' ], |
| 910 attached: function() { |
| 911 this.listen(window, 'hashchange', '_hashChanged'); |
| 912 this.listen(window, 'location-changed', '_urlChanged'); |
| 913 this.listen(window, 'popstate', '_urlChanged'); |
| 914 this.listen(document.body, 'click', '_globalOnClick'); |
| 915 this._lastChangedAt = window.performance.now() - (this.dwellTime - 200); |
| 916 this._initialized = true; |
| 917 this._urlChanged(); |
| 918 }, |
| 919 detached: function() { |
| 920 this.unlisten(window, 'hashchange', '_hashChanged'); |
| 921 this.unlisten(window, 'location-changed', '_urlChanged'); |
| 922 this.unlisten(window, 'popstate', '_urlChanged'); |
| 923 this.unlisten(document.body, 'click', '_globalOnClick'); |
| 924 this._initialized = false; |
| 925 }, |
| 926 _hashChanged: function() { |
| 927 this.hash = window.decodeURIComponent(window.location.hash.substring(1)); |
| 928 }, |
| 929 _urlChanged: function() { |
| 930 this._dontUpdateUrl = true; |
| 931 this._hashChanged(); |
| 932 this.path = window.decodeURIComponent(window.location.pathname); |
| 933 this.query = window.decodeURIComponent(window.location.search.substring(1)
); |
| 934 this._dontUpdateUrl = false; |
| 935 this._updateUrl(); |
| 936 }, |
| 937 _getUrl: function() { |
| 938 var partiallyEncodedPath = window.encodeURI(this.path).replace(/\#/g, '%23
').replace(/\?/g, '%3F'); |
| 939 var partiallyEncodedQuery = ''; |
| 940 if (this.query) { |
| 941 partiallyEncodedQuery = '?' + window.encodeURI(this.query).replace(/\#/g
, '%23'); |
| 942 } |
| 943 var partiallyEncodedHash = ''; |
| 944 if (this.hash) { |
| 945 partiallyEncodedHash = '#' + window.encodeURI(this.hash); |
| 946 } |
| 947 return partiallyEncodedPath + partiallyEncodedQuery + partiallyEncodedHash
; |
| 948 }, |
| 949 _updateUrl: function() { |
| 950 if (this._dontUpdateUrl || !this._initialized) { |
| 951 return; |
| 952 } |
| 953 if (this.path === window.decodeURIComponent(window.location.pathname) && t
his.query === window.decodeURIComponent(window.location.search.substring(1)) &&
this.hash === window.decodeURIComponent(window.location.hash.substring(1))) { |
| 954 return; |
| 955 } |
| 956 var newUrl = this._getUrl(); |
| 957 var fullNewUrl = new URL(newUrl, window.location.protocol + '//' + window.
location.host).href; |
| 958 var now = window.performance.now(); |
| 959 var shouldReplace = this._lastChangedAt + this.dwellTime > now; |
| 960 this._lastChangedAt = now; |
| 961 if (shouldReplace) { |
| 962 window.history.replaceState({}, '', fullNewUrl); |
| 963 } else { |
| 964 window.history.pushState({}, '', fullNewUrl); |
| 965 } |
| 966 this.fire('location-changed', {}, { |
| 967 node: window |
| 968 }); |
| 969 }, |
| 970 _globalOnClick: function(event) { |
| 971 if (event.defaultPrevented) { |
| 972 return; |
| 973 } |
| 974 var href = this._getSameOriginLinkHref(event); |
| 975 if (!href) { |
| 976 return; |
| 977 } |
| 978 event.preventDefault(); |
| 979 if (href === window.location.href) { |
| 980 return; |
| 981 } |
| 982 window.history.pushState({}, '', href); |
| 983 this.fire('location-changed', {}, { |
| 984 node: window |
| 985 }); |
| 986 }, |
| 987 _getSameOriginLinkHref: function(event) { |
| 988 if (event.button !== 0) { |
| 989 return null; |
| 990 } |
| 991 if (event.metaKey || event.ctrlKey) { |
| 992 return null; |
| 993 } |
| 994 var eventPath = Polymer.dom(event).path; |
| 995 var anchor = null; |
| 996 for (var i = 0; i < eventPath.length; i++) { |
| 997 var element = eventPath[i]; |
| 998 if (element.tagName === 'A' && element.href) { |
| 999 anchor = element; |
| 1000 break; |
| 1001 } |
| 1002 } |
| 1003 if (!anchor) { |
| 1004 return null; |
| 1005 } |
| 1006 if (anchor.target === '_blank') { |
| 1007 return null; |
| 1008 } |
| 1009 if ((anchor.target === '_top' || anchor.target === '_parent') && window.to
p !== window) { |
| 1010 return null; |
| 1011 } |
| 1012 var href = anchor.href; |
| 1013 var url; |
| 1014 if (document.baseURI != null) { |
| 1015 url = new URL(href, document.baseURI); |
| 1016 } else { |
| 1017 url = new URL(href); |
| 1018 } |
| 1019 var origin; |
| 1020 if (window.location.origin) { |
| 1021 origin = window.location.origin; |
| 1022 } else { |
| 1023 origin = window.location.protocol + '//' + window.location.hostname; |
| 1024 if (window.location.port) { |
| 1025 origin += ':' + window.location.port; |
| 1026 } |
| 1027 } |
| 1028 if (url.origin !== origin) { |
| 1029 return null; |
| 1030 } |
| 1031 var normalizedHref = url.pathname + url.search + url.hash; |
| 1032 if (this._urlSpaceRegExp && !this._urlSpaceRegExp.test(normalizedHref)) { |
| 1033 return null; |
| 1034 } |
| 1035 var fullNormalizedHref = new URL(normalizedHref, window.location.href).hre
f; |
| 1036 return fullNormalizedHref; |
| 1037 }, |
| 1038 _makeRegExp: function(urlSpaceRegex) { |
| 1039 return RegExp(urlSpaceRegex); |
| 1040 } |
| 1041 }); |
| 1042 })(); |
| 1043 |
| 1044 'use strict'; |
| 1045 |
| 1046 Polymer({ |
| 1047 is: 'iron-query-params', |
| 1048 properties: { |
| 1049 paramsString: { |
| 1050 type: String, |
| 1051 notify: true, |
| 1052 observer: 'paramsStringChanged' |
| 1053 }, |
| 1054 paramsObject: { |
| 1055 type: Object, |
| 1056 notify: true, |
| 1057 value: function() { |
| 1058 return {}; |
| 1059 } |
| 1060 }, |
| 1061 _dontReact: { |
| 1062 type: Boolean, |
| 1063 value: false |
| 1064 } |
| 1065 }, |
| 1066 hostAttributes: { |
| 1067 hidden: true |
| 1068 }, |
| 1069 observers: [ 'paramsObjectChanged(paramsObject.*)' ], |
| 1070 paramsStringChanged: function() { |
| 1071 this._dontReact = true; |
| 1072 this.paramsObject = this._decodeParams(this.paramsString); |
| 1073 this._dontReact = false; |
| 1074 }, |
| 1075 paramsObjectChanged: function() { |
| 1076 if (this._dontReact) { |
| 1077 return; |
| 1078 } |
| 1079 this.paramsString = this._encodeParams(this.paramsObject); |
| 1080 }, |
| 1081 _encodeParams: function(params) { |
| 1082 var encodedParams = []; |
| 1083 for (var key in params) { |
| 1084 var value = params[key]; |
| 1085 if (value === '') { |
| 1086 encodedParams.push(encodeURIComponent(key)); |
| 1087 } else if (value) { |
| 1088 encodedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(va
lue.toString())); |
| 1089 } |
| 1090 } |
| 1091 return encodedParams.join('&'); |
| 1092 }, |
| 1093 _decodeParams: function(paramString) { |
| 1094 var params = {}; |
| 1095 paramString = (paramString || '').replace(/\+/g, '%20'); |
| 1096 var paramList = paramString.split('&'); |
| 1097 for (var i = 0; i < paramList.length; i++) { |
| 1098 var param = paramList[i].split('='); |
| 1099 if (param[0]) { |
| 1100 params[decodeURIComponent(param[0])] = decodeURIComponent(param[1] || ''
); |
| 1101 } |
| 1102 } |
| 1103 return params; |
| 1104 } |
| 1105 }); |
| 1106 |
| 1107 'use strict'; |
| 1108 |
| 1109 Polymer.AppRouteConverterBehavior = { |
| 1110 properties: { |
| 1111 route: { |
| 1112 type: Object, |
| 1113 notify: true |
| 1114 }, |
| 1115 queryParams: { |
| 1116 type: Object, |
| 1117 notify: true |
| 1118 }, |
| 1119 path: { |
| 1120 type: String, |
| 1121 notify: true |
| 1122 } |
| 1123 }, |
| 1124 observers: [ '_locationChanged(path, queryParams)', '_routeChanged(route.prefi
x, route.path)', '_routeQueryParamsChanged(route.__queryParams)' ], |
| 1125 created: function() { |
| 1126 this.linkPaths('route.__queryParams', 'queryParams'); |
| 1127 this.linkPaths('queryParams', 'route.__queryParams'); |
| 1128 }, |
| 1129 _locationChanged: function() { |
| 1130 if (this.route && this.route.path === this.path && this.queryParams === this
.route.__queryParams) { |
| 1131 return; |
| 1132 } |
| 1133 this.route = { |
| 1134 prefix: '', |
| 1135 path: this.path, |
| 1136 __queryParams: this.queryParams |
| 1137 }; |
| 1138 }, |
| 1139 _routeChanged: function() { |
| 1140 if (!this.route) { |
| 1141 return; |
| 1142 } |
| 1143 this.path = this.route.prefix + this.route.path; |
| 1144 }, |
| 1145 _routeQueryParamsChanged: function(queryParams) { |
| 1146 if (!this.route) { |
| 1147 return; |
| 1148 } |
| 1149 this.queryParams = queryParams; |
| 1150 } |
| 1151 }; |
| 1152 |
| 1153 'use strict'; |
| 1154 |
| 1155 Polymer({ |
| 1156 is: 'app-location', |
| 1157 properties: { |
| 1158 route: { |
| 1159 type: Object, |
| 1160 notify: true |
| 1161 }, |
| 1162 useHashAsPath: { |
| 1163 type: Boolean, |
| 1164 value: false |
| 1165 }, |
| 1166 urlSpaceRegex: { |
| 1167 type: String, |
| 1168 notify: true |
| 1169 }, |
| 1170 __queryParams: { |
| 1171 type: Object |
| 1172 }, |
| 1173 __path: { |
| 1174 type: String |
| 1175 }, |
| 1176 __query: { |
| 1177 type: String |
| 1178 }, |
| 1179 __hash: { |
| 1180 type: String |
| 1181 }, |
| 1182 path: { |
| 1183 type: String, |
| 1184 observer: '__onPathChanged' |
| 1185 } |
| 1186 }, |
| 1187 behaviors: [ Polymer.AppRouteConverterBehavior ], |
| 1188 observers: [ '__computeRoutePath(useHashAsPath, __hash, __path)' ], |
| 1189 __computeRoutePath: function() { |
| 1190 this.path = this.useHashAsPath ? this.__hash : this.__path; |
| 1191 }, |
| 1192 __onPathChanged: function() { |
| 1193 if (!this._readied) { |
| 1194 return; |
| 1195 } |
| 1196 if (this.useHashAsPath) { |
| 1197 this.__hash = this.path; |
| 1198 } else { |
| 1199 this.__path = this.path; |
| 1200 } |
| 1201 } |
| 1202 }); |
| 1203 |
| 1204 'use strict'; |
| 1205 |
| 1206 Polymer({ |
| 1207 is: 'app-route', |
| 1208 properties: { |
| 1209 route: { |
| 1210 type: Object, |
| 1211 notify: true |
| 1212 }, |
| 1213 pattern: { |
| 1214 type: String |
| 1215 }, |
| 1216 data: { |
| 1217 type: Object, |
| 1218 value: function() { |
| 1219 return {}; |
| 1220 }, |
| 1221 notify: true |
| 1222 }, |
| 1223 queryParams: { |
| 1224 type: Object, |
| 1225 value: function() { |
| 1226 return {}; |
| 1227 }, |
| 1228 notify: true |
| 1229 }, |
| 1230 tail: { |
| 1231 type: Object, |
| 1232 value: function() { |
| 1233 return { |
| 1234 path: null, |
| 1235 prefix: null, |
| 1236 __queryParams: null |
| 1237 }; |
| 1238 }, |
| 1239 notify: true |
| 1240 }, |
| 1241 active: { |
| 1242 type: Boolean, |
| 1243 notify: true, |
| 1244 readOnly: true |
| 1245 }, |
| 1246 _queryParamsUpdating: { |
| 1247 type: Boolean, |
| 1248 value: false |
| 1249 }, |
| 1250 _matched: { |
| 1251 type: String, |
| 1252 value: '' |
| 1253 } |
| 1254 }, |
| 1255 observers: [ '__tryToMatch(route.path, pattern)', '__updatePathOnDataChange(da
ta.*)', '__tailPathChanged(tail.path)', '__routeQueryParamsChanged(route.__query
Params)', '__tailQueryParamsChanged(tail.__queryParams)', '__queryParamsChanged(
queryParams.*)' ], |
| 1256 created: function() { |
| 1257 this.linkPaths('route.__queryParams', 'tail.__queryParams'); |
| 1258 this.linkPaths('tail.__queryParams', 'route.__queryParams'); |
| 1259 }, |
| 1260 __routeQueryParamsChanged: function(queryParams) { |
| 1261 if (queryParams && this.tail) { |
| 1262 this.set('tail.__queryParams', queryParams); |
| 1263 if (!this.active || this._queryParamsUpdating) { |
| 1264 return; |
| 1265 } |
| 1266 var copyOfQueryParams = {}; |
| 1267 var anythingChanged = false; |
| 1268 for (var key in queryParams) { |
| 1269 copyOfQueryParams[key] = queryParams[key]; |
| 1270 if (anythingChanged || !this.queryParams || queryParams[key] !== this.qu
eryParams[key]) { |
| 1271 anythingChanged = true; |
| 1272 } |
| 1273 } |
| 1274 for (var key in this.queryParams) { |
| 1275 if (anythingChanged || !(key in queryParams)) { |
| 1276 anythingChanged = true; |
| 1277 break; |
| 1278 } |
| 1279 } |
| 1280 if (!anythingChanged) { |
| 1281 return; |
| 1282 } |
| 1283 this._queryParamsUpdating = true; |
| 1284 this.set('queryParams', copyOfQueryParams); |
| 1285 this._queryParamsUpdating = false; |
| 1286 } |
| 1287 }, |
| 1288 __tailQueryParamsChanged: function(queryParams) { |
| 1289 if (queryParams && this.route) { |
| 1290 this.set('route.__queryParams', queryParams); |
| 1291 } |
| 1292 }, |
| 1293 __queryParamsChanged: function(changes) { |
| 1294 if (!this.active || this._queryParamsUpdating) { |
| 1295 return; |
| 1296 } |
| 1297 this.set('route.__' + changes.path, changes.value); |
| 1298 }, |
| 1299 __resetProperties: function() { |
| 1300 this._setActive(false); |
| 1301 this._matched = null; |
| 1302 }, |
| 1303 __tryToMatch: function() { |
| 1304 if (!this.route) { |
| 1305 return; |
| 1306 } |
| 1307 var path = this.route.path; |
| 1308 var pattern = this.pattern; |
| 1309 if (!pattern) { |
| 1310 return; |
| 1311 } |
| 1312 if (!path) { |
| 1313 this.__resetProperties(); |
| 1314 return; |
| 1315 } |
| 1316 var remainingPieces = path.split('/'); |
| 1317 var patternPieces = pattern.split('/'); |
| 1318 var matched = []; |
| 1319 var namedMatches = {}; |
| 1320 for (var i = 0; i < patternPieces.length; i++) { |
| 1321 var patternPiece = patternPieces[i]; |
| 1322 if (!patternPiece && patternPiece !== '') { |
| 1323 break; |
| 1324 } |
| 1325 var pathPiece = remainingPieces.shift(); |
| 1326 if (!pathPiece && pathPiece !== '') { |
| 1327 this.__resetProperties(); |
| 1328 return; |
| 1329 } |
| 1330 matched.push(pathPiece); |
| 1331 if (patternPiece.charAt(0) == ':') { |
| 1332 namedMatches[patternPiece.slice(1)] = pathPiece; |
| 1333 } else if (patternPiece !== pathPiece) { |
| 1334 this.__resetProperties(); |
| 1335 return; |
| 1336 } |
| 1337 } |
| 1338 this._matched = matched.join('/'); |
| 1339 var propertyUpdates = {}; |
| 1340 if (!this.active) { |
| 1341 propertyUpdates.active = true; |
| 1342 } |
| 1343 var tailPrefix = this.route.prefix + this._matched; |
| 1344 var tailPath = remainingPieces.join('/'); |
| 1345 if (remainingPieces.length > 0) { |
| 1346 tailPath = '/' + tailPath; |
| 1347 } |
| 1348 if (!this.tail || this.tail.prefix !== tailPrefix || this.tail.path !== tail
Path) { |
| 1349 propertyUpdates.tail = { |
| 1350 prefix: tailPrefix, |
| 1351 path: tailPath, |
| 1352 __queryParams: this.route.__queryParams |
| 1353 }; |
| 1354 } |
| 1355 propertyUpdates.data = namedMatches; |
| 1356 this._dataInUrl = {}; |
| 1357 for (var key in namedMatches) { |
| 1358 this._dataInUrl[key] = namedMatches[key]; |
| 1359 } |
| 1360 this.__setMulti(propertyUpdates); |
| 1361 }, |
| 1362 __tailPathChanged: function() { |
| 1363 if (!this.active) { |
| 1364 return; |
| 1365 } |
| 1366 var tailPath = this.tail.path; |
| 1367 var newPath = this._matched; |
| 1368 if (tailPath) { |
| 1369 if (tailPath.charAt(0) !== '/') { |
| 1370 tailPath = '/' + tailPath; |
| 1371 } |
| 1372 newPath += tailPath; |
| 1373 } |
| 1374 this.set('route.path', newPath); |
| 1375 }, |
| 1376 __updatePathOnDataChange: function() { |
| 1377 if (!this.route || !this.active) { |
| 1378 return; |
| 1379 } |
| 1380 var newPath = this.__getLink({}); |
| 1381 var oldPath = this.__getLink(this._dataInUrl); |
| 1382 if (newPath === oldPath) { |
| 1383 return; |
| 1384 } |
| 1385 this.set('route.path', newPath); |
| 1386 }, |
| 1387 __getLink: function(overrideValues) { |
| 1388 var values = { |
| 1389 tail: null |
| 1390 }; |
| 1391 for (var key in this.data) { |
| 1392 values[key] = this.data[key]; |
| 1393 } |
| 1394 for (var key in overrideValues) { |
| 1395 values[key] = overrideValues[key]; |
| 1396 } |
| 1397 var patternPieces = this.pattern.split('/'); |
| 1398 var interp = patternPieces.map(function(value) { |
| 1399 if (value[0] == ':') { |
| 1400 value = values[value.slice(1)]; |
| 1401 } |
| 1402 return value; |
| 1403 }, this); |
| 1404 if (values.tail && values.tail.path) { |
| 1405 if (interp.length > 0 && values.tail.path.charAt(0) === '/') { |
| 1406 interp.push(values.tail.path.slice(1)); |
| 1407 } else { |
| 1408 interp.push(values.tail.path); |
| 1409 } |
| 1410 } |
| 1411 return interp.join('/'); |
| 1412 }, |
| 1413 __setMulti: function(setObj) { |
| 1414 for (var property in setObj) { |
| 1415 this._propertySetter(property, setObj[property]); |
| 1416 } |
| 1417 for (var property in setObj) { |
| 1418 this._pathEffector(property, this[property]); |
| 1419 this._notifyPathUp(property, this[property]); |
| 1420 } |
| 1421 } |
| 1422 }); |
| 1423 |
| 1424 Polymer({ |
| 1425 is: 'iron-media-query', |
| 1426 properties: { |
| 1427 queryMatches: { |
| 1428 type: Boolean, |
| 1429 value: false, |
| 1430 readOnly: true, |
| 1431 notify: true |
| 1432 }, |
| 1433 query: { |
| 1434 type: String, |
| 1435 observer: 'queryChanged' |
| 1436 }, |
| 1437 full: { |
| 1438 type: Boolean, |
| 1439 value: false |
| 1440 }, |
| 1441 _boundMQHandler: { |
| 1442 value: function() { |
| 1443 return this.queryHandler.bind(this); |
| 1444 } |
| 1445 }, |
| 1446 _mq: { |
| 1447 value: null |
| 1448 } |
| 1449 }, |
| 1450 attached: function() { |
| 1451 this.style.display = 'none'; |
| 1452 this.queryChanged(); |
| 1453 }, |
| 1454 detached: function() { |
| 1455 this._remove(); |
| 1456 }, |
| 1457 _add: function() { |
| 1458 if (this._mq) { |
| 1459 this._mq.addListener(this._boundMQHandler); |
| 1460 } |
| 1461 }, |
| 1462 _remove: function() { |
| 1463 if (this._mq) { |
| 1464 this._mq.removeListener(this._boundMQHandler); |
| 1465 } |
| 1466 this._mq = null; |
| 1467 }, |
| 1468 queryChanged: function() { |
| 1469 this._remove(); |
| 1470 var query = this.query; |
| 1471 if (!query) { |
| 1472 return; |
| 1473 } |
| 1474 if (!this.full && query[0] !== '(') { |
| 1475 query = '(' + query + ')'; |
| 1476 } |
| 1477 this._mq = window.matchMedia(query); |
| 1478 this._add(); |
| 1479 this.queryHandler(this._mq); |
| 1480 }, |
| 1481 queryHandler: function(mq) { |
| 1482 this._setQueryMatches(mq.matches); |
| 1483 } |
| 1484 }); |
| 1485 |
| 1486 Polymer.IronResizableBehavior = { |
| 1487 properties: { |
| 1488 _parentResizable: { |
| 1489 type: Object, |
| 1490 observer: '_parentResizableChanged' |
| 1491 }, |
| 1492 _notifyingDescendant: { |
| 1493 type: Boolean, |
| 1494 value: false |
| 1495 } |
| 1496 }, |
| 1497 listeners: { |
| 1498 'iron-request-resize-notifications': '_onIronRequestResizeNotifications' |
| 1499 }, |
| 1500 created: function() { |
| 1501 this._interestedResizables = []; |
| 1502 this._boundNotifyResize = this.notifyResize.bind(this); |
| 1503 }, |
| 1504 attached: function() { |
| 1505 this.fire('iron-request-resize-notifications', null, { |
| 1506 node: this, |
| 1507 bubbles: true, |
| 1508 cancelable: true |
| 1509 }); |
| 1510 if (!this._parentResizable) { |
| 1511 window.addEventListener('resize', this._boundNotifyResize); |
| 1512 this.notifyResize(); |
| 1513 } |
| 1514 }, |
| 1515 detached: function() { |
| 1516 if (this._parentResizable) { |
| 1517 this._parentResizable.stopResizeNotificationsFor(this); |
| 1518 } else { |
| 1519 window.removeEventListener('resize', this._boundNotifyResize); |
| 1520 } |
| 1521 this._parentResizable = null; |
| 1522 }, |
| 1523 notifyResize: function() { |
| 1524 if (!this.isAttached) { |
| 1525 return; |
| 1526 } |
| 1527 this._interestedResizables.forEach(function(resizable) { |
| 1528 if (this.resizerShouldNotify(resizable)) { |
| 1529 this._notifyDescendant(resizable); |
| 1530 } |
| 1531 }, this); |
| 1532 this._fireResize(); |
| 1533 }, |
| 1534 assignParentResizable: function(parentResizable) { |
| 1535 this._parentResizable = parentResizable; |
| 1536 }, |
| 1537 stopResizeNotificationsFor: function(target) { |
| 1538 var index = this._interestedResizables.indexOf(target); |
| 1539 if (index > -1) { |
| 1540 this._interestedResizables.splice(index, 1); |
| 1541 this.unlisten(target, 'iron-resize', '_onDescendantIronResize'); |
| 1542 } |
| 1543 }, |
| 1544 resizerShouldNotify: function(element) { |
| 1545 return true; |
| 1546 }, |
| 1547 _onDescendantIronResize: function(event) { |
| 1548 if (this._notifyingDescendant) { |
| 1549 event.stopPropagation(); |
| 1550 return; |
| 1551 } |
| 1552 if (!Polymer.Settings.useShadow) { |
| 1553 this._fireResize(); |
| 1554 } |
| 1555 }, |
| 1556 _fireResize: function() { |
| 1557 this.fire('iron-resize', null, { |
| 1558 node: this, |
| 1559 bubbles: false |
| 1560 }); |
| 1561 }, |
| 1562 _onIronRequestResizeNotifications: function(event) { |
| 1563 var target = event.path ? event.path[0] : event.target; |
| 1564 if (target === this) { |
| 1565 return; |
| 1566 } |
| 1567 if (this._interestedResizables.indexOf(target) === -1) { |
| 1568 this._interestedResizables.push(target); |
| 1569 this.listen(target, 'iron-resize', '_onDescendantIronResize'); |
| 1570 } |
| 1571 target.assignParentResizable(this); |
| 1572 this._notifyDescendant(target); |
| 1573 event.stopPropagation(); |
| 1574 }, |
| 1575 _parentResizableChanged: function(parentResizable) { |
| 1576 if (parentResizable) { |
| 1577 window.removeEventListener('resize', this._boundNotifyResize); |
| 1578 } |
| 1579 }, |
| 1580 _notifyDescendant: function(descendant) { |
| 1581 if (!this.isAttached) { |
| 1582 return; |
| 1583 } |
| 1584 this._notifyingDescendant = true; |
| 1585 descendant.notifyResize(); |
| 1586 this._notifyingDescendant = false; |
| 1587 } |
| 1588 }; |
| 1589 |
| 1590 Polymer.IronSelection = function(selectCallback) { |
| 1591 this.selection = []; |
| 1592 this.selectCallback = selectCallback; |
| 1593 }; |
| 1594 |
| 1595 Polymer.IronSelection.prototype = { |
| 1596 get: function() { |
| 1597 return this.multi ? this.selection.slice() : this.selection[0]; |
| 1598 }, |
| 1599 clear: function(excludes) { |
| 1600 this.selection.slice().forEach(function(item) { |
| 1601 if (!excludes || excludes.indexOf(item) < 0) { |
| 1602 this.setItemSelected(item, false); |
| 1603 } |
| 1604 }, this); |
| 1605 }, |
| 1606 isSelected: function(item) { |
| 1607 return this.selection.indexOf(item) >= 0; |
| 1608 }, |
| 1609 setItemSelected: function(item, isSelected) { |
| 1610 if (item != null) { |
| 1611 if (isSelected !== this.isSelected(item)) { |
| 1612 if (isSelected) { |
| 1613 this.selection.push(item); |
| 1614 } else { |
| 1615 var i = this.selection.indexOf(item); |
| 1616 if (i >= 0) { |
| 1617 this.selection.splice(i, 1); |
| 1618 } |
| 1619 } |
| 1620 if (this.selectCallback) { |
| 1621 this.selectCallback(item, isSelected); |
| 1622 } |
| 1623 } |
| 1624 } |
| 1625 }, |
| 1626 select: function(item) { |
| 1627 if (this.multi) { |
| 1628 this.toggle(item); |
| 1629 } else if (this.get() !== item) { |
| 1630 this.setItemSelected(this.get(), false); |
| 1631 this.setItemSelected(item, true); |
| 1632 } |
| 1633 }, |
| 1634 toggle: function(item) { |
| 1635 this.setItemSelected(item, !this.isSelected(item)); |
| 1636 } |
| 1637 }; |
| 1638 |
| 1639 Polymer.IronSelectableBehavior = { |
| 1640 properties: { |
| 1641 attrForSelected: { |
| 1642 type: String, |
| 1643 value: null |
| 1644 }, |
| 1645 selected: { |
| 1646 type: String, |
| 1647 notify: true |
| 1648 }, |
| 1649 selectedItem: { |
| 1650 type: Object, |
| 1651 readOnly: true, |
| 1652 notify: true |
| 1653 }, |
| 1654 activateEvent: { |
| 1655 type: String, |
| 1656 value: 'tap', |
| 1657 observer: '_activateEventChanged' |
| 1658 }, |
| 1659 selectable: String, |
| 1660 selectedClass: { |
| 1661 type: String, |
| 1662 value: 'iron-selected' |
| 1663 }, |
| 1664 selectedAttribute: { |
| 1665 type: String, |
| 1666 value: null |
| 1667 }, |
| 1668 fallbackSelection: { |
| 1669 type: String, |
| 1670 value: null |
| 1671 }, |
| 1672 items: { |
| 1673 type: Array, |
| 1674 readOnly: true, |
| 1675 notify: true, |
| 1676 value: function() { |
| 1677 return []; |
| 1678 } |
| 1679 }, |
| 1680 _excludedLocalNames: { |
| 1681 type: Object, |
| 1682 value: function() { |
| 1683 return { |
| 1684 template: 1 |
| 1685 }; |
| 1686 } |
| 1687 } |
| 1688 }, |
| 1689 observers: [ '_updateAttrForSelected(attrForSelected)', '_updateSelected(selec
ted)', '_checkFallback(fallbackSelection)' ], |
| 1690 created: function() { |
| 1691 this._bindFilterItem = this._filterItem.bind(this); |
| 1692 this._selection = new Polymer.IronSelection(this._applySelection.bind(this))
; |
| 1693 }, |
| 1694 attached: function() { |
| 1695 this._observer = this._observeItems(this); |
| 1696 this._updateItems(); |
| 1697 if (!this._shouldUpdateSelection) { |
| 1698 this._updateSelected(); |
| 1699 } |
| 1700 this._addListener(this.activateEvent); |
| 1701 }, |
| 1702 detached: function() { |
| 1703 if (this._observer) { |
| 1704 Polymer.dom(this).unobserveNodes(this._observer); |
| 1705 } |
| 1706 this._removeListener(this.activateEvent); |
| 1707 }, |
| 1708 indexOf: function(item) { |
| 1709 return this.items.indexOf(item); |
| 1710 }, |
| 1711 select: function(value) { |
| 1712 this.selected = value; |
| 1713 }, |
| 1714 selectPrevious: function() { |
| 1715 var length = this.items.length; |
| 1716 var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % lengt
h; |
| 1717 this.selected = this._indexToValue(index); |
| 1718 }, |
| 1719 selectNext: function() { |
| 1720 var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.len
gth; |
| 1721 this.selected = this._indexToValue(index); |
| 1722 }, |
| 1723 selectIndex: function(index) { |
| 1724 this.select(this._indexToValue(index)); |
| 1725 }, |
| 1726 forceSynchronousItemUpdate: function() { |
| 1727 this._updateItems(); |
| 1728 }, |
| 1729 get _shouldUpdateSelection() { |
| 1730 return this.selected != null; |
| 1731 }, |
| 1732 _checkFallback: function() { |
| 1733 if (this._shouldUpdateSelection) { |
| 1734 this._updateSelected(); |
| 1735 } |
| 1736 }, |
| 1737 _addListener: function(eventName) { |
| 1738 this.listen(this, eventName, '_activateHandler'); |
| 1739 }, |
| 1740 _removeListener: function(eventName) { |
| 1741 this.unlisten(this, eventName, '_activateHandler'); |
| 1742 }, |
| 1743 _activateEventChanged: function(eventName, old) { |
| 1744 this._removeListener(old); |
| 1745 this._addListener(eventName); |
| 1746 }, |
| 1747 _updateItems: function() { |
| 1748 var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*
'); |
| 1749 nodes = Array.prototype.filter.call(nodes, this._bindFilterItem); |
| 1750 this._setItems(nodes); |
| 1751 }, |
| 1752 _updateAttrForSelected: function() { |
| 1753 if (this._shouldUpdateSelection) { |
| 1754 this.selected = this._indexToValue(this.indexOf(this.selectedItem)); |
| 1755 } |
| 1756 }, |
| 1757 _updateSelected: function() { |
| 1758 this._selectSelected(this.selected); |
| 1759 }, |
| 1760 _selectSelected: function(selected) { |
| 1761 this._selection.select(this._valueToItem(this.selected)); |
| 1762 if (this.fallbackSelection && this.items.length && this._selection.get() ===
undefined) { |
| 1763 this.selected = this.fallbackSelection; |
| 1764 } |
| 1765 }, |
| 1766 _filterItem: function(node) { |
| 1767 return !this._excludedLocalNames[node.localName]; |
| 1768 }, |
| 1769 _valueToItem: function(value) { |
| 1770 return value == null ? null : this.items[this._valueToIndex(value)]; |
| 1771 }, |
| 1772 _valueToIndex: function(value) { |
| 1773 if (this.attrForSelected) { |
| 1774 for (var i = 0, item; item = this.items[i]; i++) { |
| 1775 if (this._valueForItem(item) == value) { |
| 1776 return i; |
| 1777 } |
| 1778 } |
| 1779 } else { |
| 1780 return Number(value); |
| 1781 } |
| 1782 }, |
| 1783 _indexToValue: function(index) { |
| 1784 if (this.attrForSelected) { |
| 1785 var item = this.items[index]; |
| 1786 if (item) { |
| 1787 return this._valueForItem(item); |
| 1788 } |
| 1789 } else { |
| 1790 return index; |
| 1791 } |
| 1792 }, |
| 1793 _valueForItem: function(item) { |
| 1794 var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)]; |
| 1795 return propValue != undefined ? propValue : item.getAttribute(this.attrForSe
lected); |
| 1796 }, |
| 1797 _applySelection: function(item, isSelected) { |
| 1798 if (this.selectedClass) { |
| 1799 this.toggleClass(this.selectedClass, isSelected, item); |
| 1800 } |
| 1801 if (this.selectedAttribute) { |
| 1802 this.toggleAttribute(this.selectedAttribute, isSelected, item); |
| 1803 } |
| 1804 this._selectionChange(); |
| 1805 this.fire('iron-' + (isSelected ? 'select' : 'deselect'), { |
| 1806 item: item |
| 1807 }); |
| 1808 }, |
| 1809 _selectionChange: function() { |
| 1810 this._setSelectedItem(this._selection.get()); |
| 1811 }, |
| 1812 _observeItems: function(node) { |
| 1813 return Polymer.dom(node).observeNodes(function(mutation) { |
| 1814 this._updateItems(); |
| 1815 if (this._shouldUpdateSelection) { |
| 1816 this._updateSelected(); |
| 1817 } |
| 1818 this.fire('iron-items-changed', mutation, { |
| 1819 bubbles: false, |
| 1820 cancelable: false |
| 1821 }); |
| 1822 }); |
| 1823 }, |
| 1824 _activateHandler: function(e) { |
| 1825 var t = e.target; |
| 1826 var items = this.items; |
| 1827 while (t && t != this) { |
| 1828 var i = items.indexOf(t); |
| 1829 if (i >= 0) { |
| 1830 var value = this._indexToValue(i); |
| 1831 this._itemActivate(value, t); |
| 1832 return; |
| 1833 } |
| 1834 t = t.parentNode; |
| 1835 } |
| 1836 }, |
| 1837 _itemActivate: function(value, item) { |
| 1838 if (!this.fire('iron-activate', { |
| 1839 selected: value, |
| 1840 item: item |
| 1841 }, { |
| 1842 cancelable: true |
| 1843 }).defaultPrevented) { |
| 1844 this.select(value); |
| 1845 } |
| 1846 } |
| 1847 }; |
| 1848 |
| 1849 Polymer({ |
| 1850 is: 'iron-pages', |
| 1851 behaviors: [ Polymer.IronResizableBehavior, Polymer.IronSelectableBehavior ], |
| 1852 properties: { |
| 1853 activateEvent: { |
| 1854 type: String, |
| 1855 value: null |
| 1856 } |
| 1857 }, |
| 1858 observers: [ '_selectedPageChanged(selected)' ], |
| 1859 _selectedPageChanged: function(selected, old) { |
| 1860 this.async(this.notifyResize); |
| 1861 } |
| 1862 }); |
| 1863 |
| 1864 (function() { |
| 1865 'use strict'; |
| 1866 var KEY_IDENTIFIER = { |
| 1867 'U+0008': 'backspace', |
| 1868 'U+0009': 'tab', |
| 1869 'U+001B': 'esc', |
| 1870 'U+0020': 'space', |
| 1871 'U+007F': 'del' |
| 1872 }; |
| 1873 var KEY_CODE = { |
| 1874 8: 'backspace', |
| 1875 9: 'tab', |
| 1876 13: 'enter', |
| 1877 27: 'esc', |
| 1878 33: 'pageup', |
| 1879 34: 'pagedown', |
| 1880 35: 'end', |
| 1881 36: 'home', |
| 1882 32: 'space', |
| 1883 37: 'left', |
| 1884 38: 'up', |
| 1885 39: 'right', |
| 1886 40: 'down', |
| 1887 46: 'del', |
| 1888 106: '*' |
| 1889 }; |
| 1890 var MODIFIER_KEYS = { |
| 1891 shift: 'shiftKey', |
| 1892 ctrl: 'ctrlKey', |
| 1893 alt: 'altKey', |
| 1894 meta: 'metaKey' |
| 1895 }; |
| 1896 var KEY_CHAR = /[a-z0-9*]/; |
| 1897 var IDENT_CHAR = /U\+/; |
| 1898 var ARROW_KEY = /^arrow/; |
| 1899 var SPACE_KEY = /^space(bar)?/; |
| 1900 var ESC_KEY = /^escape$/; |
| 1901 function transformKey(key, noSpecialChars) { |
| 1902 var validKey = ''; |
| 1903 if (key) { |
| 1904 var lKey = key.toLowerCase(); |
| 1905 if (lKey === ' ' || SPACE_KEY.test(lKey)) { |
| 1906 validKey = 'space'; |
| 1907 } else if (ESC_KEY.test(lKey)) { |
| 1908 validKey = 'esc'; |
| 1909 } else if (lKey.length == 1) { |
| 1910 if (!noSpecialChars || KEY_CHAR.test(lKey)) { |
| 1911 validKey = lKey; |
| 1912 } |
| 1913 } else if (ARROW_KEY.test(lKey)) { |
| 1914 validKey = lKey.replace('arrow', ''); |
| 1915 } else if (lKey == 'multiply') { |
| 1916 validKey = '*'; |
| 1917 } else { |
| 1918 validKey = lKey; |
| 1919 } |
| 1920 } |
| 1921 return validKey; |
| 1922 } |
| 1923 function transformKeyIdentifier(keyIdent) { |
| 1924 var validKey = ''; |
| 1925 if (keyIdent) { |
| 1926 if (keyIdent in KEY_IDENTIFIER) { |
| 1927 validKey = KEY_IDENTIFIER[keyIdent]; |
| 1928 } else if (IDENT_CHAR.test(keyIdent)) { |
| 1929 keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16); |
| 1930 validKey = String.fromCharCode(keyIdent).toLowerCase(); |
| 1931 } else { |
| 1932 validKey = keyIdent.toLowerCase(); |
| 1933 } |
| 1934 } |
| 1935 return validKey; |
| 1936 } |
| 1937 function transformKeyCode(keyCode) { |
| 1938 var validKey = ''; |
| 1939 if (Number(keyCode)) { |
| 1940 if (keyCode >= 65 && keyCode <= 90) { |
| 1941 validKey = String.fromCharCode(32 + keyCode); |
| 1942 } else if (keyCode >= 112 && keyCode <= 123) { |
| 1943 validKey = 'f' + (keyCode - 112); |
| 1944 } else if (keyCode >= 48 && keyCode <= 57) { |
| 1945 validKey = String(keyCode - 48); |
| 1946 } else if (keyCode >= 96 && keyCode <= 105) { |
| 1947 validKey = String(keyCode - 96); |
| 1948 } else { |
| 1949 validKey = KEY_CODE[keyCode]; |
| 1950 } |
| 1951 } |
| 1952 return validKey; |
| 1953 } |
| 1954 function normalizedKeyForEvent(keyEvent, noSpecialChars) { |
| 1955 return transformKey(keyEvent.key, noSpecialChars) || transformKeyIdentifier(
keyEvent.keyIdentifier) || transformKeyCode(keyEvent.keyCode) || transformKey(ke
yEvent.detail ? keyEvent.detail.key : keyEvent.detail, noSpecialChars) || ''; |
| 1956 } |
| 1957 function keyComboMatchesEvent(keyCombo, event) { |
| 1958 var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers); |
| 1959 return keyEvent === keyCombo.key && (!keyCombo.hasModifiers || !!event.shift
Key === !!keyCombo.shiftKey && !!event.ctrlKey === !!keyCombo.ctrlKey && !!event
.altKey === !!keyCombo.altKey && !!event.metaKey === !!keyCombo.metaKey); |
| 1960 } |
| 1961 function parseKeyComboString(keyComboString) { |
| 1962 if (keyComboString.length === 1) { |
| 1963 return { |
| 1964 combo: keyComboString, |
| 1965 key: keyComboString, |
| 1966 event: 'keydown' |
| 1967 }; |
| 1968 } |
| 1969 return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPar
t) { |
| 1970 var eventParts = keyComboPart.split(':'); |
| 1971 var keyName = eventParts[0]; |
| 1972 var event = eventParts[1]; |
| 1973 if (keyName in MODIFIER_KEYS) { |
| 1974 parsedKeyCombo[MODIFIER_KEYS[keyName]] = true; |
| 1975 parsedKeyCombo.hasModifiers = true; |
| 1976 } else { |
| 1977 parsedKeyCombo.key = keyName; |
| 1978 parsedKeyCombo.event = event || 'keydown'; |
| 1979 } |
| 1980 return parsedKeyCombo; |
| 1981 }, { |
| 1982 combo: keyComboString.split(':').shift() |
| 1983 }); |
| 1984 } |
| 1985 function parseEventString(eventString) { |
| 1986 return eventString.trim().split(' ').map(function(keyComboString) { |
| 1987 return parseKeyComboString(keyComboString); |
| 1988 }); |
| 1989 } |
| 1990 Polymer.IronA11yKeysBehavior = { |
| 1991 properties: { |
| 1992 keyEventTarget: { |
| 1993 type: Object, |
| 1994 value: function() { |
| 1995 return this; |
| 1996 } |
| 1997 }, |
| 1998 stopKeyboardEventPropagation: { |
| 1999 type: Boolean, |
| 2000 value: false |
| 2001 }, |
| 2002 _boundKeyHandlers: { |
| 2003 type: Array, |
| 2004 value: function() { |
| 2005 return []; |
| 2006 } |
| 2007 }, |
| 2008 _imperativeKeyBindings: { |
| 2009 type: Object, |
| 2010 value: function() { |
| 2011 return {}; |
| 2012 } |
| 2013 } |
| 2014 }, |
| 2015 observers: [ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)' ], |
| 2016 keyBindings: {}, |
| 2017 registered: function() { |
| 2018 this._prepKeyBindings(); |
| 2019 }, |
| 2020 attached: function() { |
| 2021 this._listenKeyEventListeners(); |
| 2022 }, |
| 2023 detached: function() { |
| 2024 this._unlistenKeyEventListeners(); |
| 2025 }, |
| 2026 addOwnKeyBinding: function(eventString, handlerName) { |
| 2027 this._imperativeKeyBindings[eventString] = handlerName; |
| 2028 this._prepKeyBindings(); |
| 2029 this._resetKeyEventListeners(); |
| 2030 }, |
| 2031 removeOwnKeyBindings: function() { |
| 2032 this._imperativeKeyBindings = {}; |
| 2033 this._prepKeyBindings(); |
| 2034 this._resetKeyEventListeners(); |
| 2035 }, |
| 2036 keyboardEventMatchesKeys: function(event, eventString) { |
| 2037 var keyCombos = parseEventString(eventString); |
| 2038 for (var i = 0; i < keyCombos.length; ++i) { |
| 2039 if (keyComboMatchesEvent(keyCombos[i], event)) { |
| 2040 return true; |
| 2041 } |
| 2042 } |
| 2043 return false; |
| 2044 }, |
| 2045 _collectKeyBindings: function() { |
| 2046 var keyBindings = this.behaviors.map(function(behavior) { |
| 2047 return behavior.keyBindings; |
| 2048 }); |
| 2049 if (keyBindings.indexOf(this.keyBindings) === -1) { |
| 2050 keyBindings.push(this.keyBindings); |
| 2051 } |
| 2052 return keyBindings; |
| 2053 }, |
| 2054 _prepKeyBindings: function() { |
| 2055 this._keyBindings = {}; |
| 2056 this._collectKeyBindings().forEach(function(keyBindings) { |
| 2057 for (var eventString in keyBindings) { |
| 2058 this._addKeyBinding(eventString, keyBindings[eventString]); |
| 2059 } |
| 2060 }, this); |
| 2061 for (var eventString in this._imperativeKeyBindings) { |
| 2062 this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString
]); |
| 2063 } |
| 2064 for (var eventName in this._keyBindings) { |
| 2065 this._keyBindings[eventName].sort(function(kb1, kb2) { |
| 2066 var b1 = kb1[0].hasModifiers; |
| 2067 var b2 = kb2[0].hasModifiers; |
| 2068 return b1 === b2 ? 0 : b1 ? -1 : 1; |
| 2069 }); |
| 2070 } |
| 2071 }, |
| 2072 _addKeyBinding: function(eventString, handlerName) { |
| 2073 parseEventString(eventString).forEach(function(keyCombo) { |
| 2074 this._keyBindings[keyCombo.event] = this._keyBindings[keyCombo.event] ||
[]; |
| 2075 this._keyBindings[keyCombo.event].push([ keyCombo, handlerName ]); |
| 2076 }, this); |
| 2077 }, |
| 2078 _resetKeyEventListeners: function() { |
| 2079 this._unlistenKeyEventListeners(); |
| 2080 if (this.isAttached) { |
| 2081 this._listenKeyEventListeners(); |
| 2082 } |
| 2083 }, |
| 2084 _listenKeyEventListeners: function() { |
| 2085 if (!this.keyEventTarget) { |
| 2086 return; |
| 2087 } |
| 2088 Object.keys(this._keyBindings).forEach(function(eventName) { |
| 2089 var keyBindings = this._keyBindings[eventName]; |
| 2090 var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings); |
| 2091 this._boundKeyHandlers.push([ this.keyEventTarget, eventName, boundKeyHa
ndler ]); |
| 2092 this.keyEventTarget.addEventListener(eventName, boundKeyHandler); |
| 2093 }, this); |
| 2094 }, |
| 2095 _unlistenKeyEventListeners: function() { |
| 2096 var keyHandlerTuple; |
| 2097 var keyEventTarget; |
| 2098 var eventName; |
| 2099 var boundKeyHandler; |
| 2100 while (this._boundKeyHandlers.length) { |
| 2101 keyHandlerTuple = this._boundKeyHandlers.pop(); |
| 2102 keyEventTarget = keyHandlerTuple[0]; |
| 2103 eventName = keyHandlerTuple[1]; |
| 2104 boundKeyHandler = keyHandlerTuple[2]; |
| 2105 keyEventTarget.removeEventListener(eventName, boundKeyHandler); |
| 2106 } |
| 2107 }, |
| 2108 _onKeyBindingEvent: function(keyBindings, event) { |
| 2109 if (this.stopKeyboardEventPropagation) { |
| 2110 event.stopPropagation(); |
| 2111 } |
| 2112 if (event.defaultPrevented) { |
| 2113 return; |
| 2114 } |
| 2115 for (var i = 0; i < keyBindings.length; i++) { |
| 2116 var keyCombo = keyBindings[i][0]; |
| 2117 var handlerName = keyBindings[i][1]; |
| 2118 if (keyComboMatchesEvent(keyCombo, event)) { |
| 2119 this._triggerKeyHandler(keyCombo, handlerName, event); |
| 2120 if (event.defaultPrevented) { |
| 2121 return; |
| 2122 } |
| 2123 } |
| 2124 } |
| 2125 }, |
| 2126 _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) { |
| 2127 var detail = Object.create(keyCombo); |
| 2128 detail.keyboardEvent = keyboardEvent; |
| 2129 var event = new CustomEvent(keyCombo.event, { |
| 2130 detail: detail, |
| 2131 cancelable: true |
| 2132 }); |
| 2133 this[handlerName].call(this, event); |
| 2134 if (event.defaultPrevented) { |
| 2135 keyboardEvent.preventDefault(); |
| 2136 } |
| 2137 } |
| 2138 }; |
| 2139 })(); |
| 2140 |
| 2141 Polymer.IronControlState = { |
| 2142 properties: { |
| 2143 focused: { |
| 2144 type: Boolean, |
| 2145 value: false, |
| 2146 notify: true, |
| 2147 readOnly: true, |
| 2148 reflectToAttribute: true |
| 2149 }, |
| 2150 disabled: { |
| 2151 type: Boolean, |
| 2152 value: false, |
| 2153 notify: true, |
| 2154 observer: '_disabledChanged', |
| 2155 reflectToAttribute: true |
| 2156 }, |
| 2157 _oldTabIndex: { |
| 2158 type: Number |
| 2159 }, |
| 2160 _boundFocusBlurHandler: { |
| 2161 type: Function, |
| 2162 value: function() { |
| 2163 return this._focusBlurHandler.bind(this); |
| 2164 } |
| 2165 } |
| 2166 }, |
| 2167 observers: [ '_changedControlState(focused, disabled)' ], |
| 2168 ready: function() { |
| 2169 this.addEventListener('focus', this._boundFocusBlurHandler, true); |
| 2170 this.addEventListener('blur', this._boundFocusBlurHandler, true); |
| 2171 }, |
| 2172 _focusBlurHandler: function(event) { |
| 2173 if (event.target === this) { |
| 2174 this._setFocused(event.type === 'focus'); |
| 2175 } else if (!this.shadowRoot) { |
| 2176 var target = Polymer.dom(event).localTarget; |
| 2177 if (!this.isLightDescendant(target)) { |
| 2178 this.fire(event.type, { |
| 2179 sourceEvent: event |
| 2180 }, { |
| 2181 node: this, |
| 2182 bubbles: event.bubbles, |
| 2183 cancelable: event.cancelable |
| 2184 }); |
| 2185 } |
| 2186 } |
| 2187 }, |
| 2188 _disabledChanged: function(disabled, old) { |
| 2189 this.setAttribute('aria-disabled', disabled ? 'true' : 'false'); |
| 2190 this.style.pointerEvents = disabled ? 'none' : ''; |
| 2191 if (disabled) { |
| 2192 this._oldTabIndex = this.tabIndex; |
| 2193 this._setFocused(false); |
| 2194 this.tabIndex = -1; |
| 2195 this.blur(); |
| 2196 } else if (this._oldTabIndex !== undefined) { |
| 2197 this.tabIndex = this._oldTabIndex; |
| 2198 } |
| 2199 }, |
| 2200 _changedControlState: function() { |
| 2201 if (this._controlStateChanged) { |
| 2202 this._controlStateChanged(); |
| 2203 } |
| 2204 } |
| 2205 }; |
| 2206 |
| 2207 Polymer.IronButtonStateImpl = { |
| 2208 properties: { |
| 2209 pressed: { |
| 2210 type: Boolean, |
| 2211 readOnly: true, |
| 2212 value: false, |
| 2213 reflectToAttribute: true, |
| 2214 observer: '_pressedChanged' |
| 2215 }, |
| 2216 toggles: { |
| 2217 type: Boolean, |
| 2218 value: false, |
| 2219 reflectToAttribute: true |
| 2220 }, |
| 2221 active: { |
| 2222 type: Boolean, |
| 2223 value: false, |
| 2224 notify: true, |
| 2225 reflectToAttribute: true |
| 2226 }, |
| 2227 pointerDown: { |
| 2228 type: Boolean, |
| 2229 readOnly: true, |
| 2230 value: false |
| 2231 }, |
| 2232 receivedFocusFromKeyboard: { |
| 2233 type: Boolean, |
| 2234 readOnly: true |
| 2235 }, |
| 2236 ariaActiveAttribute: { |
| 2237 type: String, |
| 2238 value: 'aria-pressed', |
| 2239 observer: '_ariaActiveAttributeChanged' |
| 2240 } |
| 2241 }, |
| 2242 listeners: { |
| 2243 down: '_downHandler', |
| 2244 up: '_upHandler', |
| 2245 tap: '_tapHandler' |
| 2246 }, |
| 2247 observers: [ '_detectKeyboardFocus(focused)', '_activeChanged(active, ariaActi
veAttribute)' ], |
| 2248 keyBindings: { |
| 2249 'enter:keydown': '_asyncClick', |
| 2250 'space:keydown': '_spaceKeyDownHandler', |
| 2251 'space:keyup': '_spaceKeyUpHandler' |
| 2252 }, |
| 2253 _mouseEventRe: /^mouse/, |
| 2254 _tapHandler: function() { |
| 2255 if (this.toggles) { |
| 2256 this._userActivate(!this.active); |
| 2257 } else { |
| 2258 this.active = false; |
| 2259 } |
| 2260 }, |
| 2261 _detectKeyboardFocus: function(focused) { |
| 2262 this._setReceivedFocusFromKeyboard(!this.pointerDown && focused); |
| 2263 }, |
| 2264 _userActivate: function(active) { |
| 2265 if (this.active !== active) { |
| 2266 this.active = active; |
| 2267 this.fire('change'); |
| 2268 } |
| 2269 }, |
| 2270 _downHandler: function(event) { |
| 2271 this._setPointerDown(true); |
| 2272 this._setPressed(true); |
| 2273 this._setReceivedFocusFromKeyboard(false); |
| 2274 }, |
| 2275 _upHandler: function() { |
| 2276 this._setPointerDown(false); |
| 2277 this._setPressed(false); |
| 2278 }, |
| 2279 _spaceKeyDownHandler: function(event) { |
| 2280 var keyboardEvent = event.detail.keyboardEvent; |
| 2281 var target = Polymer.dom(keyboardEvent).localTarget; |
| 2282 if (this.isLightDescendant(target)) return; |
| 2283 keyboardEvent.preventDefault(); |
| 2284 keyboardEvent.stopImmediatePropagation(); |
| 2285 this._setPressed(true); |
| 2286 }, |
| 2287 _spaceKeyUpHandler: function(event) { |
| 2288 var keyboardEvent = event.detail.keyboardEvent; |
| 2289 var target = Polymer.dom(keyboardEvent).localTarget; |
| 2290 if (this.isLightDescendant(target)) return; |
| 2291 if (this.pressed) { |
| 2292 this._asyncClick(); |
| 2293 } |
| 2294 this._setPressed(false); |
| 2295 }, |
| 2296 _asyncClick: function() { |
| 2297 this.async(function() { |
| 2298 this.click(); |
| 2299 }, 1); |
| 2300 }, |
| 2301 _pressedChanged: function(pressed) { |
| 2302 this._changedButtonState(); |
| 2303 }, |
| 2304 _ariaActiveAttributeChanged: function(value, oldValue) { |
| 2305 if (oldValue && oldValue != value && this.hasAttribute(oldValue)) { |
| 2306 this.removeAttribute(oldValue); |
| 2307 } |
| 2308 }, |
| 2309 _activeChanged: function(active, ariaActiveAttribute) { |
| 2310 if (this.toggles) { |
| 2311 this.setAttribute(this.ariaActiveAttribute, active ? 'true' : 'false'); |
| 2312 } else { |
| 2313 this.removeAttribute(this.ariaActiveAttribute); |
| 2314 } |
| 2315 this._changedButtonState(); |
| 2316 }, |
| 2317 _controlStateChanged: function() { |
| 2318 if (this.disabled) { |
| 2319 this._setPressed(false); |
| 2320 } else { |
| 2321 this._changedButtonState(); |
| 2322 } |
| 2323 }, |
| 2324 _changedButtonState: function() { |
| 2325 if (this._buttonStateChanged) { |
| 2326 this._buttonStateChanged(); |
| 2327 } |
| 2328 } |
| 2329 }; |
| 2330 |
| 2331 Polymer.IronButtonState = [ Polymer.IronA11yKeysBehavior, Polymer.IronButtonStat
eImpl ]; |
| 2332 |
| 2333 (function() { |
| 2334 var Utility = { |
| 2335 distance: function(x1, y1, x2, y2) { |
| 2336 var xDelta = x1 - x2; |
| 2337 var yDelta = y1 - y2; |
| 2338 return Math.sqrt(xDelta * xDelta + yDelta * yDelta); |
| 2339 }, |
| 2340 now: window.performance && window.performance.now ? window.performance.now.b
ind(window.performance) : Date.now |
| 2341 }; |
| 2342 function ElementMetrics(element) { |
| 2343 this.element = element; |
| 2344 this.width = this.boundingRect.width; |
| 2345 this.height = this.boundingRect.height; |
| 2346 this.size = Math.max(this.width, this.height); |
| 2347 } |
| 2348 ElementMetrics.prototype = { |
| 2349 get boundingRect() { |
| 2350 return this.element.getBoundingClientRect(); |
| 2351 }, |
| 2352 furthestCornerDistanceFrom: function(x, y) { |
| 2353 var topLeft = Utility.distance(x, y, 0, 0); |
| 2354 var topRight = Utility.distance(x, y, this.width, 0); |
| 2355 var bottomLeft = Utility.distance(x, y, 0, this.height); |
| 2356 var bottomRight = Utility.distance(x, y, this.width, this.height); |
| 2357 return Math.max(topLeft, topRight, bottomLeft, bottomRight); |
| 2358 } |
| 2359 }; |
| 2360 function Ripple(element) { |
| 2361 this.element = element; |
| 2362 this.color = window.getComputedStyle(element).color; |
| 2363 this.wave = document.createElement('div'); |
| 2364 this.waveContainer = document.createElement('div'); |
| 2365 this.wave.style.backgroundColor = this.color; |
| 2366 this.wave.classList.add('wave'); |
| 2367 this.waveContainer.classList.add('wave-container'); |
| 2368 Polymer.dom(this.waveContainer).appendChild(this.wave); |
| 2369 this.resetInteractionState(); |
| 2370 } |
| 2371 Ripple.MAX_RADIUS = 300; |
| 2372 Ripple.prototype = { |
| 2373 get recenters() { |
| 2374 return this.element.recenters; |
| 2375 }, |
| 2376 get center() { |
| 2377 return this.element.center; |
| 2378 }, |
| 2379 get mouseDownElapsed() { |
| 2380 var elapsed; |
| 2381 if (!this.mouseDownStart) { |
| 2382 return 0; |
| 2383 } |
| 2384 elapsed = Utility.now() - this.mouseDownStart; |
| 2385 if (this.mouseUpStart) { |
| 2386 elapsed -= this.mouseUpElapsed; |
| 2387 } |
| 2388 return elapsed; |
| 2389 }, |
| 2390 get mouseUpElapsed() { |
| 2391 return this.mouseUpStart ? Utility.now() - this.mouseUpStart : 0; |
| 2392 }, |
| 2393 get mouseDownElapsedSeconds() { |
| 2394 return this.mouseDownElapsed / 1e3; |
| 2395 }, |
| 2396 get mouseUpElapsedSeconds() { |
| 2397 return this.mouseUpElapsed / 1e3; |
| 2398 }, |
| 2399 get mouseInteractionSeconds() { |
| 2400 return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds; |
| 2401 }, |
| 2402 get initialOpacity() { |
| 2403 return this.element.initialOpacity; |
| 2404 }, |
| 2405 get opacityDecayVelocity() { |
| 2406 return this.element.opacityDecayVelocity; |
| 2407 }, |
| 2408 get radius() { |
| 2409 var width2 = this.containerMetrics.width * this.containerMetrics.width; |
| 2410 var height2 = this.containerMetrics.height * this.containerMetrics.height; |
| 2411 var waveRadius = Math.min(Math.sqrt(width2 + height2), Ripple.MAX_RADIUS)
* 1.1 + 5; |
| 2412 var duration = 1.1 - .2 * (waveRadius / Ripple.MAX_RADIUS); |
| 2413 var timeNow = this.mouseInteractionSeconds / duration; |
| 2414 var size = waveRadius * (1 - Math.pow(80, -timeNow)); |
| 2415 return Math.abs(size); |
| 2416 }, |
| 2417 get opacity() { |
| 2418 if (!this.mouseUpStart) { |
| 2419 return this.initialOpacity; |
| 2420 } |
| 2421 return Math.max(0, this.initialOpacity - this.mouseUpElapsedSeconds * this
.opacityDecayVelocity); |
| 2422 }, |
| 2423 get outerOpacity() { |
| 2424 var outerOpacity = this.mouseUpElapsedSeconds * .3; |
| 2425 var waveOpacity = this.opacity; |
| 2426 return Math.max(0, Math.min(outerOpacity, waveOpacity)); |
| 2427 }, |
| 2428 get isOpacityFullyDecayed() { |
| 2429 return this.opacity < .01 && this.radius >= Math.min(this.maxRadius, Rippl
e.MAX_RADIUS); |
| 2430 }, |
| 2431 get isRestingAtMaxRadius() { |
| 2432 return this.opacity >= this.initialOpacity && this.radius >= Math.min(this
.maxRadius, Ripple.MAX_RADIUS); |
| 2433 }, |
| 2434 get isAnimationComplete() { |
| 2435 return this.mouseUpStart ? this.isOpacityFullyDecayed : this.isRestingAtMa
xRadius; |
| 2436 }, |
| 2437 get translationFraction() { |
| 2438 return Math.min(1, this.radius / this.containerMetrics.size * 2 / Math.sqr
t(2)); |
| 2439 }, |
| 2440 get xNow() { |
| 2441 if (this.xEnd) { |
| 2442 return this.xStart + this.translationFraction * (this.xEnd - this.xStart
); |
| 2443 } |
| 2444 return this.xStart; |
| 2445 }, |
| 2446 get yNow() { |
| 2447 if (this.yEnd) { |
| 2448 return this.yStart + this.translationFraction * (this.yEnd - this.yStart
); |
| 2449 } |
| 2450 return this.yStart; |
| 2451 }, |
| 2452 get isMouseDown() { |
| 2453 return this.mouseDownStart && !this.mouseUpStart; |
| 2454 }, |
| 2455 resetInteractionState: function() { |
| 2456 this.maxRadius = 0; |
| 2457 this.mouseDownStart = 0; |
| 2458 this.mouseUpStart = 0; |
| 2459 this.xStart = 0; |
| 2460 this.yStart = 0; |
| 2461 this.xEnd = 0; |
| 2462 this.yEnd = 0; |
| 2463 this.slideDistance = 0; |
| 2464 this.containerMetrics = new ElementMetrics(this.element); |
| 2465 }, |
| 2466 draw: function() { |
| 2467 var scale; |
| 2468 var translateString; |
| 2469 var dx; |
| 2470 var dy; |
| 2471 this.wave.style.opacity = this.opacity; |
| 2472 scale = this.radius / (this.containerMetrics.size / 2); |
| 2473 dx = this.xNow - this.containerMetrics.width / 2; |
| 2474 dy = this.yNow - this.containerMetrics.height / 2; |
| 2475 this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy
+ 'px)'; |
| 2476 this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + '
px, 0)'; |
| 2477 this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')'; |
| 2478 this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)'; |
| 2479 }, |
| 2480 downAction: function(event) { |
| 2481 var xCenter = this.containerMetrics.width / 2; |
| 2482 var yCenter = this.containerMetrics.height / 2; |
| 2483 this.resetInteractionState(); |
| 2484 this.mouseDownStart = Utility.now(); |
| 2485 if (this.center) { |
| 2486 this.xStart = xCenter; |
| 2487 this.yStart = yCenter; |
| 2488 this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEn
d, this.yEnd); |
| 2489 } else { |
| 2490 this.xStart = event ? event.detail.x - this.containerMetrics.boundingRec
t.left : this.containerMetrics.width / 2; |
| 2491 this.yStart = event ? event.detail.y - this.containerMetrics.boundingRec
t.top : this.containerMetrics.height / 2; |
| 2492 } |
| 2493 if (this.recenters) { |
| 2494 this.xEnd = xCenter; |
| 2495 this.yEnd = yCenter; |
| 2496 this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEn
d, this.yEnd); |
| 2497 } |
| 2498 this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom(this.xSt
art, this.yStart); |
| 2499 this.waveContainer.style.top = (this.containerMetrics.height - this.contai
nerMetrics.size) / 2 + 'px'; |
| 2500 this.waveContainer.style.left = (this.containerMetrics.width - this.contai
nerMetrics.size) / 2 + 'px'; |
| 2501 this.waveContainer.style.width = this.containerMetrics.size + 'px'; |
| 2502 this.waveContainer.style.height = this.containerMetrics.size + 'px'; |
| 2503 }, |
| 2504 upAction: function(event) { |
| 2505 if (!this.isMouseDown) { |
| 2506 return; |
| 2507 } |
| 2508 this.mouseUpStart = Utility.now(); |
| 2509 }, |
| 2510 remove: function() { |
| 2511 Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)
; |
| 2512 } |
| 2513 }; |
| 2514 Polymer({ |
| 2515 is: 'paper-ripple', |
| 2516 behaviors: [ Polymer.IronA11yKeysBehavior ], |
| 2517 properties: { |
| 2518 initialOpacity: { |
| 2519 type: Number, |
| 2520 value: .25 |
| 2521 }, |
| 2522 opacityDecayVelocity: { |
| 2523 type: Number, |
| 2524 value: .8 |
| 2525 }, |
| 2526 recenters: { |
| 2527 type: Boolean, |
| 2528 value: false |
| 2529 }, |
| 2530 center: { |
| 2531 type: Boolean, |
| 2532 value: false |
| 2533 }, |
| 2534 ripples: { |
| 2535 type: Array, |
| 2536 value: function() { |
| 2537 return []; |
| 2538 } |
| 2539 }, |
| 2540 animating: { |
| 2541 type: Boolean, |
| 2542 readOnly: true, |
| 2543 reflectToAttribute: true, |
| 2544 value: false |
| 2545 }, |
| 2546 holdDown: { |
| 2547 type: Boolean, |
| 2548 value: false, |
| 2549 observer: '_holdDownChanged' |
| 2550 }, |
| 2551 noink: { |
| 2552 type: Boolean, |
| 2553 value: false |
| 2554 }, |
| 2555 _animating: { |
| 2556 type: Boolean |
| 2557 }, |
| 2558 _boundAnimate: { |
| 2559 type: Function, |
| 2560 value: function() { |
| 2561 return this.animate.bind(this); |
| 2562 } |
| 2563 } |
| 2564 }, |
| 2565 get target() { |
| 2566 return this.keyEventTarget; |
| 2567 }, |
| 2568 keyBindings: { |
| 2569 'enter:keydown': '_onEnterKeydown', |
| 2570 'space:keydown': '_onSpaceKeydown', |
| 2571 'space:keyup': '_onSpaceKeyup' |
| 2572 }, |
| 2573 attached: function() { |
| 2574 if (this.parentNode.nodeType == 11) { |
| 2575 this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host; |
| 2576 } else { |
| 2577 this.keyEventTarget = this.parentNode; |
| 2578 } |
| 2579 var keyEventTarget = this.keyEventTarget; |
| 2580 this.listen(keyEventTarget, 'up', 'uiUpAction'); |
| 2581 this.listen(keyEventTarget, 'down', 'uiDownAction'); |
| 2582 }, |
| 2583 detached: function() { |
| 2584 this.unlisten(this.keyEventTarget, 'up', 'uiUpAction'); |
| 2585 this.unlisten(this.keyEventTarget, 'down', 'uiDownAction'); |
| 2586 this.keyEventTarget = null; |
| 2587 }, |
| 2588 get shouldKeepAnimating() { |
| 2589 for (var index = 0; index < this.ripples.length; ++index) { |
| 2590 if (!this.ripples[index].isAnimationComplete) { |
| 2591 return true; |
| 2592 } |
| 2593 } |
| 2594 return false; |
| 2595 }, |
| 2596 simulatedRipple: function() { |
| 2597 this.downAction(null); |
| 2598 this.async(function() { |
| 2599 this.upAction(); |
| 2600 }, 1); |
| 2601 }, |
| 2602 uiDownAction: function(event) { |
| 2603 if (!this.noink) { |
| 2604 this.downAction(event); |
| 2605 } |
| 2606 }, |
| 2607 downAction: function(event) { |
| 2608 if (this.holdDown && this.ripples.length > 0) { |
| 2609 return; |
| 2610 } |
| 2611 var ripple = this.addRipple(); |
| 2612 ripple.downAction(event); |
| 2613 if (!this._animating) { |
| 2614 this._animating = true; |
| 2615 this.animate(); |
| 2616 } |
| 2617 }, |
| 2618 uiUpAction: function(event) { |
| 2619 if (!this.noink) { |
| 2620 this.upAction(event); |
| 2621 } |
| 2622 }, |
| 2623 upAction: function(event) { |
| 2624 if (this.holdDown) { |
| 2625 return; |
| 2626 } |
| 2627 this.ripples.forEach(function(ripple) { |
| 2628 ripple.upAction(event); |
| 2629 }); |
| 2630 this._animating = true; |
| 2631 this.animate(); |
| 2632 }, |
| 2633 onAnimationComplete: function() { |
| 2634 this._animating = false; |
| 2635 this.$.background.style.backgroundColor = null; |
| 2636 this.fire('transitionend'); |
| 2637 }, |
| 2638 addRipple: function() { |
| 2639 var ripple = new Ripple(this); |
| 2640 Polymer.dom(this.$.waves).appendChild(ripple.waveContainer); |
| 2641 this.$.background.style.backgroundColor = ripple.color; |
| 2642 this.ripples.push(ripple); |
| 2643 this._setAnimating(true); |
| 2644 return ripple; |
| 2645 }, |
| 2646 removeRipple: function(ripple) { |
| 2647 var rippleIndex = this.ripples.indexOf(ripple); |
| 2648 if (rippleIndex < 0) { |
| 2649 return; |
| 2650 } |
| 2651 this.ripples.splice(rippleIndex, 1); |
| 2652 ripple.remove(); |
| 2653 if (!this.ripples.length) { |
| 2654 this._setAnimating(false); |
| 2655 } |
| 2656 }, |
| 2657 animate: function() { |
| 2658 if (!this._animating) { |
| 2659 return; |
| 2660 } |
| 2661 var index; |
| 2662 var ripple; |
| 2663 for (index = 0; index < this.ripples.length; ++index) { |
| 2664 ripple = this.ripples[index]; |
| 2665 ripple.draw(); |
| 2666 this.$.background.style.opacity = ripple.outerOpacity; |
| 2667 if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) { |
| 2668 this.removeRipple(ripple); |
| 2669 } |
| 2670 } |
| 2671 if (!this.shouldKeepAnimating && this.ripples.length === 0) { |
| 2672 this.onAnimationComplete(); |
| 2673 } else { |
| 2674 window.requestAnimationFrame(this._boundAnimate); |
| 2675 } |
| 2676 }, |
| 2677 _onEnterKeydown: function() { |
| 2678 this.uiDownAction(); |
| 2679 this.async(this.uiUpAction, 1); |
| 2680 }, |
| 2681 _onSpaceKeydown: function() { |
| 2682 this.uiDownAction(); |
| 2683 }, |
| 2684 _onSpaceKeyup: function() { |
| 2685 this.uiUpAction(); |
| 2686 }, |
| 2687 _holdDownChanged: function(newVal, oldVal) { |
| 2688 if (oldVal === undefined) { |
| 2689 return; |
| 2690 } |
| 2691 if (newVal) { |
| 2692 this.downAction(); |
| 2693 } else { |
| 2694 this.upAction(); |
| 2695 } |
| 2696 } |
| 2697 }); |
| 2698 })(); |
| 2699 |
| 2700 Polymer.PaperRippleBehavior = { |
| 2701 properties: { |
| 2702 noink: { |
| 2703 type: Boolean, |
| 2704 observer: '_noinkChanged' |
| 2705 }, |
| 2706 _rippleContainer: { |
| 2707 type: Object |
| 2708 } |
| 2709 }, |
| 2710 _buttonStateChanged: function() { |
| 2711 if (this.focused) { |
| 2712 this.ensureRipple(); |
| 2713 } |
| 2714 }, |
| 2715 _downHandler: function(event) { |
| 2716 Polymer.IronButtonStateImpl._downHandler.call(this, event); |
| 2717 if (this.pressed) { |
| 2718 this.ensureRipple(event); |
| 2719 } |
| 2720 }, |
| 2721 ensureRipple: function(optTriggeringEvent) { |
| 2722 if (!this.hasRipple()) { |
| 2723 this._ripple = this._createRipple(); |
| 2724 this._ripple.noink = this.noink; |
| 2725 var rippleContainer = this._rippleContainer || this.root; |
| 2726 if (rippleContainer) { |
| 2727 Polymer.dom(rippleContainer).appendChild(this._ripple); |
| 2728 } |
| 2729 if (optTriggeringEvent) { |
| 2730 var domContainer = Polymer.dom(this._rippleContainer || this); |
| 2731 var target = Polymer.dom(optTriggeringEvent).rootTarget; |
| 2732 if (domContainer.deepContains(target)) { |
| 2733 this._ripple.uiDownAction(optTriggeringEvent); |
| 2734 } |
| 2735 } |
| 2736 } |
| 2737 }, |
| 2738 getRipple: function() { |
| 2739 this.ensureRipple(); |
| 2740 return this._ripple; |
| 2741 }, |
| 2742 hasRipple: function() { |
| 2743 return Boolean(this._ripple); |
| 2744 }, |
| 2745 _createRipple: function() { |
| 2746 return document.createElement('paper-ripple'); |
| 2747 }, |
| 2748 _noinkChanged: function(noink) { |
| 2749 if (this.hasRipple()) { |
| 2750 this._ripple.noink = noink; |
| 2751 } |
| 2752 } |
| 2753 }; |
| 2754 |
| 2755 Polymer.PaperButtonBehaviorImpl = { |
| 2756 properties: { |
| 2757 elevation: { |
| 2758 type: Number, |
| 2759 reflectToAttribute: true, |
| 2760 readOnly: true |
| 2761 } |
| 2762 }, |
| 2763 observers: [ '_calculateElevation(focused, disabled, active, pressed, received
FocusFromKeyboard)', '_computeKeyboardClass(receivedFocusFromKeyboard)' ], |
| 2764 hostAttributes: { |
| 2765 role: 'button', |
| 2766 tabindex: '0', |
| 2767 animated: true |
| 2768 }, |
| 2769 _calculateElevation: function() { |
| 2770 var e = 1; |
| 2771 if (this.disabled) { |
| 2772 e = 0; |
| 2773 } else if (this.active || this.pressed) { |
| 2774 e = 4; |
| 2775 } else if (this.receivedFocusFromKeyboard) { |
| 2776 e = 3; |
| 2777 } |
| 2778 this._setElevation(e); |
| 2779 }, |
| 2780 _computeKeyboardClass: function(receivedFocusFromKeyboard) { |
| 2781 this.toggleClass('keyboard-focus', receivedFocusFromKeyboard); |
| 2782 }, |
| 2783 _spaceKeyDownHandler: function(event) { |
| 2784 Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event); |
| 2785 if (this.hasRipple() && this.getRipple().ripples.length < 1) { |
| 2786 this._ripple.uiDownAction(); |
| 2787 } |
| 2788 }, |
| 2789 _spaceKeyUpHandler: function(event) { |
| 2790 Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event); |
| 2791 if (this.hasRipple()) { |
| 2792 this._ripple.uiUpAction(); |
| 2793 } |
| 2794 } |
| 2795 }; |
| 2796 |
| 2797 Polymer.PaperButtonBehavior = [ Polymer.IronButtonState, Polymer.IronControlStat
e, Polymer.PaperRippleBehavior, Polymer.PaperButtonBehaviorImpl ]; |
| 2798 |
| 2799 Polymer({ |
| 2800 is: 'paper-button', |
| 2801 behaviors: [ Polymer.PaperButtonBehavior ], |
| 2802 properties: { |
| 2803 raised: { |
| 2804 type: Boolean, |
| 2805 reflectToAttribute: true, |
| 2806 value: false, |
| 2807 observer: '_calculateElevation' |
| 2808 } |
| 2809 }, |
| 2810 _calculateElevation: function() { |
| 2811 if (!this.raised) { |
| 2812 this._setElevation(0); |
| 2813 } else { |
| 2814 Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this); |
| 2815 } |
| 2816 } |
| 2817 }); |
| 2818 |
| 2819 (function() { |
| 2820 var metaDatas = {}; |
| 2821 var metaArrays = {}; |
| 2822 var singleton = null; |
| 2823 Polymer.IronMeta = Polymer({ |
| 2824 is: 'iron-meta', |
| 2825 properties: { |
| 2826 type: { |
| 2827 type: String, |
| 2828 value: 'default', |
| 2829 observer: '_typeChanged' |
| 2830 }, |
| 2831 key: { |
| 2832 type: String, |
| 2833 observer: '_keyChanged' |
| 2834 }, |
| 2835 value: { |
| 2836 type: Object, |
| 2837 notify: true, |
| 2838 observer: '_valueChanged' |
| 2839 }, |
| 2840 self: { |
| 2841 type: Boolean, |
| 2842 observer: '_selfChanged' |
| 2843 }, |
| 2844 list: { |
| 2845 type: Array, |
| 2846 notify: true |
| 2847 } |
| 2848 }, |
| 2849 hostAttributes: { |
| 2850 hidden: true |
| 2851 }, |
| 2852 factoryImpl: function(config) { |
| 2853 if (config) { |
| 2854 for (var n in config) { |
| 2855 switch (n) { |
| 2856 case 'type': |
| 2857 case 'key': |
| 2858 case 'value': |
| 2859 this[n] = config[n]; |
| 2860 break; |
| 2861 } |
| 2862 } |
| 2863 } |
| 2864 }, |
| 2865 created: function() { |
| 2866 this._metaDatas = metaDatas; |
| 2867 this._metaArrays = metaArrays; |
| 2868 }, |
| 2869 _keyChanged: function(key, old) { |
| 2870 this._resetRegistration(old); |
| 2871 }, |
| 2872 _valueChanged: function(value) { |
| 2873 this._resetRegistration(this.key); |
| 2874 }, |
| 2875 _selfChanged: function(self) { |
| 2876 if (self) { |
| 2877 this.value = this; |
| 2878 } |
| 2879 }, |
| 2880 _typeChanged: function(type) { |
| 2881 this._unregisterKey(this.key); |
| 2882 if (!metaDatas[type]) { |
| 2883 metaDatas[type] = {}; |
| 2884 } |
| 2885 this._metaData = metaDatas[type]; |
| 2886 if (!metaArrays[type]) { |
| 2887 metaArrays[type] = []; |
| 2888 } |
| 2889 this.list = metaArrays[type]; |
| 2890 this._registerKeyValue(this.key, this.value); |
| 2891 }, |
| 2892 byKey: function(key) { |
| 2893 return this._metaData && this._metaData[key]; |
| 2894 }, |
| 2895 _resetRegistration: function(oldKey) { |
| 2896 this._unregisterKey(oldKey); |
| 2897 this._registerKeyValue(this.key, this.value); |
| 2898 }, |
| 2899 _unregisterKey: function(key) { |
| 2900 this._unregister(key, this._metaData, this.list); |
| 2901 }, |
| 2902 _registerKeyValue: function(key, value) { |
| 2903 this._register(key, value, this._metaData, this.list); |
| 2904 }, |
| 2905 _register: function(key, value, data, list) { |
| 2906 if (key && data && value !== undefined) { |
| 2907 data[key] = value; |
| 2908 list.push(value); |
| 2909 } |
| 2910 }, |
| 2911 _unregister: function(key, data, list) { |
| 2912 if (key && data) { |
| 2913 if (key in data) { |
| 2914 var value = data[key]; |
| 2915 delete data[key]; |
| 2916 this.arrayDelete(list, value); |
| 2917 } |
| 2918 } |
| 2919 } |
| 2920 }); |
| 2921 Polymer.IronMeta.getIronMeta = function getIronMeta() { |
| 2922 if (singleton === null) { |
| 2923 singleton = new Polymer.IronMeta(); |
| 2924 } |
| 2925 return singleton; |
| 2926 }; |
| 2927 Polymer.IronMetaQuery = Polymer({ |
| 2928 is: 'iron-meta-query', |
| 2929 properties: { |
| 2930 type: { |
| 2931 type: String, |
| 2932 value: 'default', |
| 2933 observer: '_typeChanged' |
| 2934 }, |
| 2935 key: { |
| 2936 type: String, |
| 2937 observer: '_keyChanged' |
| 2938 }, |
| 2939 value: { |
| 2940 type: Object, |
| 2941 notify: true, |
| 2942 readOnly: true |
| 2943 }, |
| 2944 list: { |
| 2945 type: Array, |
| 2946 notify: true |
| 2947 } |
| 2948 }, |
| 2949 factoryImpl: function(config) { |
| 2950 if (config) { |
| 2951 for (var n in config) { |
| 2952 switch (n) { |
| 2953 case 'type': |
| 2954 case 'key': |
| 2955 this[n] = config[n]; |
| 2956 break; |
| 2957 } |
| 2958 } |
| 2959 } |
| 2960 }, |
| 2961 created: function() { |
| 2962 this._metaDatas = metaDatas; |
| 2963 this._metaArrays = metaArrays; |
| 2964 }, |
| 2965 _keyChanged: function(key) { |
| 2966 this._setValue(this._metaData && this._metaData[key]); |
| 2967 }, |
| 2968 _typeChanged: function(type) { |
| 2969 this._metaData = metaDatas[type]; |
| 2970 this.list = metaArrays[type]; |
| 2971 if (this.key) { |
| 2972 this._keyChanged(this.key); |
| 2973 } |
| 2974 }, |
| 2975 byKey: function(key) { |
| 2976 return this._metaData && this._metaData[key]; |
| 2977 } |
| 2978 }); |
| 2979 })(); |
| 2980 |
| 2981 Polymer({ |
| 2982 is: 'iron-icon', |
| 2983 properties: { |
| 2984 icon: { |
| 2985 type: String, |
| 2986 observer: '_iconChanged' |
| 2987 }, |
| 2988 theme: { |
| 2989 type: String, |
| 2990 observer: '_updateIcon' |
| 2991 }, |
| 2992 src: { |
| 2993 type: String, |
| 2994 observer: '_srcChanged' |
| 2995 }, |
| 2996 _meta: { |
| 2997 value: Polymer.Base.create('iron-meta', { |
| 2998 type: 'iconset' |
| 2999 }), |
| 3000 observer: '_updateIcon' |
| 3001 } |
| 3002 }, |
| 3003 _DEFAULT_ICONSET: 'icons', |
| 3004 _iconChanged: function(icon) { |
| 3005 var parts = (icon || '').split(':'); |
| 3006 this._iconName = parts.pop(); |
| 3007 this._iconsetName = parts.pop() || this._DEFAULT_ICONSET; |
| 3008 this._updateIcon(); |
| 3009 }, |
| 3010 _srcChanged: function(src) { |
| 3011 this._updateIcon(); |
| 3012 }, |
| 3013 _usesIconset: function() { |
| 3014 return this.icon || !this.src; |
| 3015 }, |
| 3016 _updateIcon: function() { |
| 3017 if (this._usesIconset()) { |
| 3018 if (this._img && this._img.parentNode) { |
| 3019 Polymer.dom(this.root).removeChild(this._img); |
| 3020 } |
| 3021 if (this._iconName === "") { |
| 3022 if (this._iconset) { |
| 3023 this._iconset.removeIcon(this); |
| 3024 } |
| 3025 } else if (this._iconsetName && this._meta) { |
| 3026 this._iconset = this._meta.byKey(this._iconsetName); |
| 3027 if (this._iconset) { |
| 3028 this._iconset.applyIcon(this, this._iconName, this.theme); |
| 3029 this.unlisten(window, 'iron-iconset-added', '_updateIcon'); |
| 3030 } else { |
| 3031 this.listen(window, 'iron-iconset-added', '_updateIcon'); |
| 3032 } |
| 3033 } |
| 3034 } else { |
| 3035 if (this._iconset) { |
| 3036 this._iconset.removeIcon(this); |
| 3037 } |
| 3038 if (!this._img) { |
| 3039 this._img = document.createElement('img'); |
| 3040 this._img.style.width = '100%'; |
| 3041 this._img.style.height = '100%'; |
| 3042 this._img.draggable = false; |
| 3043 } |
| 3044 this._img.src = this.src; |
| 3045 Polymer.dom(this.root).appendChild(this._img); |
| 3046 } |
| 3047 } |
| 3048 }); |
| 3049 |
| 3050 Polymer.PaperInkyFocusBehaviorImpl = { |
| 3051 observers: [ '_focusedChanged(receivedFocusFromKeyboard)' ], |
| 3052 _focusedChanged: function(receivedFocusFromKeyboard) { |
| 3053 if (receivedFocusFromKeyboard) { |
| 3054 this.ensureRipple(); |
| 3055 } |
| 3056 if (this.hasRipple()) { |
| 3057 this._ripple.holdDown = receivedFocusFromKeyboard; |
| 3058 } |
| 3059 }, |
| 3060 _createRipple: function() { |
| 3061 var ripple = Polymer.PaperRippleBehavior._createRipple(); |
| 3062 ripple.id = 'ink'; |
| 3063 ripple.setAttribute('center', ''); |
| 3064 ripple.classList.add('circle'); |
| 3065 return ripple; |
| 3066 } |
| 3067 }; |
| 3068 |
| 3069 Polymer.PaperInkyFocusBehavior = [ Polymer.IronButtonState, Polymer.IronControlS
tate, Polymer.PaperRippleBehavior, Polymer.PaperInkyFocusBehaviorImpl ]; |
| 3070 |
| 3071 Polymer({ |
| 3072 is: 'paper-icon-button', |
| 3073 hostAttributes: { |
| 3074 role: 'button', |
| 3075 tabindex: '0' |
| 3076 }, |
| 3077 behaviors: [ Polymer.PaperInkyFocusBehavior ], |
| 3078 properties: { |
| 3079 src: { |
| 3080 type: String |
| 3081 }, |
| 3082 icon: { |
| 3083 type: String |
| 3084 }, |
| 3085 alt: { |
| 3086 type: String, |
| 3087 observer: "_altChanged" |
| 3088 } |
| 3089 }, |
| 3090 _altChanged: function(newValue, oldValue) { |
| 3091 var label = this.getAttribute('aria-label'); |
| 3092 if (!label || oldValue == label) { |
| 3093 this.setAttribute('aria-label', newValue); |
| 3094 } |
| 3095 } |
| 3096 }); |
| 3097 |
| 3098 Polymer({ |
| 3099 is: 'paper-tab', |
| 3100 behaviors: [ Polymer.IronControlState, Polymer.IronButtonState, Polymer.PaperR
ippleBehavior ], |
| 3101 properties: { |
| 3102 link: { |
| 3103 type: Boolean, |
| 3104 value: false, |
| 3105 reflectToAttribute: true |
| 3106 } |
| 3107 }, |
| 3108 hostAttributes: { |
| 3109 role: 'tab' |
| 3110 }, |
| 3111 listeners: { |
| 3112 down: '_updateNoink', |
| 3113 tap: '_onTap' |
| 3114 }, |
| 3115 attached: function() { |
| 3116 this._updateNoink(); |
| 3117 }, |
| 3118 get _parentNoink() { |
| 3119 var parent = Polymer.dom(this).parentNode; |
| 3120 return !!parent && !!parent.noink; |
| 3121 }, |
| 3122 _updateNoink: function() { |
| 3123 this.noink = !!this.noink || !!this._parentNoink; |
| 3124 }, |
| 3125 _onTap: function(event) { |
| 3126 if (this.link) { |
| 3127 var anchor = this.queryEffectiveChildren('a'); |
| 3128 if (!anchor) { |
| 3129 return; |
| 3130 } |
| 3131 if (event.target === anchor) { |
| 3132 return; |
| 3133 } |
| 3134 anchor.click(); |
| 3135 } |
| 3136 } |
| 3137 }); |
| 3138 |
| 3139 Polymer.IronMultiSelectableBehaviorImpl = { |
| 3140 properties: { |
| 3141 multi: { |
| 3142 type: Boolean, |
| 3143 value: false, |
| 3144 observer: 'multiChanged' |
| 3145 }, |
| 3146 selectedValues: { |
| 3147 type: Array, |
| 3148 notify: true |
| 3149 }, |
| 3150 selectedItems: { |
| 3151 type: Array, |
| 3152 readOnly: true, |
| 3153 notify: true |
| 3154 } |
| 3155 }, |
| 3156 observers: [ '_updateSelected(selectedValues.splices)' ], |
| 3157 select: function(value) { |
| 3158 if (this.multi) { |
| 3159 if (this.selectedValues) { |
| 3160 this._toggleSelected(value); |
| 3161 } else { |
| 3162 this.selectedValues = [ value ]; |
| 3163 } |
| 3164 } else { |
| 3165 this.selected = value; |
| 3166 } |
| 3167 }, |
| 3168 multiChanged: function(multi) { |
| 3169 this._selection.multi = multi; |
| 3170 }, |
| 3171 get _shouldUpdateSelection() { |
| 3172 return this.selected != null || this.selectedValues != null && this.selected
Values.length; |
| 3173 }, |
| 3174 _updateAttrForSelected: function() { |
| 3175 if (!this.multi) { |
| 3176 Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this); |
| 3177 } else if (this._shouldUpdateSelection) { |
| 3178 this.selectedValues = this.selectedItems.map(function(selectedItem) { |
| 3179 return this._indexToValue(this.indexOf(selectedItem)); |
| 3180 }, this).filter(function(unfilteredValue) { |
| 3181 return unfilteredValue != null; |
| 3182 }, this); |
| 3183 } |
| 3184 }, |
| 3185 _updateSelected: function() { |
| 3186 if (this.multi) { |
| 3187 this._selectMulti(this.selectedValues); |
| 3188 } else { |
| 3189 this._selectSelected(this.selected); |
| 3190 } |
| 3191 }, |
| 3192 _selectMulti: function(values) { |
| 3193 if (values) { |
| 3194 var selectedItems = this._valuesToItems(values); |
| 3195 this._selection.clear(selectedItems); |
| 3196 for (var i = 0; i < selectedItems.length; i++) { |
| 3197 this._selection.setItemSelected(selectedItems[i], true); |
| 3198 } |
| 3199 if (this.fallbackSelection && this.items.length && !this._selection.get().
length) { |
| 3200 var fallback = this._valueToItem(this.fallbackSelection); |
| 3201 if (fallback) { |
| 3202 this.selectedValues = [ this.fallbackSelection ]; |
| 3203 } |
| 3204 } |
| 3205 } else { |
| 3206 this._selection.clear(); |
| 3207 } |
| 3208 }, |
| 3209 _selectionChange: function() { |
| 3210 var s = this._selection.get(); |
| 3211 if (this.multi) { |
| 3212 this._setSelectedItems(s); |
| 3213 } else { |
| 3214 this._setSelectedItems([ s ]); |
| 3215 this._setSelectedItem(s); |
| 3216 } |
| 3217 }, |
| 3218 _toggleSelected: function(value) { |
| 3219 var i = this.selectedValues.indexOf(value); |
| 3220 var unselected = i < 0; |
| 3221 if (unselected) { |
| 3222 this.push('selectedValues', value); |
| 3223 } else { |
| 3224 this.splice('selectedValues', i, 1); |
| 3225 } |
| 3226 }, |
| 3227 _valuesToItems: function(values) { |
| 3228 return values == null ? null : values.map(function(value) { |
| 3229 return this._valueToItem(value); |
| 3230 }, this); |
| 3231 } |
| 3232 }; |
| 3233 |
| 3234 Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer.
IronMultiSelectableBehaviorImpl ]; |
| 3235 |
| 3236 Polymer.IronMenuBehaviorImpl = { |
| 3237 properties: { |
| 3238 focusedItem: { |
| 3239 observer: '_focusedItemChanged', |
| 3240 readOnly: true, |
| 3241 type: Object |
| 3242 }, |
| 3243 attrForItemTitle: { |
| 3244 type: String |
| 3245 } |
| 3246 }, |
| 3247 hostAttributes: { |
| 3248 role: 'menu', |
| 3249 tabindex: '0' |
| 3250 }, |
| 3251 observers: [ '_updateMultiselectable(multi)' ], |
| 3252 listeners: { |
| 3253 focus: '_onFocus', |
| 3254 keydown: '_onKeydown', |
| 3255 'iron-items-changed': '_onIronItemsChanged' |
| 3256 }, |
| 3257 keyBindings: { |
| 3258 up: '_onUpKey', |
| 3259 down: '_onDownKey', |
| 3260 esc: '_onEscKey', |
| 3261 'shift+tab:keydown': '_onShiftTabDown' |
| 3262 }, |
| 3263 attached: function() { |
| 3264 this._resetTabindices(); |
| 3265 }, |
| 3266 select: function(value) { |
| 3267 if (this._defaultFocusAsync) { |
| 3268 this.cancelAsync(this._defaultFocusAsync); |
| 3269 this._defaultFocusAsync = null; |
| 3270 } |
| 3271 var item = this._valueToItem(value); |
| 3272 if (item && item.hasAttribute('disabled')) return; |
| 3273 this._setFocusedItem(item); |
| 3274 Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments); |
| 3275 }, |
| 3276 _resetTabindices: function() { |
| 3277 var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0]
: this.selectedItem; |
| 3278 this.items.forEach(function(item) { |
| 3279 item.setAttribute('tabindex', item === selectedItem ? '0' : '-1'); |
| 3280 }, this); |
| 3281 }, |
| 3282 _updateMultiselectable: function(multi) { |
| 3283 if (multi) { |
| 3284 this.setAttribute('aria-multiselectable', 'true'); |
| 3285 } else { |
| 3286 this.removeAttribute('aria-multiselectable'); |
| 3287 } |
| 3288 }, |
| 3289 _focusWithKeyboardEvent: function(event) { |
| 3290 for (var i = 0, item; item = this.items[i]; i++) { |
| 3291 var attr = this.attrForItemTitle || 'textContent'; |
| 3292 var title = item[attr] || item.getAttribute(attr); |
| 3293 if (!item.hasAttribute('disabled') && title && title.trim().charAt(0).toLo
werCase() === String.fromCharCode(event.keyCode).toLowerCase()) { |
| 3294 this._setFocusedItem(item); |
| 3295 break; |
| 3296 } |
| 3297 } |
| 3298 }, |
| 3299 _focusPrevious: function() { |
| 3300 var length = this.items.length; |
| 3301 var curFocusIndex = Number(this.indexOf(this.focusedItem)); |
| 3302 for (var i = 1; i < length + 1; i++) { |
| 3303 var item = this.items[(curFocusIndex - i + length) % length]; |
| 3304 if (!item.hasAttribute('disabled')) { |
| 3305 this._setFocusedItem(item); |
| 3306 return; |
| 3307 } |
| 3308 } |
| 3309 }, |
| 3310 _focusNext: function() { |
| 3311 var length = this.items.length; |
| 3312 var curFocusIndex = Number(this.indexOf(this.focusedItem)); |
| 3313 for (var i = 1; i < length + 1; i++) { |
| 3314 var item = this.items[(curFocusIndex + i) % length]; |
| 3315 if (!item.hasAttribute('disabled')) { |
| 3316 this._setFocusedItem(item); |
| 3317 return; |
| 3318 } |
| 3319 } |
| 3320 }, |
| 3321 _applySelection: function(item, isSelected) { |
| 3322 if (isSelected) { |
| 3323 item.setAttribute('aria-selected', 'true'); |
| 3324 } else { |
| 3325 item.removeAttribute('aria-selected'); |
| 3326 } |
| 3327 Polymer.IronSelectableBehavior._applySelection.apply(this, arguments); |
| 3328 }, |
| 3329 _focusedItemChanged: function(focusedItem, old) { |
| 3330 old && old.setAttribute('tabindex', '-1'); |
| 3331 if (focusedItem) { |
| 3332 focusedItem.setAttribute('tabindex', '0'); |
| 3333 focusedItem.focus(); |
| 3334 } |
| 3335 }, |
| 3336 _onIronItemsChanged: function(event) { |
| 3337 if (event.detail.addedNodes.length) { |
| 3338 this._resetTabindices(); |
| 3339 } |
| 3340 }, |
| 3341 _onShiftTabDown: function(event) { |
| 3342 var oldTabIndex = this.getAttribute('tabindex'); |
| 3343 Polymer.IronMenuBehaviorImpl._shiftTabPressed = true; |
| 3344 this._setFocusedItem(null); |
| 3345 this.setAttribute('tabindex', '-1'); |
| 3346 this.async(function() { |
| 3347 this.setAttribute('tabindex', oldTabIndex); |
| 3348 Polymer.IronMenuBehaviorImpl._shiftTabPressed = false; |
| 3349 }, 1); |
| 3350 }, |
| 3351 _onFocus: function(event) { |
| 3352 if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) { |
| 3353 return; |
| 3354 } |
| 3355 var rootTarget = Polymer.dom(event).rootTarget; |
| 3356 if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !th
is.isLightDescendant(rootTarget)) { |
| 3357 return; |
| 3358 } |
| 3359 this._defaultFocusAsync = this.async(function() { |
| 3360 var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0
] : this.selectedItem; |
| 3361 this._setFocusedItem(null); |
| 3362 if (selectedItem) { |
| 3363 this._setFocusedItem(selectedItem); |
| 3364 } else if (this.items[0]) { |
| 3365 this._focusNext(); |
| 3366 } |
| 3367 }); |
| 3368 }, |
| 3369 _onUpKey: function(event) { |
| 3370 this._focusPrevious(); |
| 3371 event.detail.keyboardEvent.preventDefault(); |
| 3372 }, |
| 3373 _onDownKey: function(event) { |
| 3374 this._focusNext(); |
| 3375 event.detail.keyboardEvent.preventDefault(); |
| 3376 }, |
| 3377 _onEscKey: function(event) { |
| 3378 this.focusedItem.blur(); |
| 3379 }, |
| 3380 _onKeydown: function(event) { |
| 3381 if (!this.keyboardEventMatchesKeys(event, 'up down esc')) { |
| 3382 this._focusWithKeyboardEvent(event); |
| 3383 } |
| 3384 event.stopPropagation(); |
| 3385 }, |
| 3386 _activateHandler: function(event) { |
| 3387 Polymer.IronSelectableBehavior._activateHandler.call(this, event); |
| 3388 event.stopPropagation(); |
| 3389 } |
| 3390 }; |
| 3391 |
| 3392 Polymer.IronMenuBehaviorImpl._shiftTabPressed = false; |
| 3393 |
| 3394 Polymer.IronMenuBehavior = [ Polymer.IronMultiSelectableBehavior, Polymer.IronA1
1yKeysBehavior, Polymer.IronMenuBehaviorImpl ]; |
| 3395 |
| 3396 Polymer.IronMenubarBehaviorImpl = { |
| 3397 hostAttributes: { |
| 3398 role: 'menubar' |
| 3399 }, |
| 3400 keyBindings: { |
| 3401 left: '_onLeftKey', |
| 3402 right: '_onRightKey' |
| 3403 }, |
| 3404 _onUpKey: function(event) { |
| 3405 this.focusedItem.click(); |
| 3406 event.detail.keyboardEvent.preventDefault(); |
| 3407 }, |
| 3408 _onDownKey: function(event) { |
| 3409 this.focusedItem.click(); |
| 3410 event.detail.keyboardEvent.preventDefault(); |
| 3411 }, |
| 3412 get _isRTL() { |
| 3413 return window.getComputedStyle(this)['direction'] === 'rtl'; |
| 3414 }, |
| 3415 _onLeftKey: function(event) { |
| 3416 if (this._isRTL) { |
| 3417 this._focusNext(); |
| 3418 } else { |
| 3419 this._focusPrevious(); |
| 3420 } |
| 3421 event.detail.keyboardEvent.preventDefault(); |
| 3422 }, |
| 3423 _onRightKey: function(event) { |
| 3424 if (this._isRTL) { |
| 3425 this._focusPrevious(); |
| 3426 } else { |
| 3427 this._focusNext(); |
| 3428 } |
| 3429 event.detail.keyboardEvent.preventDefault(); |
| 3430 }, |
| 3431 _onKeydown: function(event) { |
| 3432 if (this.keyboardEventMatchesKeys(event, 'up down left right esc')) { |
| 3433 return; |
| 3434 } |
| 3435 this._focusWithKeyboardEvent(event); |
| 3436 } |
| 3437 }; |
| 3438 |
| 3439 Polymer.IronMenubarBehavior = [ Polymer.IronMenuBehavior, Polymer.IronMenubarBeh
aviorImpl ]; |
| 3440 |
| 3441 Polymer({ |
| 3442 is: 'iron-iconset-svg', |
| 3443 properties: { |
| 3444 name: { |
| 3445 type: String, |
| 3446 observer: '_nameChanged' |
| 3447 }, |
| 3448 size: { |
| 3449 type: Number, |
| 3450 value: 24 |
| 3451 } |
| 3452 }, |
| 3453 attached: function() { |
| 3454 this.style.display = 'none'; |
| 3455 }, |
| 3456 getIconNames: function() { |
| 3457 this._icons = this._createIconMap(); |
| 3458 return Object.keys(this._icons).map(function(n) { |
| 3459 return this.name + ':' + n; |
| 3460 }, this); |
| 3461 }, |
| 3462 applyIcon: function(element, iconName) { |
| 3463 element = element.root || element; |
| 3464 this.removeIcon(element); |
| 3465 var svg = this._cloneIcon(iconName); |
| 3466 if (svg) { |
| 3467 var pde = Polymer.dom(element); |
| 3468 pde.insertBefore(svg, pde.childNodes[0]); |
| 3469 return element._svgIcon = svg; |
| 3470 } |
| 3471 return null; |
| 3472 }, |
| 3473 removeIcon: function(element) { |
| 3474 if (element._svgIcon) { |
| 3475 Polymer.dom(element).removeChild(element._svgIcon); |
| 3476 element._svgIcon = null; |
| 3477 } |
| 3478 }, |
| 3479 _nameChanged: function() { |
| 3480 new Polymer.IronMeta({ |
| 3481 type: 'iconset', |
| 3482 key: this.name, |
| 3483 value: this |
| 3484 }); |
| 3485 this.async(function() { |
| 3486 this.fire('iron-iconset-added', this, { |
| 3487 node: window |
| 3488 }); |
| 3489 }); |
| 3490 }, |
| 3491 _createIconMap: function() { |
| 3492 var icons = Object.create(null); |
| 3493 Polymer.dom(this).querySelectorAll('[id]').forEach(function(icon) { |
| 3494 icons[icon.id] = icon; |
| 3495 }); |
| 3496 return icons; |
| 3497 }, |
| 3498 _cloneIcon: function(id) { |
| 3499 this._icons = this._icons || this._createIconMap(); |
| 3500 return this._prepareSvgClone(this._icons[id], this.size); |
| 3501 }, |
| 3502 _prepareSvgClone: function(sourceSvg, size) { |
| 3503 if (sourceSvg) { |
| 3504 var content = sourceSvg.cloneNode(true), svg = document.createElementNS('h
ttp://www.w3.org/2000/svg', 'svg'), viewBox = content.getAttribute('viewBox') ||
'0 0 ' + size + ' ' + size; |
| 3505 svg.setAttribute('viewBox', viewBox); |
| 3506 svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); |
| 3507 svg.style.cssText = 'pointer-events: none; display: block; width: 100%; he
ight: 100%;'; |
| 3508 svg.appendChild(content).removeAttribute('id'); |
| 3509 return svg; |
| 3510 } |
| 3511 return null; |
| 3512 } |
| 3513 }); |
| 3514 |
| 3515 Polymer({ |
| 3516 is: 'paper-tabs', |
| 3517 behaviors: [ Polymer.IronResizableBehavior, Polymer.IronMenubarBehavior ], |
| 3518 properties: { |
| 3519 noink: { |
| 3520 type: Boolean, |
| 3521 value: false, |
| 3522 observer: '_noinkChanged' |
| 3523 }, |
| 3524 noBar: { |
| 3525 type: Boolean, |
| 3526 value: false |
| 3527 }, |
| 3528 noSlide: { |
| 3529 type: Boolean, |
| 3530 value: false |
| 3531 }, |
| 3532 scrollable: { |
| 3533 type: Boolean, |
| 3534 value: false |
| 3535 }, |
| 3536 fitContainer: { |
| 3537 type: Boolean, |
| 3538 value: false |
| 3539 }, |
| 3540 disableDrag: { |
| 3541 type: Boolean, |
| 3542 value: false |
| 3543 }, |
| 3544 hideScrollButtons: { |
| 3545 type: Boolean, |
| 3546 value: false |
| 3547 }, |
| 3548 alignBottom: { |
| 3549 type: Boolean, |
| 3550 value: false |
| 3551 }, |
| 3552 selectable: { |
| 3553 type: String, |
| 3554 value: 'paper-tab' |
| 3555 }, |
| 3556 autoselect: { |
| 3557 type: Boolean, |
| 3558 value: false |
| 3559 }, |
| 3560 autoselectDelay: { |
| 3561 type: Number, |
| 3562 value: 0 |
| 3563 }, |
| 3564 _step: { |
| 3565 type: Number, |
| 3566 value: 10 |
| 3567 }, |
| 3568 _holdDelay: { |
| 3569 type: Number, |
| 3570 value: 1 |
| 3571 }, |
| 3572 _leftHidden: { |
| 3573 type: Boolean, |
| 3574 value: false |
| 3575 }, |
| 3576 _rightHidden: { |
| 3577 type: Boolean, |
| 3578 value: false |
| 3579 }, |
| 3580 _previousTab: { |
| 3581 type: Object |
| 3582 } |
| 3583 }, |
| 3584 hostAttributes: { |
| 3585 role: 'tablist' |
| 3586 }, |
| 3587 listeners: { |
| 3588 'iron-resize': '_onTabSizingChanged', |
| 3589 'iron-items-changed': '_onTabSizingChanged', |
| 3590 'iron-select': '_onIronSelect', |
| 3591 'iron-deselect': '_onIronDeselect' |
| 3592 }, |
| 3593 keyBindings: { |
| 3594 'left:keyup right:keyup': '_onArrowKeyup' |
| 3595 }, |
| 3596 created: function() { |
| 3597 this._holdJob = null; |
| 3598 this._pendingActivationItem = undefined; |
| 3599 this._pendingActivationTimeout = undefined; |
| 3600 this._bindDelayedActivationHandler = this._delayedActivationHandler.bind(thi
s); |
| 3601 this.addEventListener('blur', this._onBlurCapture.bind(this), true); |
| 3602 }, |
| 3603 ready: function() { |
| 3604 this.setScrollDirection('y', this.$.tabsContainer); |
| 3605 }, |
| 3606 detached: function() { |
| 3607 this._cancelPendingActivation(); |
| 3608 }, |
| 3609 _noinkChanged: function(noink) { |
| 3610 var childTabs = Polymer.dom(this).querySelectorAll('paper-tab'); |
| 3611 childTabs.forEach(noink ? this._setNoinkAttribute : this._removeNoinkAttribu
te); |
| 3612 }, |
| 3613 _setNoinkAttribute: function(element) { |
| 3614 element.setAttribute('noink', ''); |
| 3615 }, |
| 3616 _removeNoinkAttribute: function(element) { |
| 3617 element.removeAttribute('noink'); |
| 3618 }, |
| 3619 _computeScrollButtonClass: function(hideThisButton, scrollable, hideScrollButt
ons) { |
| 3620 if (!scrollable || hideScrollButtons) { |
| 3621 return 'hidden'; |
| 3622 } |
| 3623 if (hideThisButton) { |
| 3624 return 'not-visible'; |
| 3625 } |
| 3626 return ''; |
| 3627 }, |
| 3628 _computeTabsContentClass: function(scrollable, fitContainer) { |
| 3629 return scrollable ? 'scrollable' + (fitContainer ? ' fit-container' : '') :
' fit-container'; |
| 3630 }, |
| 3631 _computeSelectionBarClass: function(noBar, alignBottom) { |
| 3632 if (noBar) { |
| 3633 return 'hidden'; |
| 3634 } else if (alignBottom) { |
| 3635 return 'align-bottom'; |
| 3636 } |
| 3637 return ''; |
| 3638 }, |
| 3639 _onTabSizingChanged: function() { |
| 3640 this.debounce('_onTabSizingChanged', function() { |
| 3641 this._scroll(); |
| 3642 this._tabChanged(this.selectedItem); |
| 3643 }, 10); |
| 3644 }, |
| 3645 _onIronSelect: function(event) { |
| 3646 this._tabChanged(event.detail.item, this._previousTab); |
| 3647 this._previousTab = event.detail.item; |
| 3648 this.cancelDebouncer('tab-changed'); |
| 3649 }, |
| 3650 _onIronDeselect: function(event) { |
| 3651 this.debounce('tab-changed', function() { |
| 3652 this._tabChanged(null, this._previousTab); |
| 3653 this._previousTab = null; |
| 3654 }, 1); |
| 3655 }, |
| 3656 _activateHandler: function() { |
| 3657 this._cancelPendingActivation(); |
| 3658 Polymer.IronMenuBehaviorImpl._activateHandler.apply(this, arguments); |
| 3659 }, |
| 3660 _scheduleActivation: function(item, delay) { |
| 3661 this._pendingActivationItem = item; |
| 3662 this._pendingActivationTimeout = this.async(this._bindDelayedActivationHandl
er, delay); |
| 3663 }, |
| 3664 _delayedActivationHandler: function() { |
| 3665 var item = this._pendingActivationItem; |
| 3666 this._pendingActivationItem = undefined; |
| 3667 this._pendingActivationTimeout = undefined; |
| 3668 item.fire(this.activateEvent, null, { |
| 3669 bubbles: true, |
| 3670 cancelable: true |
| 3671 }); |
| 3672 }, |
| 3673 _cancelPendingActivation: function() { |
| 3674 if (this._pendingActivationTimeout !== undefined) { |
| 3675 this.cancelAsync(this._pendingActivationTimeout); |
| 3676 this._pendingActivationItem = undefined; |
| 3677 this._pendingActivationTimeout = undefined; |
| 3678 } |
| 3679 }, |
| 3680 _onArrowKeyup: function(event) { |
| 3681 if (this.autoselect) { |
| 3682 this._scheduleActivation(this.focusedItem, this.autoselectDelay); |
| 3683 } |
| 3684 }, |
| 3685 _onBlurCapture: function(event) { |
| 3686 if (event.target === this._pendingActivationItem) { |
| 3687 this._cancelPendingActivation(); |
| 3688 } |
| 3689 }, |
| 3690 get _tabContainerScrollSize() { |
| 3691 return Math.max(0, this.$.tabsContainer.scrollWidth - this.$.tabsContainer.o
ffsetWidth); |
| 3692 }, |
| 3693 _scroll: function(e, detail) { |
| 3694 if (!this.scrollable) { |
| 3695 return; |
| 3696 } |
| 3697 var ddx = detail && -detail.ddx || 0; |
| 3698 this._affectScroll(ddx); |
| 3699 }, |
| 3700 _down: function(e) { |
| 3701 this.async(function() { |
| 3702 if (this._defaultFocusAsync) { |
| 3703 this.cancelAsync(this._defaultFocusAsync); |
| 3704 this._defaultFocusAsync = null; |
| 3705 } |
| 3706 }, 1); |
| 3707 }, |
| 3708 _affectScroll: function(dx) { |
| 3709 this.$.tabsContainer.scrollLeft += dx; |
| 3710 var scrollLeft = this.$.tabsContainer.scrollLeft; |
| 3711 this._leftHidden = scrollLeft === 0; |
| 3712 this._rightHidden = scrollLeft === this._tabContainerScrollSize; |
| 3713 }, |
| 3714 _onLeftScrollButtonDown: function() { |
| 3715 this._scrollToLeft(); |
| 3716 this._holdJob = setInterval(this._scrollToLeft.bind(this), this._holdDelay); |
| 3717 }, |
| 3718 _onRightScrollButtonDown: function() { |
| 3719 this._scrollToRight(); |
| 3720 this._holdJob = setInterval(this._scrollToRight.bind(this), this._holdDelay)
; |
| 3721 }, |
| 3722 _onScrollButtonUp: function() { |
| 3723 clearInterval(this._holdJob); |
| 3724 this._holdJob = null; |
| 3725 }, |
| 3726 _scrollToLeft: function() { |
| 3727 this._affectScroll(-this._step); |
| 3728 }, |
| 3729 _scrollToRight: function() { |
| 3730 this._affectScroll(this._step); |
| 3731 }, |
| 3732 _tabChanged: function(tab, old) { |
| 3733 if (!tab) { |
| 3734 this.$.selectionBar.classList.remove('expand'); |
| 3735 this.$.selectionBar.classList.remove('contract'); |
| 3736 this._positionBar(0, 0); |
| 3737 return; |
| 3738 } |
| 3739 var r = this.$.tabsContent.getBoundingClientRect(); |
| 3740 var w = r.width; |
| 3741 var tabRect = tab.getBoundingClientRect(); |
| 3742 var tabOffsetLeft = tabRect.left - r.left; |
| 3743 this._pos = { |
| 3744 width: this._calcPercent(tabRect.width, w), |
| 3745 left: this._calcPercent(tabOffsetLeft, w) |
| 3746 }; |
| 3747 if (this.noSlide || old == null) { |
| 3748 this.$.selectionBar.classList.remove('expand'); |
| 3749 this.$.selectionBar.classList.remove('contract'); |
| 3750 this._positionBar(this._pos.width, this._pos.left); |
| 3751 return; |
| 3752 } |
| 3753 var oldRect = old.getBoundingClientRect(); |
| 3754 var oldIndex = this.items.indexOf(old); |
| 3755 var index = this.items.indexOf(tab); |
| 3756 var m = 5; |
| 3757 this.$.selectionBar.classList.add('expand'); |
| 3758 var moveRight = oldIndex < index; |
| 3759 var isRTL = this._isRTL; |
| 3760 if (isRTL) { |
| 3761 moveRight = !moveRight; |
| 3762 } |
| 3763 if (moveRight) { |
| 3764 this._positionBar(this._calcPercent(tabRect.left + tabRect.width - oldRect
.left, w) - m, this._left); |
| 3765 } else { |
| 3766 this._positionBar(this._calcPercent(oldRect.left + oldRect.width - tabRect
.left, w) - m, this._calcPercent(tabOffsetLeft, w) + m); |
| 3767 } |
| 3768 if (this.scrollable) { |
| 3769 this._scrollToSelectedIfNeeded(tabRect.width, tabOffsetLeft); |
| 3770 } |
| 3771 }, |
| 3772 _scrollToSelectedIfNeeded: function(tabWidth, tabOffsetLeft) { |
| 3773 var l = tabOffsetLeft - this.$.tabsContainer.scrollLeft; |
| 3774 if (l < 0) { |
| 3775 this.$.tabsContainer.scrollLeft += l; |
| 3776 } else { |
| 3777 l += tabWidth - this.$.tabsContainer.offsetWidth; |
| 3778 if (l > 0) { |
| 3779 this.$.tabsContainer.scrollLeft += l; |
| 3780 } |
| 3781 } |
| 3782 }, |
| 3783 _calcPercent: function(w, w0) { |
| 3784 return 100 * w / w0; |
| 3785 }, |
| 3786 _positionBar: function(width, left) { |
| 3787 width = width || 0; |
| 3788 left = left || 0; |
| 3789 this._width = width; |
| 3790 this._left = left; |
| 3791 this.transform('translateX(' + left + '%) scaleX(' + width / 100 + ')', this
.$.selectionBar); |
| 3792 }, |
| 3793 _onBarTransitionEnd: function(e) { |
| 3794 var cl = this.$.selectionBar.classList; |
| 3795 if (cl.contains('expand')) { |
| 3796 cl.remove('expand'); |
| 3797 cl.add('contract'); |
| 3798 this._positionBar(this._pos.width, this._pos.left); |
| 3799 } else if (cl.contains('contract')) { |
| 3800 cl.remove('contract'); |
| 3801 } |
| 3802 } |
| 3803 }); |
| 3804 |
| 3805 (function() { |
| 3806 'use strict'; |
| 3807 Polymer.IronA11yAnnouncer = Polymer({ |
| 3808 is: 'iron-a11y-announcer', |
| 3809 properties: { |
| 3810 mode: { |
| 3811 type: String, |
| 3812 value: 'polite' |
| 3813 }, |
| 3814 _text: { |
| 3815 type: String, |
| 3816 value: '' |
| 3817 } |
| 3818 }, |
| 3819 created: function() { |
| 3820 if (!Polymer.IronA11yAnnouncer.instance) { |
| 3821 Polymer.IronA11yAnnouncer.instance = this; |
| 3822 } |
| 3823 document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(
this)); |
| 3824 }, |
| 3825 announce: function(text) { |
| 3826 this._text = ''; |
| 3827 this.async(function() { |
| 3828 this._text = text; |
| 3829 }, 100); |
| 3830 }, |
| 3831 _onIronAnnounce: function(event) { |
| 3832 if (event.detail && event.detail.text) { |
| 3833 this.announce(event.detail.text); |
| 3834 } |
| 3835 } |
| 3836 }); |
| 3837 Polymer.IronA11yAnnouncer.instance = null; |
| 3838 Polymer.IronA11yAnnouncer.requestAvailability = function() { |
| 3839 if (!Polymer.IronA11yAnnouncer.instance) { |
| 3840 Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y-ann
ouncer'); |
| 3841 } |
| 3842 document.body.appendChild(Polymer.IronA11yAnnouncer.instance); |
| 3843 }; |
| 3844 })(); |
| 3845 |
| 3846 Polymer.IronValidatableBehaviorMeta = null; |
| 3847 |
| 3848 Polymer.IronValidatableBehavior = { |
| 3849 properties: { |
| 3850 validator: { |
| 3851 type: String |
| 3852 }, |
| 3853 invalid: { |
| 3854 notify: true, |
| 3855 reflectToAttribute: true, |
| 3856 type: Boolean, |
| 3857 value: false |
| 3858 }, |
| 3859 _validatorMeta: { |
| 3860 type: Object |
| 3861 }, |
| 3862 validatorType: { |
| 3863 type: String, |
| 3864 value: 'validator' |
| 3865 }, |
| 3866 _validator: { |
| 3867 type: Object, |
| 3868 computed: '__computeValidator(validator)' |
| 3869 } |
| 3870 }, |
| 3871 observers: [ '_invalidChanged(invalid)' ], |
| 3872 registered: function() { |
| 3873 Polymer.IronValidatableBehaviorMeta = new Polymer.IronMeta({ |
| 3874 type: 'validator' |
| 3875 }); |
| 3876 }, |
| 3877 _invalidChanged: function() { |
| 3878 if (this.invalid) { |
| 3879 this.setAttribute('aria-invalid', 'true'); |
| 3880 } else { |
| 3881 this.removeAttribute('aria-invalid'); |
| 3882 } |
| 3883 }, |
| 3884 hasValidator: function() { |
| 3885 return this._validator != null; |
| 3886 }, |
| 3887 validate: function(value) { |
| 3888 this.invalid = !this._getValidity(value); |
| 3889 return !this.invalid; |
| 3890 }, |
| 3891 _getValidity: function(value) { |
| 3892 if (this.hasValidator()) { |
| 3893 return this._validator.validate(value); |
| 3894 } |
| 3895 return true; |
| 3896 }, |
| 3897 __computeValidator: function() { |
| 3898 return Polymer.IronValidatableBehaviorMeta && Polymer.IronValidatableBehavio
rMeta.byKey(this.validator); |
| 3899 } |
| 3900 }; |
| 3901 |
| 3902 Polymer({ |
| 3903 is: 'iron-input', |
| 3904 "extends": 'input', |
| 3905 behaviors: [ Polymer.IronValidatableBehavior ], |
| 3906 properties: { |
| 3907 bindValue: { |
| 3908 observer: '_bindValueChanged', |
| 3909 type: String |
| 3910 }, |
| 3911 preventInvalidInput: { |
| 3912 type: Boolean |
| 3913 }, |
| 3914 allowedPattern: { |
| 3915 type: String, |
| 3916 observer: "_allowedPatternChanged" |
| 3917 }, |
| 3918 _previousValidInput: { |
| 3919 type: String, |
| 3920 value: '' |
| 3921 }, |
| 3922 _patternAlreadyChecked: { |
| 3923 type: Boolean, |
| 3924 value: false |
| 3925 } |
| 3926 }, |
| 3927 listeners: { |
| 3928 input: '_onInput', |
| 3929 keypress: '_onKeypress' |
| 3930 }, |
| 3931 registered: function() { |
| 3932 if (!this._canDispatchEventOnDisabled()) { |
| 3933 this._origDispatchEvent = this.dispatchEvent; |
| 3934 this.dispatchEvent = this._dispatchEventFirefoxIE; |
| 3935 } |
| 3936 }, |
| 3937 created: function() { |
| 3938 Polymer.IronA11yAnnouncer.requestAvailability(); |
| 3939 }, |
| 3940 _canDispatchEventOnDisabled: function() { |
| 3941 var input = document.createElement('input'); |
| 3942 var canDispatch = false; |
| 3943 input.disabled = true; |
| 3944 input.addEventListener('feature-check-dispatch-event', function() { |
| 3945 canDispatch = true; |
| 3946 }); |
| 3947 try { |
| 3948 input.dispatchEvent(new Event('feature-check-dispatch-event')); |
| 3949 } catch (e) {} |
| 3950 return canDispatch; |
| 3951 }, |
| 3952 _dispatchEventFirefoxIE: function() { |
| 3953 var disabled = this.disabled; |
| 3954 this.disabled = false; |
| 3955 this._origDispatchEvent.apply(this, arguments); |
| 3956 this.disabled = disabled; |
| 3957 }, |
| 3958 get _patternRegExp() { |
| 3959 var pattern; |
| 3960 if (this.allowedPattern) { |
| 3961 pattern = new RegExp(this.allowedPattern); |
| 3962 } else { |
| 3963 switch (this.type) { |
| 3964 case 'number': |
| 3965 pattern = /[0-9.,e-]/; |
| 3966 break; |
| 3967 } |
| 3968 } |
| 3969 return pattern; |
| 3970 }, |
| 3971 ready: function() { |
| 3972 this.bindValue = this.value; |
| 3973 }, |
| 3974 _bindValueChanged: function() { |
| 3975 if (this.value !== this.bindValue) { |
| 3976 this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue ==
= false) ? '' : this.bindValue; |
| 3977 } |
| 3978 this.fire('bind-value-changed', { |
| 3979 value: this.bindValue |
| 3980 }); |
| 3981 }, |
| 3982 _allowedPatternChanged: function() { |
| 3983 this.preventInvalidInput = this.allowedPattern ? true : false; |
| 3984 }, |
| 3985 _onInput: function() { |
| 3986 if (this.preventInvalidInput && !this._patternAlreadyChecked) { |
| 3987 var valid = this._checkPatternValidity(); |
| 3988 if (!valid) { |
| 3989 this._announceInvalidCharacter('Invalid string of characters not entered
.'); |
| 3990 this.value = this._previousValidInput; |
| 3991 } |
| 3992 } |
| 3993 this.bindValue = this.value; |
| 3994 this._previousValidInput = this.value; |
| 3995 this._patternAlreadyChecked = false; |
| 3996 }, |
| 3997 _isPrintable: function(event) { |
| 3998 var anyNonPrintable = event.keyCode == 8 || event.keyCode == 9 || event.keyC
ode == 13 || event.keyCode == 27; |
| 3999 var mozNonPrintable = event.keyCode == 19 || event.keyCode == 20 || event.ke
yCode == 45 || event.keyCode == 46 || event.keyCode == 144 || event.keyCode == 1
45 || event.keyCode > 32 && event.keyCode < 41 || event.keyCode > 111 && event.k
eyCode < 124; |
| 4000 return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable); |
| 4001 }, |
| 4002 _onKeypress: function(event) { |
| 4003 if (!this.preventInvalidInput && this.type !== 'number') { |
| 4004 return; |
| 4005 } |
| 4006 var regexp = this._patternRegExp; |
| 4007 if (!regexp) { |
| 4008 return; |
| 4009 } |
| 4010 if (event.metaKey || event.ctrlKey || event.altKey) return; |
| 4011 this._patternAlreadyChecked = true; |
| 4012 var thisChar = String.fromCharCode(event.charCode); |
| 4013 if (this._isPrintable(event) && !regexp.test(thisChar)) { |
| 4014 event.preventDefault(); |
| 4015 this._announceInvalidCharacter('Invalid character ' + thisChar + ' not ent
ered.'); |
| 4016 } |
| 4017 }, |
| 4018 _checkPatternValidity: function() { |
| 4019 var regexp = this._patternRegExp; |
| 4020 if (!regexp) { |
| 4021 return true; |
| 4022 } |
| 4023 for (var i = 0; i < this.value.length; i++) { |
| 4024 if (!regexp.test(this.value[i])) { |
| 4025 return false; |
| 4026 } |
| 4027 } |
| 4028 return true; |
| 4029 }, |
| 4030 validate: function() { |
| 4031 var valid = this.checkValidity(); |
| 4032 if (valid) { |
| 4033 if (this.required && this.value === '') { |
| 4034 valid = false; |
| 4035 } else if (this.hasValidator()) { |
| 4036 valid = Polymer.IronValidatableBehavior.validate.call(this, this.value); |
| 4037 } |
| 4038 } |
| 4039 this.invalid = !valid; |
| 4040 this.fire('iron-input-validate'); |
| 4041 return valid; |
| 4042 }, |
| 4043 _announceInvalidCharacter: function(message) { |
| 4044 this.fire('iron-announce', { |
| 4045 text: message |
| 4046 }); |
| 4047 } |
| 4048 }); |
| 4049 |
| 4050 Polymer({ |
| 4051 is: 'paper-input-container', |
| 4052 properties: { |
| 4053 noLabelFloat: { |
| 4054 type: Boolean, |
| 4055 value: false |
| 4056 }, |
| 4057 alwaysFloatLabel: { |
| 4058 type: Boolean, |
| 4059 value: false |
| 4060 }, |
| 4061 attrForValue: { |
| 4062 type: String, |
| 4063 value: 'bind-value' |
| 4064 }, |
| 4065 autoValidate: { |
| 4066 type: Boolean, |
| 4067 value: false |
| 4068 }, |
| 4069 invalid: { |
| 4070 observer: '_invalidChanged', |
| 4071 type: Boolean, |
| 4072 value: false |
| 4073 }, |
| 4074 focused: { |
| 4075 readOnly: true, |
| 4076 type: Boolean, |
| 4077 value: false, |
| 4078 notify: true |
| 4079 }, |
| 4080 _addons: { |
| 4081 type: Array |
| 4082 }, |
| 4083 _inputHasContent: { |
| 4084 type: Boolean, |
| 4085 value: false |
| 4086 }, |
| 4087 _inputSelector: { |
| 4088 type: String, |
| 4089 value: 'input,textarea,.paper-input-input' |
| 4090 }, |
| 4091 _boundOnFocus: { |
| 4092 type: Function, |
| 4093 value: function() { |
| 4094 return this._onFocus.bind(this); |
| 4095 } |
| 4096 }, |
| 4097 _boundOnBlur: { |
| 4098 type: Function, |
| 4099 value: function() { |
| 4100 return this._onBlur.bind(this); |
| 4101 } |
| 4102 }, |
| 4103 _boundOnInput: { |
| 4104 type: Function, |
| 4105 value: function() { |
| 4106 return this._onInput.bind(this); |
| 4107 } |
| 4108 }, |
| 4109 _boundValueChanged: { |
| 4110 type: Function, |
| 4111 value: function() { |
| 4112 return this._onValueChanged.bind(this); |
| 4113 } |
| 4114 } |
| 4115 }, |
| 4116 listeners: { |
| 4117 'addon-attached': '_onAddonAttached', |
| 4118 'iron-input-validate': '_onIronInputValidate' |
| 4119 }, |
| 4120 get _valueChangedEvent() { |
| 4121 return this.attrForValue + '-changed'; |
| 4122 }, |
| 4123 get _propertyForValue() { |
| 4124 return Polymer.CaseMap.dashToCamelCase(this.attrForValue); |
| 4125 }, |
| 4126 get _inputElement() { |
| 4127 return Polymer.dom(this).querySelector(this._inputSelector); |
| 4128 }, |
| 4129 get _inputElementValue() { |
| 4130 return this._inputElement[this._propertyForValue] || this._inputElement.valu
e; |
| 4131 }, |
| 4132 ready: function() { |
| 4133 if (!this._addons) { |
| 4134 this._addons = []; |
| 4135 } |
| 4136 this.addEventListener('focus', this._boundOnFocus, true); |
| 4137 this.addEventListener('blur', this._boundOnBlur, true); |
| 4138 }, |
| 4139 attached: function() { |
| 4140 if (this.attrForValue) { |
| 4141 this._inputElement.addEventListener(this._valueChangedEvent, this._boundVa
lueChanged); |
| 4142 } else { |
| 4143 this.addEventListener('input', this._onInput); |
| 4144 } |
| 4145 if (this._inputElementValue != '') { |
| 4146 this._handleValueAndAutoValidate(this._inputElement); |
| 4147 } else { |
| 4148 this._handleValue(this._inputElement); |
| 4149 } |
| 4150 }, |
| 4151 _onAddonAttached: function(event) { |
| 4152 if (!this._addons) { |
| 4153 this._addons = []; |
| 4154 } |
| 4155 var target = event.target; |
| 4156 if (this._addons.indexOf(target) === -1) { |
| 4157 this._addons.push(target); |
| 4158 if (this.isAttached) { |
| 4159 this._handleValue(this._inputElement); |
| 4160 } |
| 4161 } |
| 4162 }, |
| 4163 _onFocus: function() { |
| 4164 this._setFocused(true); |
| 4165 }, |
| 4166 _onBlur: function() { |
| 4167 this._setFocused(false); |
| 4168 this._handleValueAndAutoValidate(this._inputElement); |
| 4169 }, |
| 4170 _onInput: function(event) { |
| 4171 this._handleValueAndAutoValidate(event.target); |
| 4172 }, |
| 4173 _onValueChanged: function(event) { |
| 4174 this._handleValueAndAutoValidate(event.target); |
| 4175 }, |
| 4176 _handleValue: function(inputElement) { |
| 4177 var value = this._inputElementValue; |
| 4178 if (value || value === 0 || inputElement.type === 'number' && !inputElement.
checkValidity()) { |
| 4179 this._inputHasContent = true; |
| 4180 } else { |
| 4181 this._inputHasContent = false; |
| 4182 } |
| 4183 this.updateAddons({ |
| 4184 inputElement: inputElement, |
| 4185 value: value, |
| 4186 invalid: this.invalid |
| 4187 }); |
| 4188 }, |
| 4189 _handleValueAndAutoValidate: function(inputElement) { |
| 4190 if (this.autoValidate) { |
| 4191 var valid; |
| 4192 if (inputElement.validate) { |
| 4193 valid = inputElement.validate(this._inputElementValue); |
| 4194 } else { |
| 4195 valid = inputElement.checkValidity(); |
| 4196 } |
| 4197 this.invalid = !valid; |
| 4198 } |
| 4199 this._handleValue(inputElement); |
| 4200 }, |
| 4201 _onIronInputValidate: function(event) { |
| 4202 this.invalid = this._inputElement.invalid; |
| 4203 }, |
| 4204 _invalidChanged: function() { |
| 4205 if (this._addons) { |
| 4206 this.updateAddons({ |
| 4207 invalid: this.invalid |
| 4208 }); |
| 4209 } |
| 4210 }, |
| 4211 updateAddons: function(state) { |
| 4212 for (var addon, index = 0; addon = this._addons[index]; index++) { |
| 4213 addon.update(state); |
| 4214 } |
| 4215 }, |
| 4216 _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, i
nvalid, _inputHasContent) { |
| 4217 var cls = 'input-content'; |
| 4218 if (!noLabelFloat) { |
| 4219 var label = this.querySelector('label'); |
| 4220 if (alwaysFloatLabel || _inputHasContent) { |
| 4221 cls += ' label-is-floating'; |
| 4222 this.$.labelAndInputContainer.style.position = 'static'; |
| 4223 if (invalid) { |
| 4224 cls += ' is-invalid'; |
| 4225 } else if (focused) { |
| 4226 cls += " label-is-highlighted"; |
| 4227 } |
| 4228 } else { |
| 4229 if (label) { |
| 4230 this.$.labelAndInputContainer.style.position = 'relative'; |
| 4231 } |
| 4232 } |
| 4233 } else { |
| 4234 if (_inputHasContent) { |
| 4235 cls += ' label-is-hidden'; |
| 4236 } |
| 4237 } |
| 4238 return cls; |
| 4239 }, |
| 4240 _computeUnderlineClass: function(focused, invalid) { |
| 4241 var cls = 'underline'; |
| 4242 if (invalid) { |
| 4243 cls += ' is-invalid'; |
| 4244 } else if (focused) { |
| 4245 cls += ' is-highlighted'; |
| 4246 } |
| 4247 return cls; |
| 4248 }, |
| 4249 _computeAddOnContentClass: function(focused, invalid) { |
| 4250 var cls = 'add-on-content'; |
| 4251 if (invalid) { |
| 4252 cls += ' is-invalid'; |
| 4253 } else if (focused) { |
| 4254 cls += ' is-highlighted'; |
| 4255 } |
| 4256 return cls; |
| 4257 } |
| 4258 }); |
| 4259 |
| 4260 Polymer.PaperSpinnerBehavior = { |
| 4261 listeners: { |
| 4262 animationend: '__reset', |
| 4263 webkitAnimationEnd: '__reset' |
| 4264 }, |
| 4265 properties: { |
| 4266 active: { |
| 4267 type: Boolean, |
| 4268 value: false, |
| 4269 reflectToAttribute: true, |
| 4270 observer: '__activeChanged' |
| 4271 }, |
| 4272 alt: { |
| 4273 type: String, |
| 4274 value: 'loading', |
| 4275 observer: '__altChanged' |
| 4276 }, |
| 4277 __coolingDown: { |
| 4278 type: Boolean, |
| 4279 value: false |
| 4280 } |
| 4281 }, |
| 4282 __computeContainerClasses: function(active, coolingDown) { |
| 4283 return [ active || coolingDown ? 'active' : '', coolingDown ? 'cooldown' : '
' ].join(' '); |
| 4284 }, |
| 4285 __activeChanged: function(active, old) { |
| 4286 this.__setAriaHidden(!active); |
| 4287 this.__coolingDown = !active && old; |
| 4288 }, |
| 4289 __altChanged: function(alt) { |
| 4290 if (alt === this.getPropertyInfo('alt').value) { |
| 4291 this.alt = this.getAttribute('aria-label') || alt; |
| 4292 } else { |
| 4293 this.__setAriaHidden(alt === ''); |
| 4294 this.setAttribute('aria-label', alt); |
| 4295 } |
| 4296 }, |
| 4297 __setAriaHidden: function(hidden) { |
| 4298 var attr = 'aria-hidden'; |
| 4299 if (hidden) { |
| 4300 this.setAttribute(attr, 'true'); |
| 4301 } else { |
| 4302 this.removeAttribute(attr); |
| 4303 } |
| 4304 }, |
| 4305 __reset: function() { |
| 4306 this.active = false; |
| 4307 this.__coolingDown = false; |
| 4308 } |
| 4309 }; |
| 4310 |
| 4311 Polymer({ |
| 4312 is: 'paper-spinner-lite', |
| 4313 behaviors: [ Polymer.PaperSpinnerBehavior ] |
| 4314 }); |
| 4315 |
| 4316 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 4317 // Use of this source code is governed by a BSD-style license that can be |
| 4318 // found in the LICENSE file. |
| 4319 var CrSearchFieldBehavior = { |
| 4320 properties: { |
| 4321 label: { |
| 4322 type: String, |
| 4323 value: '' |
| 4324 }, |
| 4325 clearLabel: { |
| 4326 type: String, |
| 4327 value: '' |
| 4328 }, |
| 4329 showingSearch: { |
| 4330 type: Boolean, |
| 4331 value: false, |
| 4332 notify: true, |
| 4333 observer: 'showingSearchChanged_', |
| 4334 reflectToAttribute: true |
| 4335 }, |
| 4336 lastValue_: { |
| 4337 type: String, |
| 4338 value: '' |
| 4339 } |
| 4340 }, |
| 4341 getSearchInput: function() {}, |
| 4342 getValue: function() { |
| 4343 return this.getSearchInput().value; |
| 4344 }, |
| 4345 setValue: function(value) { |
| 4346 this.getSearchInput().bindValue = value; |
| 4347 this.onValueChanged_(value); |
| 4348 }, |
| 4349 showAndFocus: function() { |
| 4350 this.showingSearch = true; |
| 4351 this.focus_(); |
| 4352 }, |
| 4353 focus_: function() { |
| 4354 this.getSearchInput().focus(); |
| 4355 }, |
| 4356 onSearchTermSearch: function() { |
| 4357 this.onValueChanged_(this.getValue()); |
| 4358 }, |
| 4359 onValueChanged_: function(newValue) { |
| 4360 if (newValue == this.lastValue_) return; |
| 4361 this.fire('search-changed', newValue); |
| 4362 this.lastValue_ = newValue; |
| 4363 }, |
| 4364 onSearchTermKeydown: function(e) { |
| 4365 if (e.key == 'Escape') this.showingSearch = false; |
| 4366 }, |
| 4367 showingSearchChanged_: function() { |
| 4368 if (this.showingSearch) { |
| 4369 this.focus_(); |
| 4370 return; |
| 4371 } |
| 4372 this.setValue(''); |
| 4373 this.getSearchInput().blur(); |
| 4374 } |
| 4375 }; |
| 4376 |
| 4377 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 4378 // Use of this source code is governed by a BSD-style license that can be |
| 4379 // found in the LICENSE file. |
| 4380 Polymer({ |
| 4381 is: 'cr-toolbar-search-field', |
| 4382 behaviors: [ CrSearchFieldBehavior ], |
| 4383 properties: { |
| 4384 narrow: { |
| 4385 type: Boolean, |
| 4386 reflectToAttribute: true |
| 4387 }, |
| 4388 label: String, |
| 4389 clearLabel: String, |
| 4390 spinnerActive: { |
| 4391 type: Boolean, |
| 4392 reflectToAttribute: true |
| 4393 }, |
| 4394 hasSearchText_: Boolean |
| 4395 }, |
| 4396 listeners: { |
| 4397 tap: 'showSearch_', |
| 4398 'searchInput.bind-value-changed': 'onBindValueChanged_' |
| 4399 }, |
| 4400 getSearchInput: function() { |
| 4401 return this.$.searchInput; |
| 4402 }, |
| 4403 isSearchFocused: function() { |
| 4404 return this.$.searchTerm.focused; |
| 4405 }, |
| 4406 computeIconTabIndex_: function(narrow) { |
| 4407 return narrow ? 0 : -1; |
| 4408 }, |
| 4409 isSpinnerShown_: function(spinnerActive, showingSearch) { |
| 4410 return spinnerActive && showingSearch; |
| 4411 }, |
| 4412 onInputBlur_: function() { |
| 4413 if (!this.hasSearchText_) this.showingSearch = false; |
| 4414 }, |
| 4415 onBindValueChanged_: function() { |
| 4416 var newValue = this.$.searchInput.bindValue; |
| 4417 this.hasSearchText_ = newValue != ''; |
| 4418 if (newValue != '') this.showingSearch = true; |
| 4419 }, |
| 4420 showSearch_: function(e) { |
| 4421 if (e.target != this.$.clearSearch) this.showingSearch = true; |
| 4422 }, |
| 4423 hideSearch_: function(e) { |
| 4424 this.showingSearch = false; |
| 4425 e.stopPropagation(); |
| 4426 } |
| 4427 }); |
| 4428 |
| 4429 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 4430 // Use of this source code is governed by a BSD-style license that can be |
| 4431 // found in the LICENSE file. |
| 4432 Polymer({ |
| 4433 is: 'cr-toolbar', |
| 4434 properties: { |
| 4435 pageName: String, |
| 4436 searchPrompt: String, |
| 4437 clearLabel: String, |
| 4438 spinnerActive: Boolean, |
| 4439 showMenu: { |
| 4440 type: Boolean, |
| 4441 reflectToAttribute: true, |
| 4442 value: true |
| 4443 }, |
| 4444 narrow_: { |
| 4445 type: Boolean, |
| 4446 reflectToAttribute: true |
| 4447 }, |
| 4448 showingSearch_: { |
| 4449 type: Boolean, |
| 4450 reflectToAttribute: true |
| 4451 } |
| 4452 }, |
| 4453 getSearchField: function() { |
| 4454 return this.$.search; |
| 4455 }, |
| 4456 onMenuTap_: function(e) { |
| 4457 this.fire('cr-menu-tap'); |
| 4458 } |
| 4459 }); |
| 4460 |
| 4461 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 4462 // Use of this source code is governed by a BSD-style license that can be |
| 4463 // found in the LICENSE file. |
| 4464 Polymer({ |
| 4465 is: 'history-toolbar', |
| 4466 properties: { |
| 4467 count: { |
| 4468 type: Number, |
| 4469 value: 0, |
| 4470 observer: 'changeToolbarView_' |
| 4471 }, |
| 4472 itemsSelected_: { |
| 4473 type: Boolean, |
| 4474 value: false, |
| 4475 reflectToAttribute: true |
| 4476 }, |
| 4477 searchTerm: { |
| 4478 type: String, |
| 4479 notify: true |
| 4480 }, |
| 4481 spinnerActive: { |
| 4482 type: Boolean, |
| 4483 value: false |
| 4484 }, |
| 4485 hasDrawer: { |
| 4486 type: Boolean, |
| 4487 observer: 'hasDrawerChanged_', |
| 4488 reflectToAttribute: true |
| 4489 }, |
| 4490 isGroupedMode: { |
| 4491 type: Boolean, |
| 4492 reflectToAttribute: true |
| 4493 }, |
| 4494 groupedRange: { |
| 4495 type: Number, |
| 4496 value: 0, |
| 4497 reflectToAttribute: true, |
| 4498 notify: true |
| 4499 }, |
| 4500 queryStartTime: String, |
| 4501 queryEndTime: String |
| 4502 }, |
| 4503 changeToolbarView_: function() { |
| 4504 this.itemsSelected_ = this.count > 0; |
| 4505 }, |
| 4506 setSearchTerm: function(search) { |
| 4507 if (this.searchTerm == search) return; |
| 4508 this.searchTerm = search; |
| 4509 var searchField = this.$['main-toolbar'].getSearchField(); |
| 4510 searchField.showAndFocus(); |
| 4511 searchField.setValue(search); |
| 4512 }, |
| 4513 onSearchChanged_: function(event) { |
| 4514 this.searchTerm = event.detail; |
| 4515 }, |
| 4516 onClearSelectionTap_: function() { |
| 4517 this.fire('unselect-all'); |
| 4518 }, |
| 4519 onDeleteTap_: function() { |
| 4520 this.fire('delete-selected'); |
| 4521 }, |
| 4522 get searchBar() { |
| 4523 return this.$['main-toolbar'].getSearchField(); |
| 4524 }, |
| 4525 showSearchField: function() { |
| 4526 this.$['main-toolbar'].getSearchField().showAndFocus(); |
| 4527 }, |
| 4528 deletingAllowed_: function() { |
| 4529 return loadTimeData.getBoolean('allowDeletingHistory'); |
| 4530 }, |
| 4531 numberOfItemsSelected_: function(count) { |
| 4532 return count > 0 ? loadTimeData.getStringF('itemsSelected', count) : ''; |
| 4533 }, |
| 4534 getHistoryInterval_: function(queryStartTime, queryEndTime) { |
| 4535 return loadTimeData.getStringF('historyInterval', queryStartTime, queryEndTi
me); |
| 4536 }, |
| 4537 hasDrawerChanged_: function() { |
| 4538 this.updateStyles(); |
| 4539 } |
| 4540 }); |
| 4541 |
| 4542 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 4543 // Use of this source code is governed by a BSD-style license that can be |
| 4544 // found in the LICENSE file. |
| 4545 Polymer({ |
| 4546 is: 'cr-dialog', |
| 4547 "extends": 'dialog', |
| 4548 cancel: function() { |
| 4549 this.fire('cancel'); |
| 4550 HTMLDialogElement.prototype.close.call(this, ''); |
| 4551 }, |
| 4552 close: function(opt_returnValue) { |
| 4553 HTMLDialogElement.prototype.close.call(this, 'success'); |
| 4554 }, |
| 4555 getCloseButton: function() { |
| 4556 return this.$.close; |
| 4557 } |
| 4558 }); |
| 4559 |
| 4560 Polymer.IronFitBehavior = { |
| 4561 properties: { |
| 4562 sizingTarget: { |
| 4563 type: Object, |
| 4564 value: function() { |
| 4565 return this; |
| 4566 } |
| 4567 }, |
| 4568 fitInto: { |
| 4569 type: Object, |
| 4570 value: window |
| 4571 }, |
| 4572 noOverlap: { |
| 4573 type: Boolean |
| 4574 }, |
| 4575 positionTarget: { |
| 4576 type: Element |
| 4577 }, |
| 4578 horizontalAlign: { |
| 4579 type: String |
| 4580 }, |
| 4581 verticalAlign: { |
| 4582 type: String |
| 4583 }, |
| 4584 dynamicAlign: { |
| 4585 type: Boolean |
| 4586 }, |
| 4587 horizontalOffset: { |
| 4588 type: Number, |
| 4589 value: 0, |
| 4590 notify: true |
| 4591 }, |
| 4592 verticalOffset: { |
| 4593 type: Number, |
| 4594 value: 0, |
| 4595 notify: true |
| 4596 }, |
| 4597 autoFitOnAttach: { |
| 4598 type: Boolean, |
| 4599 value: false |
| 4600 }, |
| 4601 _fitInfo: { |
| 4602 type: Object |
| 4603 } |
| 4604 }, |
| 4605 get _fitWidth() { |
| 4606 var fitWidth; |
| 4607 if (this.fitInto === window) { |
| 4608 fitWidth = this.fitInto.innerWidth; |
| 4609 } else { |
| 4610 fitWidth = this.fitInto.getBoundingClientRect().width; |
| 4611 } |
| 4612 return fitWidth; |
| 4613 }, |
| 4614 get _fitHeight() { |
| 4615 var fitHeight; |
| 4616 if (this.fitInto === window) { |
| 4617 fitHeight = this.fitInto.innerHeight; |
| 4618 } else { |
| 4619 fitHeight = this.fitInto.getBoundingClientRect().height; |
| 4620 } |
| 4621 return fitHeight; |
| 4622 }, |
| 4623 get _fitLeft() { |
| 4624 var fitLeft; |
| 4625 if (this.fitInto === window) { |
| 4626 fitLeft = 0; |
| 4627 } else { |
| 4628 fitLeft = this.fitInto.getBoundingClientRect().left; |
| 4629 } |
| 4630 return fitLeft; |
| 4631 }, |
| 4632 get _fitTop() { |
| 4633 var fitTop; |
| 4634 if (this.fitInto === window) { |
| 4635 fitTop = 0; |
| 4636 } else { |
| 4637 fitTop = this.fitInto.getBoundingClientRect().top; |
| 4638 } |
| 4639 return fitTop; |
| 4640 }, |
| 4641 get _defaultPositionTarget() { |
| 4642 var parent = Polymer.dom(this).parentNode; |
| 4643 if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { |
| 4644 parent = parent.host; |
| 4645 } |
| 4646 return parent; |
| 4647 }, |
| 4648 get _localeHorizontalAlign() { |
| 4649 if (this._isRTL) { |
| 4650 if (this.horizontalAlign === 'right') { |
| 4651 return 'left'; |
| 4652 } |
| 4653 if (this.horizontalAlign === 'left') { |
| 4654 return 'right'; |
| 4655 } |
| 4656 } |
| 4657 return this.horizontalAlign; |
| 4658 }, |
| 4659 attached: function() { |
| 4660 this._isRTL = window.getComputedStyle(this).direction == 'rtl'; |
| 4661 this.positionTarget = this.positionTarget || this._defaultPositionTarget; |
| 4662 if (this.autoFitOnAttach) { |
| 4663 if (window.getComputedStyle(this).display === 'none') { |
| 4664 setTimeout(function() { |
| 4665 this.fit(); |
| 4666 }.bind(this)); |
| 4667 } else { |
| 4668 this.fit(); |
| 4669 } |
| 4670 } |
| 4671 }, |
| 4672 fit: function() { |
| 4673 this.position(); |
| 4674 this.constrain(); |
| 4675 this.center(); |
| 4676 }, |
| 4677 _discoverInfo: function() { |
| 4678 if (this._fitInfo) { |
| 4679 return; |
| 4680 } |
| 4681 var target = window.getComputedStyle(this); |
| 4682 var sizer = window.getComputedStyle(this.sizingTarget); |
| 4683 this._fitInfo = { |
| 4684 inlineStyle: { |
| 4685 top: this.style.top || '', |
| 4686 left: this.style.left || '', |
| 4687 position: this.style.position || '' |
| 4688 }, |
| 4689 sizerInlineStyle: { |
| 4690 maxWidth: this.sizingTarget.style.maxWidth || '', |
| 4691 maxHeight: this.sizingTarget.style.maxHeight || '', |
| 4692 boxSizing: this.sizingTarget.style.boxSizing || '' |
| 4693 }, |
| 4694 positionedBy: { |
| 4695 vertically: target.top !== 'auto' ? 'top' : target.bottom !== 'auto' ? '
bottom' : null, |
| 4696 horizontally: target.left !== 'auto' ? 'left' : target.right !== 'auto'
? 'right' : null |
| 4697 }, |
| 4698 sizedBy: { |
| 4699 height: sizer.maxHeight !== 'none', |
| 4700 width: sizer.maxWidth !== 'none', |
| 4701 minWidth: parseInt(sizer.minWidth, 10) || 0, |
| 4702 minHeight: parseInt(sizer.minHeight, 10) || 0 |
| 4703 }, |
| 4704 margin: { |
| 4705 top: parseInt(target.marginTop, 10) || 0, |
| 4706 right: parseInt(target.marginRight, 10) || 0, |
| 4707 bottom: parseInt(target.marginBottom, 10) || 0, |
| 4708 left: parseInt(target.marginLeft, 10) || 0 |
| 4709 } |
| 4710 }; |
| 4711 if (this.verticalOffset) { |
| 4712 this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffs
et; |
| 4713 this._fitInfo.inlineStyle.marginTop = this.style.marginTop || ''; |
| 4714 this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || ''; |
| 4715 this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px
'; |
| 4716 } |
| 4717 if (this.horizontalOffset) { |
| 4718 this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOf
fset; |
| 4719 this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || ''; |
| 4720 this._fitInfo.inlineStyle.marginRight = this.style.marginRight || ''; |
| 4721 this.style.marginLeft = this.style.marginRight = this.horizontalOffset + '
px'; |
| 4722 } |
| 4723 }, |
| 4724 resetFit: function() { |
| 4725 var info = this._fitInfo || {}; |
| 4726 for (var property in info.sizerInlineStyle) { |
| 4727 this.sizingTarget.style[property] = info.sizerInlineStyle[property]; |
| 4728 } |
| 4729 for (var property in info.inlineStyle) { |
| 4730 this.style[property] = info.inlineStyle[property]; |
| 4731 } |
| 4732 this._fitInfo = null; |
| 4733 }, |
| 4734 refit: function() { |
| 4735 var scrollLeft = this.sizingTarget.scrollLeft; |
| 4736 var scrollTop = this.sizingTarget.scrollTop; |
| 4737 this.resetFit(); |
| 4738 this.fit(); |
| 4739 this.sizingTarget.scrollLeft = scrollLeft; |
| 4740 this.sizingTarget.scrollTop = scrollTop; |
| 4741 }, |
| 4742 position: function() { |
| 4743 if (!this.horizontalAlign && !this.verticalAlign) { |
| 4744 return; |
| 4745 } |
| 4746 this._discoverInfo(); |
| 4747 this.style.position = 'fixed'; |
| 4748 this.sizingTarget.style.boxSizing = 'border-box'; |
| 4749 this.style.left = '0px'; |
| 4750 this.style.top = '0px'; |
| 4751 var rect = this.getBoundingClientRect(); |
| 4752 var positionRect = this.__getNormalizedRect(this.positionTarget); |
| 4753 var fitRect = this.__getNormalizedRect(this.fitInto); |
| 4754 var margin = this._fitInfo.margin; |
| 4755 var size = { |
| 4756 width: rect.width + margin.left + margin.right, |
| 4757 height: rect.height + margin.top + margin.bottom |
| 4758 }; |
| 4759 var position = this.__getPosition(this._localeHorizontalAlign, this.vertical
Align, size, positionRect, fitRect); |
| 4760 var left = position.left + margin.left; |
| 4761 var top = position.top + margin.top; |
| 4762 var right = Math.min(fitRect.right - margin.right, left + rect.width); |
| 4763 var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height); |
| 4764 var minWidth = this._fitInfo.sizedBy.minWidth; |
| 4765 var minHeight = this._fitInfo.sizedBy.minHeight; |
| 4766 if (left < margin.left) { |
| 4767 left = margin.left; |
| 4768 if (right - left < minWidth) { |
| 4769 left = right - minWidth; |
| 4770 } |
| 4771 } |
| 4772 if (top < margin.top) { |
| 4773 top = margin.top; |
| 4774 if (bottom - top < minHeight) { |
| 4775 top = bottom - minHeight; |
| 4776 } |
| 4777 } |
| 4778 this.sizingTarget.style.maxWidth = right - left + 'px'; |
| 4779 this.sizingTarget.style.maxHeight = bottom - top + 'px'; |
| 4780 this.style.left = left - rect.left + 'px'; |
| 4781 this.style.top = top - rect.top + 'px'; |
| 4782 }, |
| 4783 constrain: function() { |
| 4784 if (this.horizontalAlign || this.verticalAlign) { |
| 4785 return; |
| 4786 } |
| 4787 this._discoverInfo(); |
| 4788 var info = this._fitInfo; |
| 4789 if (!info.positionedBy.vertically) { |
| 4790 this.style.position = 'fixed'; |
| 4791 this.style.top = '0px'; |
| 4792 } |
| 4793 if (!info.positionedBy.horizontally) { |
| 4794 this.style.position = 'fixed'; |
| 4795 this.style.left = '0px'; |
| 4796 } |
| 4797 this.sizingTarget.style.boxSizing = 'border-box'; |
| 4798 var rect = this.getBoundingClientRect(); |
| 4799 if (!info.sizedBy.height) { |
| 4800 this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom',
'Height'); |
| 4801 } |
| 4802 if (!info.sizedBy.width) { |
| 4803 this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right'
, 'Width'); |
| 4804 } |
| 4805 }, |
| 4806 _sizeDimension: function(rect, positionedBy, start, end, extent) { |
| 4807 this.__sizeDimension(rect, positionedBy, start, end, extent); |
| 4808 }, |
| 4809 __sizeDimension: function(rect, positionedBy, start, end, extent) { |
| 4810 var info = this._fitInfo; |
| 4811 var fitRect = this.__getNormalizedRect(this.fitInto); |
| 4812 var max = extent === 'Width' ? fitRect.width : fitRect.height; |
| 4813 var flip = positionedBy === end; |
| 4814 var offset = flip ? max - rect[end] : rect[start]; |
| 4815 var margin = info.margin[flip ? start : end]; |
| 4816 var offsetExtent = 'offset' + extent; |
| 4817 var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent]; |
| 4818 this.sizingTarget.style['max' + extent] = max - margin - offset - sizingOffs
et + 'px'; |
| 4819 }, |
| 4820 center: function() { |
| 4821 if (this.horizontalAlign || this.verticalAlign) { |
| 4822 return; |
| 4823 } |
| 4824 this._discoverInfo(); |
| 4825 var positionedBy = this._fitInfo.positionedBy; |
| 4826 if (positionedBy.vertically && positionedBy.horizontally) { |
| 4827 return; |
| 4828 } |
| 4829 this.style.position = 'fixed'; |
| 4830 if (!positionedBy.vertically) { |
| 4831 this.style.top = '0px'; |
| 4832 } |
| 4833 if (!positionedBy.horizontally) { |
| 4834 this.style.left = '0px'; |
| 4835 } |
| 4836 var rect = this.getBoundingClientRect(); |
| 4837 var fitRect = this.__getNormalizedRect(this.fitInto); |
| 4838 if (!positionedBy.vertically) { |
| 4839 var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2; |
| 4840 this.style.top = top + 'px'; |
| 4841 } |
| 4842 if (!positionedBy.horizontally) { |
| 4843 var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2; |
| 4844 this.style.left = left + 'px'; |
| 4845 } |
| 4846 }, |
| 4847 __getNormalizedRect: function(target) { |
| 4848 if (target === document.documentElement || target === window) { |
| 4849 return { |
| 4850 top: 0, |
| 4851 left: 0, |
| 4852 width: window.innerWidth, |
| 4853 height: window.innerHeight, |
| 4854 right: window.innerWidth, |
| 4855 bottom: window.innerHeight |
| 4856 }; |
| 4857 } |
| 4858 return target.getBoundingClientRect(); |
| 4859 }, |
| 4860 __getCroppedArea: function(position, size, fitRect) { |
| 4861 var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom -
(position.top + size.height)); |
| 4862 var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right
- (position.left + size.width)); |
| 4863 return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size
.height; |
| 4864 }, |
| 4865 __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) { |
| 4866 var positions = [ { |
| 4867 verticalAlign: 'top', |
| 4868 horizontalAlign: 'left', |
| 4869 top: positionRect.top, |
| 4870 left: positionRect.left |
| 4871 }, { |
| 4872 verticalAlign: 'top', |
| 4873 horizontalAlign: 'right', |
| 4874 top: positionRect.top, |
| 4875 left: positionRect.right - size.width |
| 4876 }, { |
| 4877 verticalAlign: 'bottom', |
| 4878 horizontalAlign: 'left', |
| 4879 top: positionRect.bottom - size.height, |
| 4880 left: positionRect.left |
| 4881 }, { |
| 4882 verticalAlign: 'bottom', |
| 4883 horizontalAlign: 'right', |
| 4884 top: positionRect.bottom - size.height, |
| 4885 left: positionRect.right - size.width |
| 4886 } ]; |
| 4887 if (this.noOverlap) { |
| 4888 for (var i = 0, l = positions.length; i < l; i++) { |
| 4889 var copy = {}; |
| 4890 for (var key in positions[i]) { |
| 4891 copy[key] = positions[i][key]; |
| 4892 } |
| 4893 positions.push(copy); |
| 4894 } |
| 4895 positions[0].top = positions[1].top += positionRect.height; |
| 4896 positions[2].top = positions[3].top -= positionRect.height; |
| 4897 positions[4].left = positions[6].left += positionRect.width; |
| 4898 positions[5].left = positions[7].left -= positionRect.width; |
| 4899 } |
| 4900 vAlign = vAlign === 'auto' ? null : vAlign; |
| 4901 hAlign = hAlign === 'auto' ? null : hAlign; |
| 4902 var position; |
| 4903 for (var i = 0; i < positions.length; i++) { |
| 4904 var pos = positions[i]; |
| 4905 if (!this.dynamicAlign && !this.noOverlap && pos.verticalAlign === vAlign
&& pos.horizontalAlign === hAlign) { |
| 4906 position = pos; |
| 4907 break; |
| 4908 } |
| 4909 var alignOk = (!vAlign || pos.verticalAlign === vAlign) && (!hAlign || pos
.horizontalAlign === hAlign); |
| 4910 if (!this.dynamicAlign && !alignOk) { |
| 4911 continue; |
| 4912 } |
| 4913 position = position || pos; |
| 4914 pos.croppedArea = this.__getCroppedArea(pos, size, fitRect); |
| 4915 var diff = pos.croppedArea - position.croppedArea; |
| 4916 if (diff < 0 || diff === 0 && alignOk) { |
| 4917 position = pos; |
| 4918 } |
| 4919 if (position.croppedArea === 0 && alignOk) { |
| 4920 break; |
| 4921 } |
| 4922 } |
| 4923 return position; |
| 4924 } |
| 4925 }; |
| 4926 |
| 4927 (function() { |
| 4928 'use strict'; |
| 4929 Polymer({ |
| 4930 is: 'iron-overlay-backdrop', |
| 4931 properties: { |
| 4932 opened: { |
| 4933 reflectToAttribute: true, |
| 4934 type: Boolean, |
| 4935 value: false, |
| 4936 observer: '_openedChanged' |
| 4937 } |
| 4938 }, |
| 4939 listeners: { |
| 4940 transitionend: '_onTransitionend' |
| 4941 }, |
| 4942 created: function() { |
| 4943 this.__openedRaf = null; |
| 4944 }, |
| 4945 attached: function() { |
| 4946 this.opened && this._openedChanged(this.opened); |
| 4947 }, |
| 4948 prepare: function() { |
| 4949 if (this.opened && !this.parentNode) { |
| 4950 Polymer.dom(document.body).appendChild(this); |
| 4951 } |
| 4952 }, |
| 4953 open: function() { |
| 4954 this.opened = true; |
| 4955 }, |
| 4956 close: function() { |
| 4957 this.opened = false; |
| 4958 }, |
| 4959 complete: function() { |
| 4960 if (!this.opened && this.parentNode === document.body) { |
| 4961 Polymer.dom(this.parentNode).removeChild(this); |
| 4962 } |
| 4963 }, |
| 4964 _onTransitionend: function(event) { |
| 4965 if (event && event.target === this) { |
| 4966 this.complete(); |
| 4967 } |
| 4968 }, |
| 4969 _openedChanged: function(opened) { |
| 4970 if (opened) { |
| 4971 this.prepare(); |
| 4972 } else { |
| 4973 var cs = window.getComputedStyle(this); |
| 4974 if (cs.transitionDuration === '0s' || cs.opacity == 0) { |
| 4975 this.complete(); |
| 4976 } |
| 4977 } |
| 4978 if (!this.isAttached) { |
| 4979 return; |
| 4980 } |
| 4981 if (this.__openedRaf) { |
| 4982 window.cancelAnimationFrame(this.__openedRaf); |
| 4983 this.__openedRaf = null; |
| 4984 } |
| 4985 this.scrollTop = this.scrollTop; |
| 4986 this.__openedRaf = window.requestAnimationFrame(function() { |
| 4987 this.__openedRaf = null; |
| 4988 this.toggleClass('opened', this.opened); |
| 4989 }.bind(this)); |
| 4990 } |
| 4991 }); |
| 4992 })(); |
| 4993 |
| 4994 Polymer.IronOverlayManagerClass = function() { |
| 4995 this._overlays = []; |
| 4996 this._minimumZ = 101; |
| 4997 this._backdropElement = null; |
| 4998 Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this)); |
| 4999 document.addEventListener('focus', this._onCaptureFocus.bind(this), true); |
| 5000 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true); |
| 5001 }; |
| 5002 |
| 5003 Polymer.IronOverlayManagerClass.prototype = { |
| 5004 constructor: Polymer.IronOverlayManagerClass, |
| 5005 get backdropElement() { |
| 5006 if (!this._backdropElement) { |
| 5007 this._backdropElement = document.createElement('iron-overlay-backdrop'); |
| 5008 } |
| 5009 return this._backdropElement; |
| 5010 }, |
| 5011 get deepActiveElement() { |
| 5012 var active = document.activeElement || document.body; |
| 5013 while (active.root && Polymer.dom(active.root).activeElement) { |
| 5014 active = Polymer.dom(active.root).activeElement; |
| 5015 } |
| 5016 return active; |
| 5017 }, |
| 5018 _bringOverlayAtIndexToFront: function(i) { |
| 5019 var overlay = this._overlays[i]; |
| 5020 if (!overlay) { |
| 5021 return; |
| 5022 } |
| 5023 var lastI = this._overlays.length - 1; |
| 5024 var currentOverlay = this._overlays[lastI]; |
| 5025 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay))
{ |
| 5026 lastI--; |
| 5027 } |
| 5028 if (i >= lastI) { |
| 5029 return; |
| 5030 } |
| 5031 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ); |
| 5032 if (this._getZ(overlay) <= minimumZ) { |
| 5033 this._applyOverlayZ(overlay, minimumZ); |
| 5034 } |
| 5035 while (i < lastI) { |
| 5036 this._overlays[i] = this._overlays[i + 1]; |
| 5037 i++; |
| 5038 } |
| 5039 this._overlays[lastI] = overlay; |
| 5040 }, |
| 5041 addOrRemoveOverlay: function(overlay) { |
| 5042 if (overlay.opened) { |
| 5043 this.addOverlay(overlay); |
| 5044 } else { |
| 5045 this.removeOverlay(overlay); |
| 5046 } |
| 5047 }, |
| 5048 addOverlay: function(overlay) { |
| 5049 var i = this._overlays.indexOf(overlay); |
| 5050 if (i >= 0) { |
| 5051 this._bringOverlayAtIndexToFront(i); |
| 5052 this.trackBackdrop(); |
| 5053 return; |
| 5054 } |
| 5055 var insertionIndex = this._overlays.length; |
| 5056 var currentOverlay = this._overlays[insertionIndex - 1]; |
| 5057 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); |
| 5058 var newZ = this._getZ(overlay); |
| 5059 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay))
{ |
| 5060 this._applyOverlayZ(currentOverlay, minimumZ); |
| 5061 insertionIndex--; |
| 5062 var previousOverlay = this._overlays[insertionIndex - 1]; |
| 5063 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); |
| 5064 } |
| 5065 if (newZ <= minimumZ) { |
| 5066 this._applyOverlayZ(overlay, minimumZ); |
| 5067 } |
| 5068 this._overlays.splice(insertionIndex, 0, overlay); |
| 5069 this.trackBackdrop(); |
| 5070 }, |
| 5071 removeOverlay: function(overlay) { |
| 5072 var i = this._overlays.indexOf(overlay); |
| 5073 if (i === -1) { |
| 5074 return; |
| 5075 } |
| 5076 this._overlays.splice(i, 1); |
| 5077 this.trackBackdrop(); |
| 5078 }, |
| 5079 currentOverlay: function() { |
| 5080 var i = this._overlays.length - 1; |
| 5081 return this._overlays[i]; |
| 5082 }, |
| 5083 currentOverlayZ: function() { |
| 5084 return this._getZ(this.currentOverlay()); |
| 5085 }, |
| 5086 ensureMinimumZ: function(minimumZ) { |
| 5087 this._minimumZ = Math.max(this._minimumZ, minimumZ); |
| 5088 }, |
| 5089 focusOverlay: function() { |
| 5090 var current = this.currentOverlay(); |
| 5091 if (current) { |
| 5092 current._applyFocus(); |
| 5093 } |
| 5094 }, |
| 5095 trackBackdrop: function() { |
| 5096 var overlay = this._overlayWithBackdrop(); |
| 5097 if (!overlay && !this._backdropElement) { |
| 5098 return; |
| 5099 } |
| 5100 this.backdropElement.style.zIndex = this._getZ(overlay) - 1; |
| 5101 this.backdropElement.opened = !!overlay; |
| 5102 }, |
| 5103 getBackdrops: function() { |
| 5104 var backdrops = []; |
| 5105 for (var i = 0; i < this._overlays.length; i++) { |
| 5106 if (this._overlays[i].withBackdrop) { |
| 5107 backdrops.push(this._overlays[i]); |
| 5108 } |
| 5109 } |
| 5110 return backdrops; |
| 5111 }, |
| 5112 backdropZ: function() { |
| 5113 return this._getZ(this._overlayWithBackdrop()) - 1; |
| 5114 }, |
| 5115 _overlayWithBackdrop: function() { |
| 5116 for (var i = 0; i < this._overlays.length; i++) { |
| 5117 if (this._overlays[i].withBackdrop) { |
| 5118 return this._overlays[i]; |
| 5119 } |
| 5120 } |
| 5121 }, |
| 5122 _getZ: function(overlay) { |
| 5123 var z = this._minimumZ; |
| 5124 if (overlay) { |
| 5125 var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).z
Index); |
| 5126 if (z1 === z1) { |
| 5127 z = z1; |
| 5128 } |
| 5129 } |
| 5130 return z; |
| 5131 }, |
| 5132 _setZ: function(element, z) { |
| 5133 element.style.zIndex = z; |
| 5134 }, |
| 5135 _applyOverlayZ: function(overlay, aboveZ) { |
| 5136 this._setZ(overlay, aboveZ + 2); |
| 5137 }, |
| 5138 _overlayInPath: function(path) { |
| 5139 path = path || []; |
| 5140 for (var i = 0; i < path.length; i++) { |
| 5141 if (path[i]._manager === this) { |
| 5142 return path[i]; |
| 5143 } |
| 5144 } |
| 5145 }, |
| 5146 _onCaptureClick: function(event) { |
| 5147 var overlay = this.currentOverlay(); |
| 5148 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) { |
| 5149 overlay._onCaptureClick(event); |
| 5150 } |
| 5151 }, |
| 5152 _onCaptureFocus: function(event) { |
| 5153 var overlay = this.currentOverlay(); |
| 5154 if (overlay) { |
| 5155 overlay._onCaptureFocus(event); |
| 5156 } |
| 5157 }, |
| 5158 _onCaptureKeyDown: function(event) { |
| 5159 var overlay = this.currentOverlay(); |
| 5160 if (overlay) { |
| 5161 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) { |
| 5162 overlay._onCaptureEsc(event); |
| 5163 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 't
ab')) { |
| 5164 overlay._onCaptureTab(event); |
| 5165 } |
| 5166 } |
| 5167 }, |
| 5168 _shouldBeBehindOverlay: function(overlay1, overlay2) { |
| 5169 return !overlay1.alwaysOnTop && overlay2.alwaysOnTop; |
| 5170 } |
| 5171 }; |
| 5172 |
| 5173 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); |
| 5174 |
| 5175 (function() { |
| 5176 'use strict'; |
| 5177 Polymer.IronOverlayBehaviorImpl = { |
| 5178 properties: { |
| 5179 opened: { |
| 5180 observer: '_openedChanged', |
| 5181 type: Boolean, |
| 5182 value: false, |
| 5183 notify: true |
| 5184 }, |
| 5185 canceled: { |
| 5186 observer: '_canceledChanged', |
| 5187 readOnly: true, |
| 5188 type: Boolean, |
| 5189 value: false |
| 5190 }, |
| 5191 withBackdrop: { |
| 5192 observer: '_withBackdropChanged', |
| 5193 type: Boolean |
| 5194 }, |
| 5195 noAutoFocus: { |
| 5196 type: Boolean, |
| 5197 value: false |
| 5198 }, |
| 5199 noCancelOnEscKey: { |
| 5200 type: Boolean, |
| 5201 value: false |
| 5202 }, |
| 5203 noCancelOnOutsideClick: { |
| 5204 type: Boolean, |
| 5205 value: false |
| 5206 }, |
| 5207 closingReason: { |
| 5208 type: Object |
| 5209 }, |
| 5210 restoreFocusOnClose: { |
| 5211 type: Boolean, |
| 5212 value: false |
| 5213 }, |
| 5214 alwaysOnTop: { |
| 5215 type: Boolean |
| 5216 }, |
| 5217 _manager: { |
| 5218 type: Object, |
| 5219 value: Polymer.IronOverlayManager |
| 5220 }, |
| 5221 _focusedChild: { |
| 5222 type: Object |
| 5223 } |
| 5224 }, |
| 5225 listeners: { |
| 5226 'iron-resize': '_onIronResize' |
| 5227 }, |
| 5228 get backdropElement() { |
| 5229 return this._manager.backdropElement; |
| 5230 }, |
| 5231 get _focusNode() { |
| 5232 return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]'
) || this; |
| 5233 }, |
| 5234 get _focusableNodes() { |
| 5235 var FOCUSABLE_WITH_DISABLED = [ 'a[href]', 'area[href]', 'iframe', '[tabin
dex]', '[contentEditable=true]' ]; |
| 5236 var FOCUSABLE_WITHOUT_DISABLED = [ 'input', 'select', 'textarea', 'button'
]; |
| 5237 var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') + ':
not([tabindex="-1"]),' + FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([
tabindex="-1"]),') + ':not([disabled]):not([tabindex="-1"])'; |
| 5238 var focusables = Polymer.dom(this).querySelectorAll(selector); |
| 5239 if (this.tabIndex >= 0) { |
| 5240 focusables.splice(0, 0, this); |
| 5241 } |
| 5242 return focusables.sort(function(a, b) { |
| 5243 if (a.tabIndex === b.tabIndex) { |
| 5244 return 0; |
| 5245 } |
| 5246 if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) { |
| 5247 return 1; |
| 5248 } |
| 5249 return -1; |
| 5250 }); |
| 5251 }, |
| 5252 ready: function() { |
| 5253 this.__isAnimating = false; |
| 5254 this.__shouldRemoveTabIndex = false; |
| 5255 this.__firstFocusableNode = this.__lastFocusableNode = null; |
| 5256 this.__raf = null; |
| 5257 this.__restoreFocusNode = null; |
| 5258 this._ensureSetup(); |
| 5259 }, |
| 5260 attached: function() { |
| 5261 if (this.opened) { |
| 5262 this._openedChanged(this.opened); |
| 5263 } |
| 5264 this._observer = Polymer.dom(this).observeNodes(this._onNodesChange); |
| 5265 }, |
| 5266 detached: function() { |
| 5267 Polymer.dom(this).unobserveNodes(this._observer); |
| 5268 this._observer = null; |
| 5269 if (this.__raf) { |
| 5270 window.cancelAnimationFrame(this.__raf); |
| 5271 this.__raf = null; |
| 5272 } |
| 5273 this._manager.removeOverlay(this); |
| 5274 }, |
| 5275 toggle: function() { |
| 5276 this._setCanceled(false); |
| 5277 this.opened = !this.opened; |
| 5278 }, |
| 5279 open: function() { |
| 5280 this._setCanceled(false); |
| 5281 this.opened = true; |
| 5282 }, |
| 5283 close: function() { |
| 5284 this._setCanceled(false); |
| 5285 this.opened = false; |
| 5286 }, |
| 5287 cancel: function(event) { |
| 5288 var cancelEvent = this.fire('iron-overlay-canceled', event, { |
| 5289 cancelable: true |
| 5290 }); |
| 5291 if (cancelEvent.defaultPrevented) { |
| 5292 return; |
| 5293 } |
| 5294 this._setCanceled(true); |
| 5295 this.opened = false; |
| 5296 }, |
| 5297 _ensureSetup: function() { |
| 5298 if (this._overlaySetup) { |
| 5299 return; |
| 5300 } |
| 5301 this._overlaySetup = true; |
| 5302 this.style.outline = 'none'; |
| 5303 this.style.display = 'none'; |
| 5304 }, |
| 5305 _openedChanged: function(opened) { |
| 5306 if (opened) { |
| 5307 this.removeAttribute('aria-hidden'); |
| 5308 } else { |
| 5309 this.setAttribute('aria-hidden', 'true'); |
| 5310 } |
| 5311 if (!this.isAttached) { |
| 5312 return; |
| 5313 } |
| 5314 this.__isAnimating = true; |
| 5315 this.__onNextAnimationFrame(this.__openedChanged); |
| 5316 }, |
| 5317 _canceledChanged: function() { |
| 5318 this.closingReason = this.closingReason || {}; |
| 5319 this.closingReason.canceled = this.canceled; |
| 5320 }, |
| 5321 _withBackdropChanged: function() { |
| 5322 if (this.withBackdrop && !this.hasAttribute('tabindex')) { |
| 5323 this.setAttribute('tabindex', '-1'); |
| 5324 this.__shouldRemoveTabIndex = true; |
| 5325 } else if (this.__shouldRemoveTabIndex) { |
| 5326 this.removeAttribute('tabindex'); |
| 5327 this.__shouldRemoveTabIndex = false; |
| 5328 } |
| 5329 if (this.opened && this.isAttached) { |
| 5330 this._manager.trackBackdrop(); |
| 5331 } |
| 5332 }, |
| 5333 _prepareRenderOpened: function() { |
| 5334 this.__restoreFocusNode = this._manager.deepActiveElement; |
| 5335 this._preparePositioning(); |
| 5336 this.refit(); |
| 5337 this._finishPositioning(); |
| 5338 if (this.noAutoFocus && document.activeElement === this._focusNode) { |
| 5339 this._focusNode.blur(); |
| 5340 this.__restoreFocusNode.focus(); |
| 5341 } |
| 5342 }, |
| 5343 _renderOpened: function() { |
| 5344 this._finishRenderOpened(); |
| 5345 }, |
| 5346 _renderClosed: function() { |
| 5347 this._finishRenderClosed(); |
| 5348 }, |
| 5349 _finishRenderOpened: function() { |
| 5350 this.notifyResize(); |
| 5351 this.__isAnimating = false; |
| 5352 var focusableNodes = this._focusableNodes; |
| 5353 this.__firstFocusableNode = focusableNodes[0]; |
| 5354 this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1]; |
| 5355 this.fire('iron-overlay-opened'); |
| 5356 }, |
| 5357 _finishRenderClosed: function() { |
| 5358 this.style.display = 'none'; |
| 5359 this.style.zIndex = ''; |
| 5360 this.notifyResize(); |
| 5361 this.__isAnimating = false; |
| 5362 this.fire('iron-overlay-closed', this.closingReason); |
| 5363 }, |
| 5364 _preparePositioning: function() { |
| 5365 this.style.transition = this.style.webkitTransition = 'none'; |
| 5366 this.style.transform = this.style.webkitTransform = 'none'; |
| 5367 this.style.display = ''; |
| 5368 }, |
| 5369 _finishPositioning: function() { |
| 5370 this.style.display = 'none'; |
| 5371 this.scrollTop = this.scrollTop; |
| 5372 this.style.transition = this.style.webkitTransition = ''; |
| 5373 this.style.transform = this.style.webkitTransform = ''; |
| 5374 this.style.display = ''; |
| 5375 this.scrollTop = this.scrollTop; |
| 5376 }, |
| 5377 _applyFocus: function() { |
| 5378 if (this.opened) { |
| 5379 if (!this.noAutoFocus) { |
| 5380 this._focusNode.focus(); |
| 5381 } |
| 5382 } else { |
| 5383 this._focusNode.blur(); |
| 5384 this._focusedChild = null; |
| 5385 if (this.restoreFocusOnClose && this.__restoreFocusNode) { |
| 5386 this.__restoreFocusNode.focus(); |
| 5387 } |
| 5388 this.__restoreFocusNode = null; |
| 5389 var currentOverlay = this._manager.currentOverlay(); |
| 5390 if (currentOverlay && this !== currentOverlay) { |
| 5391 currentOverlay._applyFocus(); |
| 5392 } |
| 5393 } |
| 5394 }, |
| 5395 _onCaptureClick: function(event) { |
| 5396 if (!this.noCancelOnOutsideClick) { |
| 5397 this.cancel(event); |
| 5398 } |
| 5399 }, |
| 5400 _onCaptureFocus: function(event) { |
| 5401 if (!this.withBackdrop) { |
| 5402 return; |
| 5403 } |
| 5404 var path = Polymer.dom(event).path; |
| 5405 if (path.indexOf(this) === -1) { |
| 5406 event.stopPropagation(); |
| 5407 this._applyFocus(); |
| 5408 } else { |
| 5409 this._focusedChild = path[0]; |
| 5410 } |
| 5411 }, |
| 5412 _onCaptureEsc: function(event) { |
| 5413 if (!this.noCancelOnEscKey) { |
| 5414 this.cancel(event); |
| 5415 } |
| 5416 }, |
| 5417 _onCaptureTab: function(event) { |
| 5418 if (!this.withBackdrop) { |
| 5419 return; |
| 5420 } |
| 5421 var shift = event.shiftKey; |
| 5422 var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusable
Node; |
| 5423 var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNo
de; |
| 5424 var shouldWrap = false; |
| 5425 if (nodeToCheck === nodeToSet) { |
| 5426 shouldWrap = true; |
| 5427 } else { |
| 5428 var focusedNode = this._manager.deepActiveElement; |
| 5429 shouldWrap = focusedNode === nodeToCheck || focusedNode === this; |
| 5430 } |
| 5431 if (shouldWrap) { |
| 5432 event.preventDefault(); |
| 5433 this._focusedChild = nodeToSet; |
| 5434 this._applyFocus(); |
| 5435 } |
| 5436 }, |
| 5437 _onIronResize: function() { |
| 5438 if (this.opened && !this.__isAnimating) { |
| 5439 this.__onNextAnimationFrame(this.refit); |
| 5440 } |
| 5441 }, |
| 5442 _onNodesChange: function() { |
| 5443 if (this.opened && !this.__isAnimating) { |
| 5444 this.notifyResize(); |
| 5445 } |
| 5446 }, |
| 5447 __openedChanged: function() { |
| 5448 if (this.opened) { |
| 5449 this._prepareRenderOpened(); |
| 5450 this._manager.addOverlay(this); |
| 5451 this._applyFocus(); |
| 5452 this._renderOpened(); |
| 5453 } else { |
| 5454 this._manager.removeOverlay(this); |
| 5455 this._applyFocus(); |
| 5456 this._renderClosed(); |
| 5457 } |
| 5458 }, |
| 5459 __onNextAnimationFrame: function(callback) { |
| 5460 if (this.__raf) { |
| 5461 window.cancelAnimationFrame(this.__raf); |
| 5462 } |
| 5463 var self = this; |
| 5464 this.__raf = window.requestAnimationFrame(function nextAnimationFrame() { |
| 5465 self.__raf = null; |
| 5466 callback.call(self); |
| 5467 }); |
| 5468 } |
| 5469 }; |
| 5470 Polymer.IronOverlayBehavior = [ Polymer.IronFitBehavior, Polymer.IronResizable
Behavior, Polymer.IronOverlayBehaviorImpl ]; |
| 5471 })(); |
| 5472 |
| 5473 Polymer.NeonAnimatableBehavior = { |
| 5474 properties: { |
| 5475 animationConfig: { |
| 5476 type: Object |
| 5477 }, |
| 5478 entryAnimation: { |
| 5479 observer: '_entryAnimationChanged', |
| 5480 type: String |
| 5481 }, |
| 5482 exitAnimation: { |
| 5483 observer: '_exitAnimationChanged', |
| 5484 type: String |
| 5485 } |
| 5486 }, |
| 5487 _entryAnimationChanged: function() { |
| 5488 this.animationConfig = this.animationConfig || {}; |
| 5489 this.animationConfig['entry'] = [ { |
| 5490 name: this.entryAnimation, |
| 5491 node: this |
| 5492 } ]; |
| 5493 }, |
| 5494 _exitAnimationChanged: function() { |
| 5495 this.animationConfig = this.animationConfig || {}; |
| 5496 this.animationConfig['exit'] = [ { |
| 5497 name: this.exitAnimation, |
| 5498 node: this |
| 5499 } ]; |
| 5500 }, |
| 5501 _copyProperties: function(config1, config2) { |
| 5502 for (var property in config2) { |
| 5503 config1[property] = config2[property]; |
| 5504 } |
| 5505 }, |
| 5506 _cloneConfig: function(config) { |
| 5507 var clone = { |
| 5508 isClone: true |
| 5509 }; |
| 5510 this._copyProperties(clone, config); |
| 5511 return clone; |
| 5512 }, |
| 5513 _getAnimationConfigRecursive: function(type, map, allConfigs) { |
| 5514 if (!this.animationConfig) { |
| 5515 return; |
| 5516 } |
| 5517 if (this.animationConfig.value && typeof this.animationConfig.value === 'fun
ction') { |
| 5518 this._warn(this._logf('playAnimation', "Please put 'animationConfig' insid
e of your components 'properties' object instead of outside of it.")); |
| 5519 return; |
| 5520 } |
| 5521 var thisConfig; |
| 5522 if (type) { |
| 5523 thisConfig = this.animationConfig[type]; |
| 5524 } else { |
| 5525 thisConfig = this.animationConfig; |
| 5526 } |
| 5527 if (!Array.isArray(thisConfig)) { |
| 5528 thisConfig = [ thisConfig ]; |
| 5529 } |
| 5530 if (thisConfig) { |
| 5531 for (var config, index = 0; config = thisConfig[index]; index++) { |
| 5532 if (config.animatable) { |
| 5533 config.animatable._getAnimationConfigRecursive(config.type || type, ma
p, allConfigs); |
| 5534 } else { |
| 5535 if (config.id) { |
| 5536 var cachedConfig = map[config.id]; |
| 5537 if (cachedConfig) { |
| 5538 if (!cachedConfig.isClone) { |
| 5539 map[config.id] = this._cloneConfig(cachedConfig); |
| 5540 cachedConfig = map[config.id]; |
| 5541 } |
| 5542 this._copyProperties(cachedConfig, config); |
| 5543 } else { |
| 5544 map[config.id] = config; |
| 5545 } |
| 5546 } else { |
| 5547 allConfigs.push(config); |
| 5548 } |
| 5549 } |
| 5550 } |
| 5551 } |
| 5552 }, |
| 5553 getAnimationConfig: function(type) { |
| 5554 var map = {}; |
| 5555 var allConfigs = []; |
| 5556 this._getAnimationConfigRecursive(type, map, allConfigs); |
| 5557 for (var key in map) { |
| 5558 allConfigs.push(map[key]); |
| 5559 } |
| 5560 return allConfigs; |
| 5561 } |
| 5562 }; |
| 5563 |
| 5564 Polymer.NeonAnimationRunnerBehaviorImpl = { |
| 5565 _configureAnimations: function(configs) { |
| 5566 var results = []; |
| 5567 if (configs.length > 0) { |
| 5568 for (var config, index = 0; config = configs[index]; index++) { |
| 5569 var neonAnimation = document.createElement(config.name); |
| 5570 if (neonAnimation.isNeonAnimation) { |
| 5571 var result = null; |
| 5572 try { |
| 5573 result = neonAnimation.configure(config); |
| 5574 if (typeof result.cancel != 'function') { |
| 5575 result = document.timeline.play(result); |
| 5576 } |
| 5577 } catch (e) { |
| 5578 result = null; |
| 5579 console.warn('Couldnt play', '(', config.name, ').', e); |
| 5580 } |
| 5581 if (result) { |
| 5582 results.push({ |
| 5583 neonAnimation: neonAnimation, |
| 5584 config: config, |
| 5585 animation: result |
| 5586 }); |
| 5587 } |
| 5588 } else { |
| 5589 console.warn(this.is + ':', config.name, 'not found!'); |
| 5590 } |
| 5591 } |
| 5592 } |
| 5593 return results; |
| 5594 }, |
| 5595 _shouldComplete: function(activeEntries) { |
| 5596 var finished = true; |
| 5597 for (var i = 0; i < activeEntries.length; i++) { |
| 5598 if (activeEntries[i].animation.playState != 'finished') { |
| 5599 finished = false; |
| 5600 break; |
| 5601 } |
| 5602 } |
| 5603 return finished; |
| 5604 }, |
| 5605 _complete: function(activeEntries) { |
| 5606 for (var i = 0; i < activeEntries.length; i++) { |
| 5607 activeEntries[i].neonAnimation.complete(activeEntries[i].config); |
| 5608 } |
| 5609 for (var i = 0; i < activeEntries.length; i++) { |
| 5610 activeEntries[i].animation.cancel(); |
| 5611 } |
| 5612 }, |
| 5613 playAnimation: function(type, cookie) { |
| 5614 var configs = this.getAnimationConfig(type); |
| 5615 if (!configs) { |
| 5616 return; |
| 5617 } |
| 5618 this._active = this._active || {}; |
| 5619 if (this._active[type]) { |
| 5620 this._complete(this._active[type]); |
| 5621 delete this._active[type]; |
| 5622 } |
| 5623 var activeEntries = this._configureAnimations(configs); |
| 5624 if (activeEntries.length == 0) { |
| 5625 this.fire('neon-animation-finish', cookie, { |
| 5626 bubbles: false |
| 5627 }); |
| 5628 return; |
| 5629 } |
| 5630 this._active[type] = activeEntries; |
| 5631 for (var i = 0; i < activeEntries.length; i++) { |
| 5632 activeEntries[i].animation.onfinish = function() { |
| 5633 if (this._shouldComplete(activeEntries)) { |
| 5634 this._complete(activeEntries); |
| 5635 delete this._active[type]; |
| 5636 this.fire('neon-animation-finish', cookie, { |
| 5637 bubbles: false |
| 5638 }); |
| 5639 } |
| 5640 }.bind(this); |
| 5641 } |
| 5642 }, |
| 5643 cancelAnimation: function() { |
| 5644 for (var k in this._animations) { |
| 5645 this._animations[k].cancel(); |
| 5646 } |
| 5647 this._animations = {}; |
| 5648 } |
| 5649 }; |
| 5650 |
| 5651 Polymer.NeonAnimationRunnerBehavior = [ Polymer.NeonAnimatableBehavior, Polymer.
NeonAnimationRunnerBehaviorImpl ]; |
| 5652 |
| 5653 Polymer.NeonAnimationBehavior = { |
| 5654 properties: { |
| 5655 animationTiming: { |
| 5656 type: Object, |
| 5657 value: function() { |
| 5658 return { |
| 5659 duration: 500, |
| 5660 easing: 'cubic-bezier(0.4, 0, 0.2, 1)', |
| 5661 fill: 'both' |
| 5662 }; |
| 5663 } |
| 5664 } |
| 5665 }, |
| 5666 isNeonAnimation: true, |
| 5667 timingFromConfig: function(config) { |
| 5668 if (config.timing) { |
| 5669 for (var property in config.timing) { |
| 5670 this.animationTiming[property] = config.timing[property]; |
| 5671 } |
| 5672 } |
| 5673 return this.animationTiming; |
| 5674 }, |
| 5675 setPrefixedProperty: function(node, property, value) { |
| 5676 var map = { |
| 5677 transform: [ 'webkitTransform' ], |
| 5678 transformOrigin: [ 'mozTransformOrigin', 'webkitTransformOrigin' ] |
| 5679 }; |
| 5680 var prefixes = map[property]; |
| 5681 for (var prefix, index = 0; prefix = prefixes[index]; index++) { |
| 5682 node.style[prefix] = value; |
| 5683 } |
| 5684 node.style[property] = value; |
| 5685 }, |
| 5686 complete: function() {} |
| 5687 }; |
| 5688 |
| 5689 Polymer({ |
| 5690 is: 'opaque-animation', |
| 5691 behaviors: [ Polymer.NeonAnimationBehavior ], |
| 5692 configure: function(config) { |
| 5693 var node = config.node; |
| 5694 this._effect = new KeyframeEffect(node, [ { |
| 5695 opacity: '1' |
| 5696 }, { |
| 5697 opacity: '1' |
| 5698 } ], this.timingFromConfig(config)); |
| 5699 node.style.opacity = '0'; |
| 5700 return this._effect; |
| 5701 }, |
| 5702 complete: function(config) { |
| 5703 config.node.style.opacity = ''; |
| 5704 } |
| 5705 }); |
| 5706 |
| 5707 (function() { |
| 5708 'use strict'; |
| 5709 var LAST_TOUCH_POSITION = { |
| 5710 pageX: 0, |
| 5711 pageY: 0 |
| 5712 }; |
| 5713 var ROOT_TARGET = null; |
| 5714 var SCROLLABLE_NODES = []; |
| 5715 Polymer.IronDropdownScrollManager = { |
| 5716 get currentLockingElement() { |
| 5717 return this._lockingElements[this._lockingElements.length - 1]; |
| 5718 }, |
| 5719 elementIsScrollLocked: function(element) { |
| 5720 var currentLockingElement = this.currentLockingElement; |
| 5721 if (currentLockingElement === undefined) return false; |
| 5722 var scrollLocked; |
| 5723 if (this._hasCachedLockedElement(element)) { |
| 5724 return true; |
| 5725 } |
| 5726 if (this._hasCachedUnlockedElement(element)) { |
| 5727 return false; |
| 5728 } |
| 5729 scrollLocked = !!currentLockingElement && currentLockingElement !== elemen
t && !this._composedTreeContains(currentLockingElement, element); |
| 5730 if (scrollLocked) { |
| 5731 this._lockedElementCache.push(element); |
| 5732 } else { |
| 5733 this._unlockedElementCache.push(element); |
| 5734 } |
| 5735 return scrollLocked; |
| 5736 }, |
| 5737 pushScrollLock: function(element) { |
| 5738 if (this._lockingElements.indexOf(element) >= 0) { |
| 5739 return; |
| 5740 } |
| 5741 if (this._lockingElements.length === 0) { |
| 5742 this._lockScrollInteractions(); |
| 5743 } |
| 5744 this._lockingElements.push(element); |
| 5745 this._lockedElementCache = []; |
| 5746 this._unlockedElementCache = []; |
| 5747 }, |
| 5748 removeScrollLock: function(element) { |
| 5749 var index = this._lockingElements.indexOf(element); |
| 5750 if (index === -1) { |
| 5751 return; |
| 5752 } |
| 5753 this._lockingElements.splice(index, 1); |
| 5754 this._lockedElementCache = []; |
| 5755 this._unlockedElementCache = []; |
| 5756 if (this._lockingElements.length === 0) { |
| 5757 this._unlockScrollInteractions(); |
| 5758 } |
| 5759 }, |
| 5760 _lockingElements: [], |
| 5761 _lockedElementCache: null, |
| 5762 _unlockedElementCache: null, |
| 5763 _hasCachedLockedElement: function(element) { |
| 5764 return this._lockedElementCache.indexOf(element) > -1; |
| 5765 }, |
| 5766 _hasCachedUnlockedElement: function(element) { |
| 5767 return this._unlockedElementCache.indexOf(element) > -1; |
| 5768 }, |
| 5769 _composedTreeContains: function(element, child) { |
| 5770 var contentElements; |
| 5771 var distributedNodes; |
| 5772 var contentIndex; |
| 5773 var nodeIndex; |
| 5774 if (element.contains(child)) { |
| 5775 return true; |
| 5776 } |
| 5777 contentElements = Polymer.dom(element).querySelectorAll('content'); |
| 5778 for (contentIndex = 0; contentIndex < contentElements.length; ++contentInd
ex) { |
| 5779 distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistrib
utedNodes(); |
| 5780 for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) { |
| 5781 if (this._composedTreeContains(distributedNodes[nodeIndex], child)) { |
| 5782 return true; |
| 5783 } |
| 5784 } |
| 5785 } |
| 5786 return false; |
| 5787 }, |
| 5788 _scrollInteractionHandler: function(event) { |
| 5789 if (event.cancelable && this._shouldPreventScrolling(event)) { |
| 5790 event.preventDefault(); |
| 5791 } |
| 5792 if (event.targetTouches) { |
| 5793 var touch = event.targetTouches[0]; |
| 5794 LAST_TOUCH_POSITION.pageX = touch.pageX; |
| 5795 LAST_TOUCH_POSITION.pageY = touch.pageY; |
| 5796 } |
| 5797 }, |
| 5798 _lockScrollInteractions: function() { |
| 5799 this._boundScrollHandler = this._boundScrollHandler || this._scrollInterac
tionHandler.bind(this); |
| 5800 document.addEventListener('wheel', this._boundScrollHandler, true); |
| 5801 document.addEventListener('mousewheel', this._boundScrollHandler, true); |
| 5802 document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true
); |
| 5803 document.addEventListener('touchstart', this._boundScrollHandler, true); |
| 5804 document.addEventListener('touchmove', this._boundScrollHandler, true); |
| 5805 }, |
| 5806 _unlockScrollInteractions: function() { |
| 5807 document.removeEventListener('wheel', this._boundScrollHandler, true); |
| 5808 document.removeEventListener('mousewheel', this._boundScrollHandler, true)
; |
| 5809 document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, t
rue); |
| 5810 document.removeEventListener('touchstart', this._boundScrollHandler, true)
; |
| 5811 document.removeEventListener('touchmove', this._boundScrollHandler, true); |
| 5812 }, |
| 5813 _shouldPreventScrolling: function(event) { |
| 5814 var target = Polymer.dom(event).rootTarget; |
| 5815 if (event.type !== 'touchmove' && ROOT_TARGET !== target) { |
| 5816 ROOT_TARGET = target; |
| 5817 SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path); |
| 5818 } |
| 5819 if (!SCROLLABLE_NODES.length) { |
| 5820 return true; |
| 5821 } |
| 5822 if (event.type === 'touchstart') { |
| 5823 return false; |
| 5824 } |
| 5825 var info = this._getScrollInfo(event); |
| 5826 return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY)
; |
| 5827 }, |
| 5828 _getScrollableNodes: function(nodes) { |
| 5829 var scrollables = []; |
| 5830 var lockingIndex = nodes.indexOf(this.currentLockingElement); |
| 5831 for (var i = 0; i <= lockingIndex; i++) { |
| 5832 var node = nodes[i]; |
| 5833 if (node.nodeType === 11) { |
| 5834 continue; |
| 5835 } |
| 5836 var style = node.style; |
| 5837 if (style.overflow !== 'scroll' && style.overflow !== 'auto') { |
| 5838 style = window.getComputedStyle(node); |
| 5839 } |
| 5840 if (style.overflow === 'scroll' || style.overflow === 'auto') { |
| 5841 scrollables.push(node); |
| 5842 } |
| 5843 } |
| 5844 return scrollables; |
| 5845 }, |
| 5846 _getScrollingNode: function(nodes, deltaX, deltaY) { |
| 5847 if (!deltaX && !deltaY) { |
| 5848 return; |
| 5849 } |
| 5850 var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX); |
| 5851 for (var i = 0; i < nodes.length; i++) { |
| 5852 var node = nodes[i]; |
| 5853 var canScroll = false; |
| 5854 if (verticalScroll) { |
| 5855 canScroll = deltaY < 0 ? node.scrollTop > 0 : node.scrollTop < node.sc
rollHeight - node.clientHeight; |
| 5856 } else { |
| 5857 canScroll = deltaX < 0 ? node.scrollLeft > 0 : node.scrollLeft < node.
scrollWidth - node.clientWidth; |
| 5858 } |
| 5859 if (canScroll) { |
| 5860 return node; |
| 5861 } |
| 5862 } |
| 5863 }, |
| 5864 _getScrollInfo: function(event) { |
| 5865 var info = { |
| 5866 deltaX: event.deltaX, |
| 5867 deltaY: event.deltaY |
| 5868 }; |
| 5869 if ('deltaX' in event) {} else if ('wheelDeltaX' in event) { |
| 5870 info.deltaX = -event.wheelDeltaX; |
| 5871 info.deltaY = -event.wheelDeltaY; |
| 5872 } else if ('axis' in event) { |
| 5873 info.deltaX = event.axis === 1 ? event.detail : 0; |
| 5874 info.deltaY = event.axis === 2 ? event.detail : 0; |
| 5875 } else if (event.targetTouches) { |
| 5876 var touch = event.targetTouches[0]; |
| 5877 info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX; |
| 5878 info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY; |
| 5879 } |
| 5880 return info; |
| 5881 } |
| 5882 }; |
| 5883 })(); |
| 5884 |
| 5885 (function() { |
| 5886 'use strict'; |
| 5887 Polymer({ |
| 5888 is: 'iron-dropdown', |
| 5889 behaviors: [ Polymer.IronControlState, Polymer.IronA11yKeysBehavior, Polymer
.IronOverlayBehavior, Polymer.NeonAnimationRunnerBehavior ], |
| 5890 properties: { |
| 5891 horizontalAlign: { |
| 5892 type: String, |
| 5893 value: 'left', |
| 5894 reflectToAttribute: true |
| 5895 }, |
| 5896 verticalAlign: { |
| 5897 type: String, |
| 5898 value: 'top', |
| 5899 reflectToAttribute: true |
| 5900 }, |
| 5901 openAnimationConfig: { |
| 5902 type: Object |
| 5903 }, |
| 5904 closeAnimationConfig: { |
| 5905 type: Object |
| 5906 }, |
| 5907 focusTarget: { |
| 5908 type: Object |
| 5909 }, |
| 5910 noAnimations: { |
| 5911 type: Boolean, |
| 5912 value: false |
| 5913 }, |
| 5914 allowOutsideScroll: { |
| 5915 type: Boolean, |
| 5916 value: false |
| 5917 }, |
| 5918 _boundOnCaptureScroll: { |
| 5919 type: Function, |
| 5920 value: function() { |
| 5921 return this._onCaptureScroll.bind(this); |
| 5922 } |
| 5923 } |
| 5924 }, |
| 5925 listeners: { |
| 5926 'neon-animation-finish': '_onNeonAnimationFinish' |
| 5927 }, |
| 5928 observers: [ '_updateOverlayPosition(positionTarget, verticalAlign, horizont
alAlign, verticalOffset, horizontalOffset)' ], |
| 5929 get containedElement() { |
| 5930 return Polymer.dom(this.$.content).getDistributedNodes()[0]; |
| 5931 }, |
| 5932 get _focusTarget() { |
| 5933 return this.focusTarget || this.containedElement; |
| 5934 }, |
| 5935 ready: function() { |
| 5936 this._scrollTop = 0; |
| 5937 this._scrollLeft = 0; |
| 5938 this._refitOnScrollRAF = null; |
| 5939 }, |
| 5940 detached: function() { |
| 5941 this.cancelAnimation(); |
| 5942 Polymer.IronDropdownScrollManager.removeScrollLock(this); |
| 5943 }, |
| 5944 _openedChanged: function() { |
| 5945 if (this.opened && this.disabled) { |
| 5946 this.cancel(); |
| 5947 } else { |
| 5948 this.cancelAnimation(); |
| 5949 this.sizingTarget = this.containedElement || this.sizingTarget; |
| 5950 this._updateAnimationConfig(); |
| 5951 this._saveScrollPosition(); |
| 5952 if (this.opened) { |
| 5953 document.addEventListener('scroll', this._boundOnCaptureScroll); |
| 5954 !this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScro
llLock(this); |
| 5955 } else { |
| 5956 document.removeEventListener('scroll', this._boundOnCaptureScroll); |
| 5957 Polymer.IronDropdownScrollManager.removeScrollLock(this); |
| 5958 } |
| 5959 Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments); |
| 5960 } |
| 5961 }, |
| 5962 _renderOpened: function() { |
| 5963 if (!this.noAnimations && this.animationConfig.open) { |
| 5964 this.$.contentWrapper.classList.add('animating'); |
| 5965 this.playAnimation('open'); |
| 5966 } else { |
| 5967 Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments); |
| 5968 } |
| 5969 }, |
| 5970 _renderClosed: function() { |
| 5971 if (!this.noAnimations && this.animationConfig.close) { |
| 5972 this.$.contentWrapper.classList.add('animating'); |
| 5973 this.playAnimation('close'); |
| 5974 } else { |
| 5975 Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments); |
| 5976 } |
| 5977 }, |
| 5978 _onNeonAnimationFinish: function() { |
| 5979 this.$.contentWrapper.classList.remove('animating'); |
| 5980 if (this.opened) { |
| 5981 this._finishRenderOpened(); |
| 5982 } else { |
| 5983 this._finishRenderClosed(); |
| 5984 } |
| 5985 }, |
| 5986 _onCaptureScroll: function() { |
| 5987 if (!this.allowOutsideScroll) { |
| 5988 this._restoreScrollPosition(); |
| 5989 } else { |
| 5990 this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrol
lRAF); |
| 5991 this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(th
is)); |
| 5992 } |
| 5993 }, |
| 5994 _saveScrollPosition: function() { |
| 5995 if (document.scrollingElement) { |
| 5996 this._scrollTop = document.scrollingElement.scrollTop; |
| 5997 this._scrollLeft = document.scrollingElement.scrollLeft; |
| 5998 } else { |
| 5999 this._scrollTop = Math.max(document.documentElement.scrollTop, document.
body.scrollTop); |
| 6000 this._scrollLeft = Math.max(document.documentElement.scrollLeft, documen
t.body.scrollLeft); |
| 6001 } |
| 6002 }, |
| 6003 _restoreScrollPosition: function() { |
| 6004 if (document.scrollingElement) { |
| 6005 document.scrollingElement.scrollTop = this._scrollTop; |
| 6006 document.scrollingElement.scrollLeft = this._scrollLeft; |
| 6007 } else { |
| 6008 document.documentElement.scrollTop = this._scrollTop; |
| 6009 document.documentElement.scrollLeft = this._scrollLeft; |
| 6010 document.body.scrollTop = this._scrollTop; |
| 6011 document.body.scrollLeft = this._scrollLeft; |
| 6012 } |
| 6013 }, |
| 6014 _updateAnimationConfig: function() { |
| 6015 var animations = (this.openAnimationConfig || []).concat(this.closeAnimati
onConfig || []); |
| 6016 for (var i = 0; i < animations.length; i++) { |
| 6017 animations[i].node = this.containedElement; |
| 6018 } |
| 6019 this.animationConfig = { |
| 6020 open: this.openAnimationConfig, |
| 6021 close: this.closeAnimationConfig |
| 6022 }; |
| 6023 }, |
| 6024 _updateOverlayPosition: function() { |
| 6025 if (this.isAttached) { |
| 6026 this.notifyResize(); |
| 6027 } |
| 6028 }, |
| 6029 _applyFocus: function() { |
| 6030 var focusTarget = this.focusTarget || this.containedElement; |
| 6031 if (focusTarget && this.opened && !this.noAutoFocus) { |
| 6032 focusTarget.focus(); |
| 6033 } else { |
| 6034 Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments); |
| 6035 } |
| 6036 } |
| 6037 }); |
| 6038 })(); |
| 6039 |
| 6040 Polymer({ |
| 6041 is: 'fade-in-animation', |
| 6042 behaviors: [ Polymer.NeonAnimationBehavior ], |
| 6043 configure: function(config) { |
| 6044 var node = config.node; |
| 6045 this._effect = new KeyframeEffect(node, [ { |
| 6046 opacity: '0' |
| 6047 }, { |
| 6048 opacity: '1' |
| 6049 } ], this.timingFromConfig(config)); |
| 6050 return this._effect; |
| 6051 } |
| 6052 }); |
| 6053 |
| 6054 Polymer({ |
| 6055 is: 'fade-out-animation', |
| 6056 behaviors: [ Polymer.NeonAnimationBehavior ], |
| 6057 configure: function(config) { |
| 6058 var node = config.node; |
| 6059 this._effect = new KeyframeEffect(node, [ { |
| 6060 opacity: '1' |
| 6061 }, { |
| 6062 opacity: '0' |
| 6063 } ], this.timingFromConfig(config)); |
| 6064 return this._effect; |
| 6065 } |
| 6066 }); |
| 6067 |
| 6068 Polymer({ |
| 6069 is: 'paper-menu-grow-height-animation', |
| 6070 behaviors: [ Polymer.NeonAnimationBehavior ], |
| 6071 configure: function(config) { |
| 6072 var node = config.node; |
| 6073 var rect = node.getBoundingClientRect(); |
| 6074 var height = rect.height; |
| 6075 this._effect = new KeyframeEffect(node, [ { |
| 6076 height: height / 2 + 'px' |
| 6077 }, { |
| 6078 height: height + 'px' |
| 6079 } ], this.timingFromConfig(config)); |
| 6080 return this._effect; |
| 6081 } |
| 6082 }); |
| 6083 |
| 6084 Polymer({ |
| 6085 is: 'paper-menu-grow-width-animation', |
| 6086 behaviors: [ Polymer.NeonAnimationBehavior ], |
| 6087 configure: function(config) { |
| 6088 var node = config.node; |
| 6089 var rect = node.getBoundingClientRect(); |
| 6090 var width = rect.width; |
| 6091 this._effect = new KeyframeEffect(node, [ { |
| 6092 width: width / 2 + 'px' |
| 6093 }, { |
| 6094 width: width + 'px' |
| 6095 } ], this.timingFromConfig(config)); |
| 6096 return this._effect; |
| 6097 } |
| 6098 }); |
| 6099 |
| 6100 Polymer({ |
| 6101 is: 'paper-menu-shrink-width-animation', |
| 6102 behaviors: [ Polymer.NeonAnimationBehavior ], |
| 6103 configure: function(config) { |
| 6104 var node = config.node; |
| 6105 var rect = node.getBoundingClientRect(); |
| 6106 var width = rect.width; |
| 6107 this._effect = new KeyframeEffect(node, [ { |
| 6108 width: width + 'px' |
| 6109 }, { |
| 6110 width: width - width / 20 + 'px' |
| 6111 } ], this.timingFromConfig(config)); |
| 6112 return this._effect; |
| 6113 } |
| 6114 }); |
| 6115 |
| 6116 Polymer({ |
| 6117 is: 'paper-menu-shrink-height-animation', |
| 6118 behaviors: [ Polymer.NeonAnimationBehavior ], |
| 6119 configure: function(config) { |
| 6120 var node = config.node; |
| 6121 var rect = node.getBoundingClientRect(); |
| 6122 var height = rect.height; |
| 6123 var top = rect.top; |
| 6124 this.setPrefixedProperty(node, 'transformOrigin', '0 0'); |
| 6125 this._effect = new KeyframeEffect(node, [ { |
| 6126 height: height + 'px', |
| 6127 transform: 'translateY(0)' |
| 6128 }, { |
| 6129 height: height / 2 + 'px', |
| 6130 transform: 'translateY(-20px)' |
| 6131 } ], this.timingFromConfig(config)); |
| 6132 return this._effect; |
| 6133 } |
| 6134 }); |
| 6135 |
| 6136 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 6137 // Use of this source code is governed by a BSD-style license that can be |
| 6138 // found in the LICENSE file. |
| 6139 var SLIDE_CUBIC_BEZIER = 'cubic-bezier(0.3, 0.95, 0.5, 1)'; |
| 6140 |
| 6141 Polymer({ |
| 6142 is: 'cr-shared-menu', |
| 6143 behaviors: [ Polymer.IronA11yKeysBehavior ], |
| 6144 properties: { |
| 6145 menuOpen: { |
| 6146 type: Boolean, |
| 6147 observer: 'menuOpenChanged_', |
| 6148 value: false |
| 6149 }, |
| 6150 itemData: { |
| 6151 type: Object, |
| 6152 value: null |
| 6153 }, |
| 6154 keyEventTarget: { |
| 6155 type: Object, |
| 6156 value: function() { |
| 6157 return this.$.menu; |
| 6158 } |
| 6159 }, |
| 6160 openAnimationConfig: { |
| 6161 type: Object, |
| 6162 value: function() { |
| 6163 return [ { |
| 6164 name: 'fade-in-animation', |
| 6165 timing: { |
| 6166 delay: 50, |
| 6167 duration: 200 |
| 6168 } |
| 6169 }, { |
| 6170 name: 'paper-menu-grow-width-animation', |
| 6171 timing: { |
| 6172 delay: 50, |
| 6173 duration: 150, |
| 6174 easing: SLIDE_CUBIC_BEZIER |
| 6175 } |
| 6176 }, { |
| 6177 name: 'paper-menu-grow-height-animation', |
| 6178 timing: { |
| 6179 delay: 100, |
| 6180 duration: 275, |
| 6181 easing: SLIDE_CUBIC_BEZIER |
| 6182 } |
| 6183 } ]; |
| 6184 } |
| 6185 }, |
| 6186 closeAnimationConfig: { |
| 6187 type: Object, |
| 6188 value: function() { |
| 6189 return [ { |
| 6190 name: 'fade-out-animation', |
| 6191 timing: { |
| 6192 duration: 150 |
| 6193 } |
| 6194 } ]; |
| 6195 } |
| 6196 } |
| 6197 }, |
| 6198 keyBindings: { |
| 6199 tab: 'onTabPressed_' |
| 6200 }, |
| 6201 listeners: { |
| 6202 'dropdown.iron-overlay-canceled': 'onOverlayCanceled_' |
| 6203 }, |
| 6204 lastAnchor_: null, |
| 6205 firstFocus_: null, |
| 6206 lastFocus_: null, |
| 6207 attached: function() { |
| 6208 window.addEventListener('resize', this.closeMenu.bind(this)); |
| 6209 }, |
| 6210 closeMenu: function() { |
| 6211 if (this.root.activeElement == null) { |
| 6212 this.$.dropdown.restoreFocusOnClose = false; |
| 6213 } |
| 6214 this.menuOpen = false; |
| 6215 }, |
| 6216 openMenu: function(anchor, itemData) { |
| 6217 if (this.lastAnchor_ == anchor && this.menuOpen) return; |
| 6218 if (this.menuOpen) this.closeMenu(); |
| 6219 this.itemData = itemData; |
| 6220 this.lastAnchor_ = anchor; |
| 6221 this.$.dropdown.restoreFocusOnClose = true; |
| 6222 var focusableChildren = Polymer.dom(this).querySelectorAll('[tabindex]:not([
hidden]),button:not([hidden])'); |
| 6223 if (focusableChildren.length > 0) { |
| 6224 this.$.dropdown.focusTarget = focusableChildren[0]; |
| 6225 this.firstFocus_ = focusableChildren[0]; |
| 6226 this.lastFocus_ = focusableChildren[focusableChildren.length - 1]; |
| 6227 } |
| 6228 this.$.dropdown.positionTarget = anchor; |
| 6229 this.menuOpen = true; |
| 6230 }, |
| 6231 toggleMenu: function(anchor, itemData) { |
| 6232 if (anchor == this.lastAnchor_ && this.menuOpen) this.closeMenu(); else this
.openMenu(anchor, itemData); |
| 6233 }, |
| 6234 onTabPressed_: function(e) { |
| 6235 if (!this.firstFocus_ || !this.lastFocus_) return; |
| 6236 var toFocus; |
| 6237 var keyEvent = e.detail.keyboardEvent; |
| 6238 if (keyEvent.shiftKey && keyEvent.target == this.firstFocus_) toFocus = this
.lastFocus_; else if (keyEvent.target == this.lastFocus_) toFocus = this.firstFo
cus_; |
| 6239 if (!toFocus) return; |
| 6240 e.preventDefault(); |
| 6241 toFocus.focus(); |
| 6242 }, |
| 6243 menuOpenChanged_: function() { |
| 6244 if (!this.menuOpen) { |
| 6245 this.itemData = null; |
| 6246 this.lastAnchor_ = null; |
| 6247 } |
| 6248 }, |
| 6249 onOverlayCanceled_: function(e) { |
| 6250 if (e.detail.type == 'tap') this.$.dropdown.restoreFocusOnClose = false; |
| 6251 } |
| 6252 }); |
| 6253 |
| 6254 Polymer.PaperItemBehaviorImpl = { |
| 6255 hostAttributes: { |
| 6256 role: 'option', |
| 6257 tabindex: '0' |
| 6258 } |
| 6259 }; |
| 6260 |
| 6261 Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState,
Polymer.PaperItemBehaviorImpl ]; |
| 6262 |
| 6263 Polymer({ |
| 6264 is: 'paper-item', |
| 6265 behaviors: [ Polymer.PaperItemBehavior ] |
| 6266 }); |
| 6267 |
| 6268 Polymer({ |
| 6269 is: 'iron-collapse', |
| 6270 behaviors: [ Polymer.IronResizableBehavior ], |
| 6271 properties: { |
| 6272 horizontal: { |
| 6273 type: Boolean, |
| 6274 value: false, |
| 6275 observer: '_horizontalChanged' |
| 6276 }, |
| 6277 opened: { |
| 6278 type: Boolean, |
| 6279 value: false, |
| 6280 notify: true, |
| 6281 observer: '_openedChanged' |
| 6282 }, |
| 6283 noAnimation: { |
| 6284 type: Boolean |
| 6285 } |
| 6286 }, |
| 6287 get dimension() { |
| 6288 return this.horizontal ? 'width' : 'height'; |
| 6289 }, |
| 6290 get _dimensionMax() { |
| 6291 return this.horizontal ? 'maxWidth' : 'maxHeight'; |
| 6292 }, |
| 6293 get _dimensionMaxCss() { |
| 6294 return this.horizontal ? 'max-width' : 'max-height'; |
| 6295 }, |
| 6296 hostAttributes: { |
| 6297 role: 'group', |
| 6298 'aria-hidden': 'true', |
| 6299 'aria-expanded': 'false' |
| 6300 }, |
| 6301 listeners: { |
| 6302 transitionend: '_transitionEnd' |
| 6303 }, |
| 6304 attached: function() { |
| 6305 this._transitionEnd(); |
| 6306 }, |
| 6307 toggle: function() { |
| 6308 this.opened = !this.opened; |
| 6309 }, |
| 6310 show: function() { |
| 6311 this.opened = true; |
| 6312 }, |
| 6313 hide: function() { |
| 6314 this.opened = false; |
| 6315 }, |
| 6316 updateSize: function(size, animated) { |
| 6317 var curSize = this.style[this._dimensionMax]; |
| 6318 if (curSize === size || size === 'auto' && !curSize) { |
| 6319 return; |
| 6320 } |
| 6321 this._updateTransition(false); |
| 6322 if (animated && !this.noAnimation && this._isDisplayed) { |
| 6323 var startSize = this._calcSize(); |
| 6324 if (size === 'auto') { |
| 6325 this.style[this._dimensionMax] = ''; |
| 6326 size = this._calcSize(); |
| 6327 } |
| 6328 this.style[this._dimensionMax] = startSize; |
| 6329 this.scrollTop = this.scrollTop; |
| 6330 this._updateTransition(true); |
| 6331 } |
| 6332 if (size === 'auto') { |
| 6333 this.style[this._dimensionMax] = ''; |
| 6334 } else { |
| 6335 this.style[this._dimensionMax] = size; |
| 6336 } |
| 6337 }, |
| 6338 enableTransition: function(enabled) { |
| 6339 Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` in
stead.'); |
| 6340 this.noAnimation = !enabled; |
| 6341 }, |
| 6342 _updateTransition: function(enabled) { |
| 6343 this.style.transitionDuration = enabled && !this.noAnimation ? '' : '0s'; |
| 6344 }, |
| 6345 _horizontalChanged: function() { |
| 6346 this.style.transitionProperty = this._dimensionMaxCss; |
| 6347 var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxW
idth'; |
| 6348 this.style[otherDimension] = ''; |
| 6349 this.updateSize(this.opened ? 'auto' : '0px', false); |
| 6350 }, |
| 6351 _openedChanged: function() { |
| 6352 this.setAttribute('aria-expanded', this.opened); |
| 6353 this.setAttribute('aria-hidden', !this.opened); |
| 6354 this.toggleClass('iron-collapse-closed', false); |
| 6355 this.toggleClass('iron-collapse-opened', false); |
| 6356 this.updateSize(this.opened ? 'auto' : '0px', true); |
| 6357 if (this.opened) { |
| 6358 this.focus(); |
| 6359 } |
| 6360 if (this.noAnimation) { |
| 6361 this._transitionEnd(); |
| 6362 } |
| 6363 }, |
| 6364 _transitionEnd: function() { |
| 6365 if (this.opened) { |
| 6366 this.style[this._dimensionMax] = ''; |
| 6367 } |
| 6368 this.toggleClass('iron-collapse-closed', !this.opened); |
| 6369 this.toggleClass('iron-collapse-opened', this.opened); |
| 6370 this._updateTransition(false); |
| 6371 this.notifyResize(); |
| 6372 }, |
| 6373 get _isDisplayed() { |
| 6374 var rect = this.getBoundingClientRect(); |
| 6375 for (var prop in rect) { |
| 6376 if (rect[prop] !== 0) return true; |
| 6377 } |
| 6378 return false; |
| 6379 }, |
| 6380 _calcSize: function() { |
| 6381 return this.getBoundingClientRect()[this.dimension] + 'px'; |
| 6382 } |
| 6383 }); |
| 6384 |
| 6385 Polymer.IronFormElementBehavior = { |
| 6386 properties: { |
| 6387 name: { |
| 6388 type: String |
| 6389 }, |
| 6390 value: { |
| 6391 notify: true, |
| 6392 type: String |
| 6393 }, |
| 6394 required: { |
| 6395 type: Boolean, |
| 6396 value: false |
| 6397 }, |
| 6398 _parentForm: { |
| 6399 type: Object |
| 6400 } |
| 6401 }, |
| 6402 attached: function() { |
| 6403 this.fire('iron-form-element-register'); |
| 6404 }, |
| 6405 detached: function() { |
| 6406 if (this._parentForm) { |
| 6407 this._parentForm.fire('iron-form-element-unregister', { |
| 6408 target: this |
| 6409 }); |
| 6410 } |
| 6411 } |
| 6412 }; |
| 6413 |
| 6414 Polymer.IronCheckedElementBehaviorImpl = { |
| 6415 properties: { |
| 6416 checked: { |
| 6417 type: Boolean, |
| 6418 value: false, |
| 6419 reflectToAttribute: true, |
| 6420 notify: true, |
| 6421 observer: '_checkedChanged' |
| 6422 }, |
| 6423 toggles: { |
| 6424 type: Boolean, |
| 6425 value: true, |
| 6426 reflectToAttribute: true |
| 6427 }, |
| 6428 value: { |
| 6429 type: String, |
| 6430 value: 'on', |
| 6431 observer: '_valueChanged' |
| 6432 } |
| 6433 }, |
| 6434 observers: [ '_requiredChanged(required)' ], |
| 6435 created: function() { |
| 6436 this._hasIronCheckedElementBehavior = true; |
| 6437 }, |
| 6438 _getValidity: function(_value) { |
| 6439 return this.disabled || !this.required || this.checked; |
| 6440 }, |
| 6441 _requiredChanged: function() { |
| 6442 if (this.required) { |
| 6443 this.setAttribute('aria-required', 'true'); |
| 6444 } else { |
| 6445 this.removeAttribute('aria-required'); |
| 6446 } |
| 6447 }, |
| 6448 _checkedChanged: function() { |
| 6449 this.active = this.checked; |
| 6450 this.fire('iron-change'); |
| 6451 }, |
| 6452 _valueChanged: function() { |
| 6453 if (this.value === undefined || this.value === null) { |
| 6454 this.value = 'on'; |
| 6455 } |
| 6456 } |
| 6457 }; |
| 6458 |
| 6459 Polymer.IronCheckedElementBehavior = [ Polymer.IronFormElementBehavior, Polymer.
IronValidatableBehavior, Polymer.IronCheckedElementBehaviorImpl ]; |
| 6460 |
| 6461 Polymer.PaperCheckedElementBehaviorImpl = { |
| 6462 _checkedChanged: function() { |
| 6463 Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this); |
| 6464 if (this.hasRipple()) { |
| 6465 if (this.checked) { |
| 6466 this._ripple.setAttribute('checked', ''); |
| 6467 } else { |
| 6468 this._ripple.removeAttribute('checked'); |
| 6469 } |
| 6470 } |
| 6471 }, |
| 6472 _buttonStateChanged: function() { |
| 6473 Polymer.PaperRippleBehavior._buttonStateChanged.call(this); |
| 6474 if (this.disabled) { |
| 6475 return; |
| 6476 } |
| 6477 if (this.isAttached) { |
| 6478 this.checked = this.active; |
| 6479 } |
| 6480 } |
| 6481 }; |
| 6482 |
| 6483 Polymer.PaperCheckedElementBehavior = [ Polymer.PaperInkyFocusBehavior, Polymer.
IronCheckedElementBehavior, Polymer.PaperCheckedElementBehaviorImpl ]; |
| 6484 |
| 6485 Polymer({ |
| 6486 is: 'paper-checkbox', |
| 6487 behaviors: [ Polymer.PaperCheckedElementBehavior ], |
| 6488 hostAttributes: { |
| 6489 role: 'checkbox', |
| 6490 'aria-checked': false, |
| 6491 tabindex: 0 |
| 6492 }, |
| 6493 properties: { |
| 6494 ariaActiveAttribute: { |
| 6495 type: String, |
| 6496 value: 'aria-checked' |
| 6497 } |
| 6498 }, |
| 6499 _computeCheckboxClass: function(checked, invalid) { |
| 6500 var className = ''; |
| 6501 if (checked) { |
| 6502 className += 'checked '; |
| 6503 } |
| 6504 if (invalid) { |
| 6505 className += 'invalid'; |
| 6506 } |
| 6507 return className; |
| 6508 }, |
| 6509 _computeCheckmarkClass: function(checked) { |
| 6510 return checked ? '' : 'hidden'; |
| 6511 }, |
| 6512 _createRipple: function() { |
| 6513 this._rippleContainer = this.$.checkboxContainer; |
| 6514 return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this); |
| 6515 } |
| 6516 }); |
| 6517 |
| 6518 Polymer({ |
| 6519 is: 'paper-icon-button-light', |
| 6520 "extends": 'button', |
| 6521 behaviors: [ Polymer.PaperRippleBehavior ], |
| 6522 listeners: { |
| 6523 down: '_rippleDown', |
| 6524 up: '_rippleUp', |
| 6525 focus: '_rippleDown', |
| 6526 blur: '_rippleUp' |
| 6527 }, |
| 6528 _rippleDown: function() { |
| 6529 this.getRipple().downAction(); |
| 6530 }, |
| 6531 _rippleUp: function() { |
| 6532 this.getRipple().upAction(); |
| 6533 }, |
| 6534 ensureRipple: function(var_args) { |
| 6535 var lastRipple = this._ripple; |
| 6536 Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments); |
| 6537 if (this._ripple && this._ripple !== lastRipple) { |
| 6538 this._ripple.center = true; |
| 6539 this._ripple.classList.add('circle'); |
| 6540 } |
| 6541 } |
| 6542 }); |
| 6543 |
| 6544 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 6545 // Use of this source code is governed by a BSD-style license that can be |
| 6546 // found in the LICENSE file. |
| 6547 cr.define('cr.icon', function() { |
| 6548 function getSupportedScaleFactors() { |
| 6549 var supportedScaleFactors = []; |
| 6550 if (cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux) { |
| 6551 supportedScaleFactors.push(1); |
| 6552 supportedScaleFactors.push(2); |
| 6553 } else { |
| 6554 supportedScaleFactors.push(window.devicePixelRatio); |
| 6555 } |
| 6556 return supportedScaleFactors; |
| 6557 } |
| 6558 function getProfileAvatarIcon(path) { |
| 6559 var chromeThemePath = 'chrome://theme'; |
| 6560 var isDefaultAvatar = path.slice(0, chromeThemePath.length) == chromeThemePa
th; |
| 6561 return isDefaultAvatar ? imageset(path + '@scalefactorx') : url(path); |
| 6562 } |
| 6563 function imageset(path) { |
| 6564 var supportedScaleFactors = getSupportedScaleFactors(); |
| 6565 var replaceStartIndex = path.indexOf('scalefactor'); |
| 6566 if (replaceStartIndex < 0) return url(path); |
| 6567 var s = ''; |
| 6568 for (var i = 0; i < supportedScaleFactors.length; ++i) { |
| 6569 var scaleFactor = supportedScaleFactors[i]; |
| 6570 var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor
+ path.substr(replaceStartIndex + 'scalefactor'.length); |
| 6571 s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x'; |
| 6572 if (i != supportedScaleFactors.length - 1) s += ', '; |
| 6573 } |
| 6574 return '-webkit-image-set(' + s + ')'; |
| 6575 } |
| 6576 var FAVICON_URL_REGEX = /\.ico$/i; |
| 6577 function getFaviconImageSet(url, opt_size, opt_type) { |
| 6578 var size = opt_size || 16; |
| 6579 var type = opt_type || 'favicon'; |
| 6580 return imageset('chrome://' + type + '/size/' + size + '@scalefactorx/' + (F
AVICON_URL_REGEX.test(url) ? 'iconurl/' : '') + url); |
| 6581 } |
| 6582 return { |
| 6583 getSupportedScaleFactors: getSupportedScaleFactors, |
| 6584 getProfileAvatarIcon: getProfileAvatarIcon, |
| 6585 getFaviconImageSet: getFaviconImageSet |
| 6586 }; |
| 6587 }); |
| 6588 |
| 6589 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 6590 // Use of this source code is governed by a BSD-style license that can be |
| 6591 // found in the LICENSE file. |
| 6592 cr.define('md_history', function() { |
| 6593 function BrowserService() { |
| 6594 this.pendingDeleteItems_ = null; |
| 6595 this.pendingDeletePromise_ = null; |
| 6596 } |
| 6597 BrowserService.prototype = { |
| 6598 deleteItems: function(items) { |
| 6599 if (this.pendingDeleteItems_ != null) { |
| 6600 return new Promise(function(resolve, reject) { |
| 6601 reject(items); |
| 6602 }); |
| 6603 } |
| 6604 var removalList = items.map(function(item) { |
| 6605 return { |
| 6606 url: item.url, |
| 6607 timestamps: item.allTimestamps |
| 6608 }; |
| 6609 }); |
| 6610 this.pendingDeleteItems_ = items; |
| 6611 this.pendingDeletePromise_ = new PromiseResolver(); |
| 6612 chrome.send('removeVisits', removalList); |
| 6613 return this.pendingDeletePromise_.promise; |
| 6614 }, |
| 6615 removeBookmark: function(url) { |
| 6616 chrome.send('removeBookmark', [ url ]); |
| 6617 }, |
| 6618 openForeignSessionAllTabs: function(sessionTag) { |
| 6619 chrome.send('openForeignSession', [ sessionTag ]); |
| 6620 }, |
| 6621 openForeignSessionTab: function(sessionTag, windowId, tabId, e) { |
| 6622 chrome.send('openForeignSession', [ sessionTag, String(windowId), String(t
abId), e.button || 0, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey ]); |
| 6623 }, |
| 6624 deleteForeignSession: function(sessionTag) { |
| 6625 chrome.send('deleteForeignSession', [ sessionTag ]); |
| 6626 }, |
| 6627 openClearBrowsingData: function() { |
| 6628 chrome.send('clearBrowsingData'); |
| 6629 }, |
| 6630 resolveDelete_: function(successful) { |
| 6631 if (this.pendingDeleteItems_ == null || this.pendingDeletePromise_ == null
) { |
| 6632 return; |
| 6633 } |
| 6634 if (successful) this.pendingDeletePromise_.resolve(this.pendingDeleteItems
_); else this.pendingDeletePromise_.reject(this.pendingDeleteItems_); |
| 6635 this.pendingDeleteItems_ = null; |
| 6636 this.pendingDeletePromise_ = null; |
| 6637 } |
| 6638 }; |
| 6639 cr.addSingletonGetter(BrowserService); |
| 6640 return { |
| 6641 BrowserService: BrowserService |
| 6642 }; |
| 6643 }); |
| 6644 |
| 6645 function deleteComplete() { |
| 6646 md_history.BrowserService.getInstance().resolveDelete_(true); |
| 6647 } |
| 6648 |
| 6649 function deleteFailed() { |
| 6650 md_history.BrowserService.getInstance().resolveDelete_(false); |
| 6651 } |
| 6652 |
| 6653 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 6654 // Use of this source code is governed by a BSD-style license that can be |
| 6655 // found in the LICENSE file. |
| 6656 Polymer({ |
| 6657 is: 'history-searched-label', |
| 6658 properties: { |
| 6659 title: String, |
| 6660 searchTerm: String |
| 6661 }, |
| 6662 observers: [ 'setSearchedTextToBold_(title, searchTerm)' ], |
| 6663 setSearchedTextToBold_: function() { |
| 6664 var i = 0; |
| 6665 var titleElem = this.$.container; |
| 6666 var titleText = this.title; |
| 6667 if (this.searchTerm == '' || this.searchTerm == null) { |
| 6668 titleElem.textContent = titleText; |
| 6669 return; |
| 6670 } |
| 6671 var re = new RegExp(quoteString(this.searchTerm), 'gim'); |
| 6672 var match; |
| 6673 titleElem.textContent = ''; |
| 6674 while (match = re.exec(titleText)) { |
| 6675 if (match.index > i) titleElem.appendChild(document.createTextNode(titleTe
xt.slice(i, match.index))); |
| 6676 i = re.lastIndex; |
| 6677 var b = document.createElement('b'); |
| 6678 b.textContent = titleText.substring(match.index, i); |
| 6679 titleElem.appendChild(b); |
| 6680 } |
| 6681 if (i < titleText.length) titleElem.appendChild(document.createTextNode(titl
eText.slice(i))); |
| 6682 } |
| 6683 }); |
| 6684 |
| 6685 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 6686 // Use of this source code is governed by a BSD-style license that can be |
| 6687 // found in the LICENSE file. |
| 6688 cr.define('md_history', function() { |
| 6689 var HistoryItem = Polymer({ |
| 6690 is: 'history-item', |
| 6691 properties: { |
| 6692 item: { |
| 6693 type: Object, |
| 6694 observer: 'showIcon_' |
| 6695 }, |
| 6696 searchTerm: { |
| 6697 type: String |
| 6698 }, |
| 6699 selected: { |
| 6700 type: Boolean, |
| 6701 notify: true |
| 6702 }, |
| 6703 isFirstItem: { |
| 6704 type: Boolean, |
| 6705 reflectToAttribute: true |
| 6706 }, |
| 6707 isCardStart: { |
| 6708 type: Boolean, |
| 6709 reflectToAttribute: true |
| 6710 }, |
| 6711 isCardEnd: { |
| 6712 type: Boolean, |
| 6713 reflectToAttribute: true |
| 6714 }, |
| 6715 embedded: { |
| 6716 type: Boolean, |
| 6717 reflectToAttribute: true |
| 6718 }, |
| 6719 hasTimeGap: { |
| 6720 type: Boolean |
| 6721 }, |
| 6722 numberOfItems: { |
| 6723 type: Number |
| 6724 }, |
| 6725 path: String |
| 6726 }, |
| 6727 onCheckboxSelected_: function() { |
| 6728 this.fire('history-checkbox-select', { |
| 6729 element: this, |
| 6730 countAddition: this.$.checkbox.checked ? 1 : -1 |
| 6731 }); |
| 6732 }, |
| 6733 onRemoveBookmarkTap_: function() { |
| 6734 if (!this.item.starred) return; |
| 6735 if (this.$$('#bookmark-star') == this.root.activeElement) this.$['menu-but
ton'].focus(); |
| 6736 md_history.BrowserService.getInstance().removeBookmark(this.item.url); |
| 6737 this.fire('remove-bookmark-stars', this.item.url); |
| 6738 }, |
| 6739 onMenuButtonTap_: function(e) { |
| 6740 this.fire('toggle-menu', { |
| 6741 target: Polymer.dom(e).localTarget, |
| 6742 item: this.item |
| 6743 }); |
| 6744 e.stopPropagation(); |
| 6745 }, |
| 6746 showIcon_: function() { |
| 6747 this.$.icon.style.backgroundImage = cr.icon.getFaviconImageSet(this.item.u
rl); |
| 6748 }, |
| 6749 selectionNotAllowed_: function() { |
| 6750 return !loadTimeData.getBoolean('allowDeletingHistory'); |
| 6751 }, |
| 6752 cardTitle_: function(numberOfItems, historyDate, search) { |
| 6753 if (!search) return this.item.dateRelativeDay; |
| 6754 var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults'; |
| 6755 return loadTimeData.getStringF('foundSearchResults', numberOfItems, loadTi
meData.getString(resultId), search); |
| 6756 }, |
| 6757 cropItemTitle_: function(title) { |
| 6758 return title.length > TITLE_MAX_LENGTH ? title.substr(0, TITLE_MAX_LENGTH)
: title; |
| 6759 } |
| 6760 }); |
| 6761 HistoryItem.needsTimeGap = function(visits, currentIndex, searchedTerm) { |
| 6762 if (currentIndex >= visits.length - 1 || visits.length == 0) return false; |
| 6763 var currentItem = visits[currentIndex]; |
| 6764 var nextItem = visits[currentIndex + 1]; |
| 6765 if (searchedTerm) return currentItem.dateShort != nextItem.dateShort; |
| 6766 return currentItem.time - nextItem.time > BROWSING_GAP_TIME && currentItem.d
ateRelativeDay == nextItem.dateRelativeDay; |
| 6767 }; |
| 6768 return { |
| 6769 HistoryItem: HistoryItem |
| 6770 }; |
| 6771 }); |
| 6772 |
| 6773 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 6774 // Use of this source code is governed by a BSD-style license that can be |
| 6775 // found in the LICENSE file. |
| 6776 var SelectionTreeNode = function(currentPath) { |
| 6777 this.currentPath = currentPath; |
| 6778 this.leaf = false; |
| 6779 this.indexes = []; |
| 6780 this.children = []; |
| 6781 }; |
| 6782 |
| 6783 SelectionTreeNode.prototype.addChild = function(index, path) { |
| 6784 this.indexes.push(index); |
| 6785 this.children[index] = new SelectionTreeNode(path); |
| 6786 }; |
| 6787 |
| 6788 var HistoryListBehavior = { |
| 6789 properties: { |
| 6790 selectedPaths: { |
| 6791 type: Array, |
| 6792 value: function() { |
| 6793 return []; |
| 6794 } |
| 6795 } |
| 6796 }, |
| 6797 listeners: { |
| 6798 'history-checkbox-select': 'itemSelected_' |
| 6799 }, |
| 6800 hasResults: function(historyDataLength) { |
| 6801 return historyDataLength > 0; |
| 6802 }, |
| 6803 noResultsMessage: function(searchedTerm, isLoading) { |
| 6804 if (isLoading) return ''; |
| 6805 var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults'; |
| 6806 return loadTimeData.getString(messageId); |
| 6807 }, |
| 6808 unselectAllItems: function() { |
| 6809 this.selectedPaths.forEach(function(path) { |
| 6810 this.set(path + '.selected', false); |
| 6811 }.bind(this)); |
| 6812 this.selectedPaths = []; |
| 6813 }, |
| 6814 deleteSelected: function() { |
| 6815 var toBeRemoved = this.selectedPaths.map(function(path) { |
| 6816 return this.get(path); |
| 6817 }.bind(this)); |
| 6818 md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(functi
on() { |
| 6819 this.removeItemsByPath(this.selectedPaths); |
| 6820 this.fire('unselect-all'); |
| 6821 }.bind(this)); |
| 6822 }, |
| 6823 removeItemsByPath: function(paths) { |
| 6824 if (paths.length == 0) return; |
| 6825 this.removeItemsBeneathNode_(this.buildRemovalTree_(paths)); |
| 6826 }, |
| 6827 buildRemovalTree_: function(paths) { |
| 6828 var rootNode = new SelectionTreeNode(paths[0].split('.')[0]); |
| 6829 paths.forEach(function(path) { |
| 6830 var components = path.split('.'); |
| 6831 var node = rootNode; |
| 6832 components.shift(); |
| 6833 while (components.length > 1) { |
| 6834 var index = Number(components.shift()); |
| 6835 var arrayName = components.shift(); |
| 6836 if (!node.children[index]) node.addChild(index, [ node.currentPath, inde
x, arrayName ].join('.')); |
| 6837 node = node.children[index]; |
| 6838 } |
| 6839 node.leaf = true; |
| 6840 node.indexes.push(Number(components.shift())); |
| 6841 }); |
| 6842 return rootNode; |
| 6843 }, |
| 6844 removeItemsBeneathNode_: function(node) { |
| 6845 var array = this.get(node.currentPath); |
| 6846 var splices = []; |
| 6847 node.indexes.sort(function(a, b) { |
| 6848 return b - a; |
| 6849 }); |
| 6850 node.indexes.forEach(function(index) { |
| 6851 if (node.leaf || this.removeItemsBeneathNode_(node.children[index])) { |
| 6852 var item = array.splice(index, 1); |
| 6853 splices.push({ |
| 6854 index: index, |
| 6855 removed: [ item ], |
| 6856 addedCount: 0, |
| 6857 object: array, |
| 6858 type: 'splice' |
| 6859 }); |
| 6860 } |
| 6861 }.bind(this)); |
| 6862 if (array.length == 0) return true; |
| 6863 this.notifySplices(node.currentPath, splices); |
| 6864 return false; |
| 6865 }, |
| 6866 itemSelected_: function(e) { |
| 6867 var item = e.detail.element; |
| 6868 var path = item.path; |
| 6869 if (item.selected) { |
| 6870 this.push('selectedPaths', path); |
| 6871 return; |
| 6872 } |
| 6873 var index = this.selectedPaths.indexOf(path); |
| 6874 if (index != -1) this.splice('selectedPaths', index, 1); |
| 6875 } |
| 6876 }; |
| 6877 |
| 6878 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 6879 // Use of this source code is governed by a BSD-style license that can be |
| 6880 // found in the LICENSE file. |
| 6881 var HistoryDomain; |
| 6882 |
| 6883 var HistoryGroup; |
| 6884 |
| 6885 Polymer({ |
| 6886 is: 'history-grouped-list', |
| 6887 behaviors: [ HistoryListBehavior ], |
| 6888 properties: { |
| 6889 historyData: { |
| 6890 type: Array |
| 6891 }, |
| 6892 groupedHistoryData_: { |
| 6893 type: Array |
| 6894 }, |
| 6895 searchedTerm: { |
| 6896 type: String, |
| 6897 value: '' |
| 6898 }, |
| 6899 range: { |
| 6900 type: Number |
| 6901 }, |
| 6902 queryStartTime: String, |
| 6903 queryEndTime: String |
| 6904 }, |
| 6905 observers: [ 'updateGroupedHistoryData_(range, historyData)' ], |
| 6906 createHistoryDomains_: function(visits) { |
| 6907 var domainIndexes = {}; |
| 6908 var domains = []; |
| 6909 for (var i = 0, visit; visit = visits[i]; i++) { |
| 6910 var domain = visit.domain; |
| 6911 if (domainIndexes[domain] == undefined) { |
| 6912 domainIndexes[domain] = domains.length; |
| 6913 domains.push({ |
| 6914 domain: domain, |
| 6915 visits: [], |
| 6916 expanded: false, |
| 6917 rendered: false |
| 6918 }); |
| 6919 } |
| 6920 domains[domainIndexes[domain]].visits.push(visit); |
| 6921 } |
| 6922 var sortByVisits = function(a, b) { |
| 6923 return b.visits.length - a.visits.length; |
| 6924 }; |
| 6925 domains.sort(sortByVisits); |
| 6926 return domains; |
| 6927 }, |
| 6928 updateGroupedHistoryData_: function() { |
| 6929 if (this.historyData.length == 0) { |
| 6930 this.groupedHistoryData_ = []; |
| 6931 return; |
| 6932 } |
| 6933 if (this.range == HistoryRange.WEEK) { |
| 6934 var days = []; |
| 6935 var currentDayVisits = [ this.historyData[0] ]; |
| 6936 var pushCurrentDay = function() { |
| 6937 days.push({ |
| 6938 title: this.searchedTerm ? currentDayVisits[0].dateShort : currentDayV
isits[0].dateRelativeDay, |
| 6939 domains: this.createHistoryDomains_(currentDayVisits) |
| 6940 }); |
| 6941 }.bind(this); |
| 6942 var visitsSameDay = function(a, b) { |
| 6943 if (this.searchedTerm) return a.dateShort == b.dateShort; |
| 6944 return a.dateRelativeDay == b.dateRelativeDay; |
| 6945 }.bind(this); |
| 6946 for (var i = 1; i < this.historyData.length; i++) { |
| 6947 var visit = this.historyData[i]; |
| 6948 if (!visitsSameDay(visit, currentDayVisits[0])) { |
| 6949 pushCurrentDay(); |
| 6950 currentDayVisits = []; |
| 6951 } |
| 6952 currentDayVisits.push(visit); |
| 6953 } |
| 6954 pushCurrentDay(); |
| 6955 this.groupedHistoryData_ = days; |
| 6956 } else if (this.range == HistoryRange.MONTH) { |
| 6957 this.groupedHistoryData_ = [ { |
| 6958 title: this.queryStartTime + ' – ' + this.queryEndTime, |
| 6959 domains: this.createHistoryDomains_(this.historyData) |
| 6960 } ]; |
| 6961 } |
| 6962 }, |
| 6963 toggleDomainExpanded_: function(e) { |
| 6964 var collapse = e.currentTarget.parentNode.querySelector('iron-collapse'); |
| 6965 e.model.set('domain.rendered', true); |
| 6966 setTimeout(function() { |
| 6967 collapse.toggle(); |
| 6968 }, 0); |
| 6969 }, |
| 6970 needsTimeGap_: function(groupIndex, domainIndex, itemIndex) { |
| 6971 var visits = this.groupedHistoryData_[groupIndex].domains[domainIndex].visit
s; |
| 6972 return md_history.HistoryItem.needsTimeGap(visits, itemIndex, this.searchedT
erm); |
| 6973 }, |
| 6974 pathForItem_: function(groupIndex, domainIndex, itemIndex) { |
| 6975 return [ 'groupedHistoryData_', groupIndex, 'domains', domainIndex, 'visits'
, itemIndex ].join('.'); |
| 6976 }, |
| 6977 getWebsiteIconStyle_: function(domain) { |
| 6978 return 'background-image: ' + cr.icon.getFaviconImageSet(domain.visits[0].ur
l); |
| 6979 }, |
| 6980 getDropdownIcon_: function(expanded) { |
| 6981 return expanded ? 'cr:expand-less' : 'cr:expand-more'; |
| 6982 } |
| 6983 }); |
| 6984 |
| 6985 Polymer.IronScrollTargetBehavior = { |
| 6986 properties: { |
| 6987 scrollTarget: { |
| 6988 type: HTMLElement, |
| 6989 value: function() { |
| 6990 return this._defaultScrollTarget; |
| 6991 } |
| 6992 } |
| 6993 }, |
| 6994 observers: [ '_scrollTargetChanged(scrollTarget, isAttached)' ], |
| 6995 _scrollTargetChanged: function(scrollTarget, isAttached) { |
| 6996 var eventTarget; |
| 6997 if (this._oldScrollTarget) { |
| 6998 eventTarget = this._oldScrollTarget === this._doc ? window : this._oldScro
llTarget; |
| 6999 eventTarget.removeEventListener('scroll', this._boundScrollHandler); |
| 7000 this._oldScrollTarget = null; |
| 7001 } |
| 7002 if (!isAttached) { |
| 7003 return; |
| 7004 } |
| 7005 if (scrollTarget === 'document') { |
| 7006 this.scrollTarget = this._doc; |
| 7007 } else if (typeof scrollTarget === 'string') { |
| 7008 this.scrollTarget = this.domHost ? this.domHost.$[scrollTarget] : Polymer.
dom(this.ownerDocument).querySelector('#' + scrollTarget); |
| 7009 } else if (this._isValidScrollTarget()) { |
| 7010 eventTarget = scrollTarget === this._doc ? window : scrollTarget; |
| 7011 this._boundScrollHandler = this._boundScrollHandler || this._scrollHandler
.bind(this); |
| 7012 this._oldScrollTarget = scrollTarget; |
| 7013 eventTarget.addEventListener('scroll', this._boundScrollHandler); |
| 7014 } |
| 7015 }, |
| 7016 _scrollHandler: function scrollHandler() {}, |
| 7017 get _defaultScrollTarget() { |
| 7018 return this._doc; |
| 7019 }, |
| 7020 get _doc() { |
| 7021 return this.ownerDocument.documentElement; |
| 7022 }, |
| 7023 get _scrollTop() { |
| 7024 if (this._isValidScrollTarget()) { |
| 7025 return this.scrollTarget === this._doc ? window.pageYOffset : this.scrollT
arget.scrollTop; |
| 7026 } |
| 7027 return 0; |
| 7028 }, |
| 7029 get _scrollLeft() { |
| 7030 if (this._isValidScrollTarget()) { |
| 7031 return this.scrollTarget === this._doc ? window.pageXOffset : this.scrollT
arget.scrollLeft; |
| 7032 } |
| 7033 return 0; |
| 7034 }, |
| 7035 set _scrollTop(top) { |
| 7036 if (this.scrollTarget === this._doc) { |
| 7037 window.scrollTo(window.pageXOffset, top); |
| 7038 } else if (this._isValidScrollTarget()) { |
| 7039 this.scrollTarget.scrollTop = top; |
| 7040 } |
| 7041 }, |
| 7042 set _scrollLeft(left) { |
| 7043 if (this.scrollTarget === this._doc) { |
| 7044 window.scrollTo(left, window.pageYOffset); |
| 7045 } else if (this._isValidScrollTarget()) { |
| 7046 this.scrollTarget.scrollLeft = left; |
| 7047 } |
| 7048 }, |
| 7049 scroll: function(left, top) { |
| 7050 if (this.scrollTarget === this._doc) { |
| 7051 window.scrollTo(left, top); |
| 7052 } else if (this._isValidScrollTarget()) { |
| 7053 this.scrollTarget.scrollLeft = left; |
| 7054 this.scrollTarget.scrollTop = top; |
| 7055 } |
| 7056 }, |
| 7057 get _scrollTargetWidth() { |
| 7058 if (this._isValidScrollTarget()) { |
| 7059 return this.scrollTarget === this._doc ? window.innerWidth : this.scrollTa
rget.offsetWidth; |
| 7060 } |
| 7061 return 0; |
| 7062 }, |
| 7063 get _scrollTargetHeight() { |
| 7064 if (this._isValidScrollTarget()) { |
| 7065 return this.scrollTarget === this._doc ? window.innerHeight : this.scrollT
arget.offsetHeight; |
| 7066 } |
| 7067 return 0; |
| 7068 }, |
| 7069 _isValidScrollTarget: function() { |
| 7070 return this.scrollTarget instanceof HTMLElement; |
| 7071 } |
| 7072 }; |
| 7073 |
| 7074 (function() { |
| 7075 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/); |
| 7076 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8; |
| 7077 var DEFAULT_PHYSICAL_COUNT = 3; |
| 7078 var HIDDEN_Y = '-10000px'; |
| 7079 var DEFAULT_GRID_SIZE = 200; |
| 7080 var SECRET_TABINDEX = -100; |
| 7081 Polymer({ |
| 7082 is: 'iron-list', |
| 7083 properties: { |
| 7084 items: { |
| 7085 type: Array |
| 7086 }, |
| 7087 maxPhysicalCount: { |
| 7088 type: Number, |
| 7089 value: 500 |
| 7090 }, |
| 7091 as: { |
| 7092 type: String, |
| 7093 value: 'item' |
| 7094 }, |
| 7095 indexAs: { |
| 7096 type: String, |
| 7097 value: 'index' |
| 7098 }, |
| 7099 selectedAs: { |
| 7100 type: String, |
| 7101 value: 'selected' |
| 7102 }, |
| 7103 grid: { |
| 7104 type: Boolean, |
| 7105 value: false, |
| 7106 reflectToAttribute: true |
| 7107 }, |
| 7108 selectionEnabled: { |
| 7109 type: Boolean, |
| 7110 value: false |
| 7111 }, |
| 7112 selectedItem: { |
| 7113 type: Object, |
| 7114 notify: true |
| 7115 }, |
| 7116 selectedItems: { |
| 7117 type: Object, |
| 7118 notify: true |
| 7119 }, |
| 7120 multiSelection: { |
| 7121 type: Boolean, |
| 7122 value: false |
| 7123 } |
| 7124 }, |
| 7125 observers: [ '_itemsChanged(items.*)', '_selectionEnabledChanged(selectionEn
abled)', '_multiSelectionChanged(multiSelection)', '_setOverflow(scrollTarget)'
], |
| 7126 behaviors: [ Polymer.Templatizer, Polymer.IronResizableBehavior, Polymer.Iro
nA11yKeysBehavior, Polymer.IronScrollTargetBehavior ], |
| 7127 keyBindings: { |
| 7128 up: '_didMoveUp', |
| 7129 down: '_didMoveDown', |
| 7130 enter: '_didEnter' |
| 7131 }, |
| 7132 _ratio: .5, |
| 7133 _scrollerPaddingTop: 0, |
| 7134 _scrollPosition: 0, |
| 7135 _physicalSize: 0, |
| 7136 _physicalAverage: 0, |
| 7137 _physicalAverageCount: 0, |
| 7138 _physicalTop: 0, |
| 7139 _virtualCount: 0, |
| 7140 _physicalIndexForKey: null, |
| 7141 _estScrollHeight: 0, |
| 7142 _scrollHeight: 0, |
| 7143 _viewportHeight: 0, |
| 7144 _viewportWidth: 0, |
| 7145 _physicalItems: null, |
| 7146 _physicalSizes: null, |
| 7147 _firstVisibleIndexVal: null, |
| 7148 _lastVisibleIndexVal: null, |
| 7149 _collection: null, |
| 7150 _itemsRendered: false, |
| 7151 _lastPage: null, |
| 7152 _maxPages: 3, |
| 7153 _focusedItem: null, |
| 7154 _focusedIndex: -1, |
| 7155 _offscreenFocusedItem: null, |
| 7156 _focusBackfillItem: null, |
| 7157 _itemsPerRow: 1, |
| 7158 _itemWidth: 0, |
| 7159 _rowHeight: 0, |
| 7160 get _physicalBottom() { |
| 7161 return this._physicalTop + this._physicalSize; |
| 7162 }, |
| 7163 get _scrollBottom() { |
| 7164 return this._scrollPosition + this._viewportHeight; |
| 7165 }, |
| 7166 get _virtualEnd() { |
| 7167 return this._virtualStart + this._physicalCount - 1; |
| 7168 }, |
| 7169 get _hiddenContentSize() { |
| 7170 var size = this.grid ? this._physicalRows * this._rowHeight : this._physic
alSize; |
| 7171 return size - this._viewportHeight; |
| 7172 }, |
| 7173 get _maxScrollTop() { |
| 7174 return this._estScrollHeight - this._viewportHeight + this._scrollerPaddin
gTop; |
| 7175 }, |
| 7176 _minVirtualStart: 0, |
| 7177 get _maxVirtualStart() { |
| 7178 return Math.max(0, this._virtualCount - this._physicalCount); |
| 7179 }, |
| 7180 _virtualStartVal: 0, |
| 7181 set _virtualStart(val) { |
| 7182 this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._min
VirtualStart, val)); |
| 7183 }, |
| 7184 get _virtualStart() { |
| 7185 return this._virtualStartVal || 0; |
| 7186 }, |
| 7187 _physicalStartVal: 0, |
| 7188 set _physicalStart(val) { |
| 7189 this._physicalStartVal = val % this._physicalCount; |
| 7190 if (this._physicalStartVal < 0) { |
| 7191 this._physicalStartVal = this._physicalCount + this._physicalStartVal; |
| 7192 } |
| 7193 this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this
._physicalCount; |
| 7194 }, |
| 7195 get _physicalStart() { |
| 7196 return this._physicalStartVal || 0; |
| 7197 }, |
| 7198 _physicalCountVal: 0, |
| 7199 set _physicalCount(val) { |
| 7200 this._physicalCountVal = val; |
| 7201 this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this
._physicalCount; |
| 7202 }, |
| 7203 get _physicalCount() { |
| 7204 return this._physicalCountVal; |
| 7205 }, |
| 7206 _physicalEnd: 0, |
| 7207 get _optPhysicalSize() { |
| 7208 if (this.grid) { |
| 7209 return this._estRowsInView * this._rowHeight * this._maxPages; |
| 7210 } |
| 7211 return this._viewportHeight * this._maxPages; |
| 7212 }, |
| 7213 get _optPhysicalCount() { |
| 7214 return this._estRowsInView * this._itemsPerRow * this._maxPages; |
| 7215 }, |
| 7216 get _isVisible() { |
| 7217 return this.scrollTarget && Boolean(this.scrollTarget.offsetWidth || this.
scrollTarget.offsetHeight); |
| 7218 }, |
| 7219 get firstVisibleIndex() { |
| 7220 if (this._firstVisibleIndexVal === null) { |
| 7221 var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddin
gTop); |
| 7222 this._firstVisibleIndexVal = this._iterateItems(function(pidx, vidx) { |
| 7223 physicalOffset += this._getPhysicalSizeIncrement(pidx); |
| 7224 if (physicalOffset > this._scrollPosition) { |
| 7225 return this.grid ? vidx - vidx % this._itemsPerRow : vidx; |
| 7226 } |
| 7227 if (this.grid && this._virtualCount - 1 === vidx) { |
| 7228 return vidx - vidx % this._itemsPerRow; |
| 7229 } |
| 7230 }) || 0; |
| 7231 } |
| 7232 return this._firstVisibleIndexVal; |
| 7233 }, |
| 7234 get lastVisibleIndex() { |
| 7235 if (this._lastVisibleIndexVal === null) { |
| 7236 if (this.grid) { |
| 7237 var lastIndex = this.firstVisibleIndex + this._estRowsInView * this._i
temsPerRow - 1; |
| 7238 this._lastVisibleIndexVal = Math.min(this._virtualCount, lastIndex); |
| 7239 } else { |
| 7240 var physicalOffset = this._physicalTop; |
| 7241 this._iterateItems(function(pidx, vidx) { |
| 7242 if (physicalOffset < this._scrollBottom) { |
| 7243 this._lastVisibleIndexVal = vidx; |
| 7244 } else { |
| 7245 return true; |
| 7246 } |
| 7247 physicalOffset += this._getPhysicalSizeIncrement(pidx); |
| 7248 }); |
| 7249 } |
| 7250 } |
| 7251 return this._lastVisibleIndexVal; |
| 7252 }, |
| 7253 get _defaultScrollTarget() { |
| 7254 return this; |
| 7255 }, |
| 7256 get _virtualRowCount() { |
| 7257 return Math.ceil(this._virtualCount / this._itemsPerRow); |
| 7258 }, |
| 7259 get _estRowsInView() { |
| 7260 return Math.ceil(this._viewportHeight / this._rowHeight); |
| 7261 }, |
| 7262 get _physicalRows() { |
| 7263 return Math.ceil(this._physicalCount / this._itemsPerRow); |
| 7264 }, |
| 7265 ready: function() { |
| 7266 this.addEventListener('focus', this._didFocus.bind(this), true); |
| 7267 }, |
| 7268 attached: function() { |
| 7269 this.updateViewportBoundaries(); |
| 7270 this._render(); |
| 7271 this.listen(this, 'iron-resize', '_resizeHandler'); |
| 7272 }, |
| 7273 detached: function() { |
| 7274 this._itemsRendered = false; |
| 7275 this.unlisten(this, 'iron-resize', '_resizeHandler'); |
| 7276 }, |
| 7277 _setOverflow: function(scrollTarget) { |
| 7278 this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : ''; |
| 7279 this.style.overflow = scrollTarget === this ? 'auto' : ''; |
| 7280 }, |
| 7281 updateViewportBoundaries: function() { |
| 7282 this._scrollerPaddingTop = this.scrollTarget === this ? 0 : parseInt(windo
w.getComputedStyle(this)['padding-top'], 10); |
| 7283 this._viewportHeight = this._scrollTargetHeight; |
| 7284 if (this.grid) { |
| 7285 this._updateGridMetrics(); |
| 7286 } |
| 7287 }, |
| 7288 _scrollHandler: function() { |
| 7289 var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop))
; |
| 7290 var delta = scrollTop - this._scrollPosition; |
| 7291 var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBotto
m; |
| 7292 var ratio = this._ratio; |
| 7293 var recycledTiles = 0; |
| 7294 var hiddenContentSize = this._hiddenContentSize; |
| 7295 var currentRatio = ratio; |
| 7296 var movingUp = []; |
| 7297 this._scrollPosition = scrollTop; |
| 7298 this._firstVisibleIndexVal = null; |
| 7299 this._lastVisibleIndexVal = null; |
| 7300 scrollBottom = this._scrollBottom; |
| 7301 physicalBottom = this._physicalBottom; |
| 7302 if (Math.abs(delta) > this._physicalSize) { |
| 7303 this._physicalTop += delta; |
| 7304 recycledTiles = Math.round(delta / this._physicalAverage); |
| 7305 } else if (delta < 0) { |
| 7306 var topSpace = scrollTop - this._physicalTop; |
| 7307 var virtualStart = this._virtualStart; |
| 7308 recycledTileSet = []; |
| 7309 kth = this._physicalEnd; |
| 7310 currentRatio = topSpace / hiddenContentSize; |
| 7311 while (currentRatio < ratio && recycledTiles < this._physicalCount && vi
rtualStart - recycledTiles > 0 && physicalBottom - this._getPhysicalSizeIncremen
t(kth) > scrollBottom) { |
| 7312 tileHeight = this._getPhysicalSizeIncrement(kth); |
| 7313 currentRatio += tileHeight / hiddenContentSize; |
| 7314 physicalBottom -= tileHeight; |
| 7315 recycledTileSet.push(kth); |
| 7316 recycledTiles++; |
| 7317 kth = kth === 0 ? this._physicalCount - 1 : kth - 1; |
| 7318 } |
| 7319 movingUp = recycledTileSet; |
| 7320 recycledTiles = -recycledTiles; |
| 7321 } else if (delta > 0) { |
| 7322 var bottomSpace = physicalBottom - scrollBottom; |
| 7323 var virtualEnd = this._virtualEnd; |
| 7324 var lastVirtualItemIndex = this._virtualCount - 1; |
| 7325 recycledTileSet = []; |
| 7326 kth = this._physicalStart; |
| 7327 currentRatio = bottomSpace / hiddenContentSize; |
| 7328 while (currentRatio < ratio && recycledTiles < this._physicalCount && vi
rtualEnd + recycledTiles < lastVirtualItemIndex && this._physicalTop + this._get
PhysicalSizeIncrement(kth) < scrollTop) { |
| 7329 tileHeight = this._getPhysicalSizeIncrement(kth); |
| 7330 currentRatio += tileHeight / hiddenContentSize; |
| 7331 this._physicalTop += tileHeight; |
| 7332 recycledTileSet.push(kth); |
| 7333 recycledTiles++; |
| 7334 kth = (kth + 1) % this._physicalCount; |
| 7335 } |
| 7336 } |
| 7337 if (recycledTiles === 0) { |
| 7338 if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) { |
| 7339 this._increasePoolIfNeeded(); |
| 7340 } |
| 7341 } else { |
| 7342 this._virtualStart = this._virtualStart + recycledTiles; |
| 7343 this._physicalStart = this._physicalStart + recycledTiles; |
| 7344 this._update(recycledTileSet, movingUp); |
| 7345 } |
| 7346 }, |
| 7347 _update: function(itemSet, movingUp) { |
| 7348 this._manageFocus(); |
| 7349 this._assignModels(itemSet); |
| 7350 this._updateMetrics(itemSet); |
| 7351 if (movingUp) { |
| 7352 while (movingUp.length) { |
| 7353 var idx = movingUp.pop(); |
| 7354 this._physicalTop -= this._getPhysicalSizeIncrement(idx); |
| 7355 } |
| 7356 } |
| 7357 this._positionItems(); |
| 7358 this._updateScrollerSize(); |
| 7359 this._increasePoolIfNeeded(); |
| 7360 }, |
| 7361 _createPool: function(size) { |
| 7362 var physicalItems = new Array(size); |
| 7363 this._ensureTemplatized(); |
| 7364 for (var i = 0; i < size; i++) { |
| 7365 var inst = this.stamp(null); |
| 7366 physicalItems[i] = inst.root.querySelector('*'); |
| 7367 Polymer.dom(this).appendChild(inst.root); |
| 7368 } |
| 7369 return physicalItems; |
| 7370 }, |
| 7371 _increasePoolIfNeeded: function() { |
| 7372 if (this._viewportHeight === 0) { |
| 7373 return false; |
| 7374 } |
| 7375 var isClientHeightFull = this._physicalBottom >= this._scrollBottom && thi
s._physicalTop <= this._scrollPosition; |
| 7376 if (this._physicalSize >= this._optPhysicalSize && isClientHeightFull) { |
| 7377 return false; |
| 7378 } |
| 7379 var currentPage = Math.floor(this._physicalSize / this._viewportHeight); |
| 7380 if (currentPage === 0) { |
| 7381 this._debounceTemplate(this._increasePool.bind(this, Math.round(this._ph
ysicalCount * .5))); |
| 7382 } else if (this._lastPage !== currentPage && isClientHeightFull) { |
| 7383 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increa
sePool.bind(this, this._itemsPerRow), 16)); |
| 7384 } else { |
| 7385 this._debounceTemplate(this._increasePool.bind(this, this._itemsPerRow))
; |
| 7386 } |
| 7387 this._lastPage = currentPage; |
| 7388 return true; |
| 7389 }, |
| 7390 _increasePool: function(missingItems) { |
| 7391 var nextPhysicalCount = Math.min(this._physicalCount + missingItems, this.
_virtualCount - this._virtualStart, Math.max(this.maxPhysicalCount, DEFAULT_PHYS
ICAL_COUNT)); |
| 7392 var prevPhysicalCount = this._physicalCount; |
| 7393 var delta = nextPhysicalCount - prevPhysicalCount; |
| 7394 if (delta <= 0) { |
| 7395 return; |
| 7396 } |
| 7397 [].push.apply(this._physicalItems, this._createPool(delta)); |
| 7398 [].push.apply(this._physicalSizes, new Array(delta)); |
| 7399 this._physicalCount = prevPhysicalCount + delta; |
| 7400 if (this._physicalStart > this._physicalEnd && this._isIndexRendered(this.
_focusedIndex) && this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd
) { |
| 7401 this._physicalStart = this._physicalStart + delta; |
| 7402 } |
| 7403 this._update(); |
| 7404 }, |
| 7405 _render: function() { |
| 7406 var requiresUpdate = this._virtualCount > 0 || this._physicalCount > 0; |
| 7407 if (this.isAttached && !this._itemsRendered && this._isVisible && requires
Update) { |
| 7408 this._lastPage = 0; |
| 7409 this._update(); |
| 7410 this._itemsRendered = true; |
| 7411 } |
| 7412 }, |
| 7413 _ensureTemplatized: function() { |
| 7414 if (!this.ctor) { |
| 7415 var props = {}; |
| 7416 props.__key__ = true; |
| 7417 props[this.as] = true; |
| 7418 props[this.indexAs] = true; |
| 7419 props[this.selectedAs] = true; |
| 7420 props.tabIndex = true; |
| 7421 this._instanceProps = props; |
| 7422 this._userTemplate = Polymer.dom(this).querySelector('template'); |
| 7423 if (this._userTemplate) { |
| 7424 this.templatize(this._userTemplate); |
| 7425 } else { |
| 7426 console.warn('iron-list requires a template to be provided in light-do
m'); |
| 7427 } |
| 7428 } |
| 7429 }, |
| 7430 _getStampedChildren: function() { |
| 7431 return this._physicalItems; |
| 7432 }, |
| 7433 _forwardInstancePath: function(inst, path, value) { |
| 7434 if (path.indexOf(this.as + '.') === 0) { |
| 7435 this.notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.lengt
h + 1), value); |
| 7436 } |
| 7437 }, |
| 7438 _forwardParentProp: function(prop, value) { |
| 7439 if (this._physicalItems) { |
| 7440 this._physicalItems.forEach(function(item) { |
| 7441 item._templateInstance[prop] = value; |
| 7442 }, this); |
| 7443 } |
| 7444 }, |
| 7445 _forwardParentPath: function(path, value) { |
| 7446 if (this._physicalItems) { |
| 7447 this._physicalItems.forEach(function(item) { |
| 7448 item._templateInstance.notifyPath(path, value, true); |
| 7449 }, this); |
| 7450 } |
| 7451 }, |
| 7452 _forwardItemPath: function(path, value) { |
| 7453 if (!this._physicalIndexForKey) { |
| 7454 return; |
| 7455 } |
| 7456 var dot = path.indexOf('.'); |
| 7457 var key = path.substring(0, dot < 0 ? path.length : dot); |
| 7458 var idx = this._physicalIndexForKey[key]; |
| 7459 var offscreenItem = this._offscreenFocusedItem; |
| 7460 var el = offscreenItem && offscreenItem._templateInstance.__key__ === key
? offscreenItem : this._physicalItems[idx]; |
| 7461 if (!el || el._templateInstance.__key__ !== key) { |
| 7462 return; |
| 7463 } |
| 7464 if (dot >= 0) { |
| 7465 path = this.as + '.' + path.substring(dot + 1); |
| 7466 el._templateInstance.notifyPath(path, value, true); |
| 7467 } else { |
| 7468 var currentItem = el._templateInstance[this.as]; |
| 7469 if (Array.isArray(this.selectedItems)) { |
| 7470 for (var i = 0; i < this.selectedItems.length; i++) { |
| 7471 if (this.selectedItems[i] === currentItem) { |
| 7472 this.set('selectedItems.' + i, value); |
| 7473 break; |
| 7474 } |
| 7475 } |
| 7476 } else if (this.selectedItem === currentItem) { |
| 7477 this.set('selectedItem', value); |
| 7478 } |
| 7479 el._templateInstance[this.as] = value; |
| 7480 } |
| 7481 }, |
| 7482 _itemsChanged: function(change) { |
| 7483 if (change.path === 'items') { |
| 7484 this._virtualStart = 0; |
| 7485 this._physicalTop = 0; |
| 7486 this._virtualCount = this.items ? this.items.length : 0; |
| 7487 this._collection = this.items ? Polymer.Collection.get(this.items) : nul
l; |
| 7488 this._physicalIndexForKey = {}; |
| 7489 this._firstVisibleIndexVal = null; |
| 7490 this._lastVisibleIndexVal = null; |
| 7491 this._resetScrollPosition(0); |
| 7492 this._removeFocusedItem(); |
| 7493 if (!this._physicalItems) { |
| 7494 this._physicalCount = Math.max(1, Math.min(DEFAULT_PHYSICAL_COUNT, thi
s._virtualCount)); |
| 7495 this._physicalItems = this._createPool(this._physicalCount); |
| 7496 this._physicalSizes = new Array(this._physicalCount); |
| 7497 } |
| 7498 this._physicalStart = 0; |
| 7499 } else if (change.path === 'items.splices') { |
| 7500 this._adjustVirtualIndex(change.value.indexSplices); |
| 7501 this._virtualCount = this.items ? this.items.length : 0; |
| 7502 } else { |
| 7503 this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.
value); |
| 7504 return; |
| 7505 } |
| 7506 this._itemsRendered = false; |
| 7507 this._debounceTemplate(this._render); |
| 7508 }, |
| 7509 _adjustVirtualIndex: function(splices) { |
| 7510 splices.forEach(function(splice) { |
| 7511 splice.removed.forEach(this._removeItem, this); |
| 7512 if (splice.index < this._virtualStart) { |
| 7513 var delta = Math.max(splice.addedCount - splice.removed.length, splice
.index - this._virtualStart); |
| 7514 this._virtualStart = this._virtualStart + delta; |
| 7515 if (this._focusedIndex >= 0) { |
| 7516 this._focusedIndex = this._focusedIndex + delta; |
| 7517 } |
| 7518 } |
| 7519 }, this); |
| 7520 }, |
| 7521 _removeItem: function(item) { |
| 7522 this.$.selector.deselect(item); |
| 7523 if (this._focusedItem && this._focusedItem._templateInstance[this.as] ===
item) { |
| 7524 this._removeFocusedItem(); |
| 7525 } |
| 7526 }, |
| 7527 _iterateItems: function(fn, itemSet) { |
| 7528 var pidx, vidx, rtn, i; |
| 7529 if (arguments.length === 2 && itemSet) { |
| 7530 for (i = 0; i < itemSet.length; i++) { |
| 7531 pidx = itemSet[i]; |
| 7532 vidx = this._computeVidx(pidx); |
| 7533 if ((rtn = fn.call(this, pidx, vidx)) != null) { |
| 7534 return rtn; |
| 7535 } |
| 7536 } |
| 7537 } else { |
| 7538 pidx = this._physicalStart; |
| 7539 vidx = this._virtualStart; |
| 7540 for (;pidx < this._physicalCount; pidx++, vidx++) { |
| 7541 if ((rtn = fn.call(this, pidx, vidx)) != null) { |
| 7542 return rtn; |
| 7543 } |
| 7544 } |
| 7545 for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) { |
| 7546 if ((rtn = fn.call(this, pidx, vidx)) != null) { |
| 7547 return rtn; |
| 7548 } |
| 7549 } |
| 7550 } |
| 7551 }, |
| 7552 _computeVidx: function(pidx) { |
| 7553 if (pidx >= this._physicalStart) { |
| 7554 return this._virtualStart + (pidx - this._physicalStart); |
| 7555 } |
| 7556 return this._virtualStart + (this._physicalCount - this._physicalStart) +
pidx; |
| 7557 }, |
| 7558 _assignModels: function(itemSet) { |
| 7559 this._iterateItems(function(pidx, vidx) { |
| 7560 var el = this._physicalItems[pidx]; |
| 7561 var inst = el._templateInstance; |
| 7562 var item = this.items && this.items[vidx]; |
| 7563 if (item != null) { |
| 7564 inst[this.as] = item; |
| 7565 inst.__key__ = this._collection.getKey(item); |
| 7566 inst[this.selectedAs] = this.$.selector.isSelected(item); |
| 7567 inst[this.indexAs] = vidx; |
| 7568 inst.tabIndex = this._focusedIndex === vidx ? 0 : -1; |
| 7569 this._physicalIndexForKey[inst.__key__] = pidx; |
| 7570 el.removeAttribute('hidden'); |
| 7571 } else { |
| 7572 inst.__key__ = null; |
| 7573 el.setAttribute('hidden', ''); |
| 7574 } |
| 7575 }, itemSet); |
| 7576 }, |
| 7577 _updateMetrics: function(itemSet) { |
| 7578 Polymer.dom.flush(); |
| 7579 var newPhysicalSize = 0; |
| 7580 var oldPhysicalSize = 0; |
| 7581 var prevAvgCount = this._physicalAverageCount; |
| 7582 var prevPhysicalAvg = this._physicalAverage; |
| 7583 this._iterateItems(function(pidx, vidx) { |
| 7584 oldPhysicalSize += this._physicalSizes[pidx] || 0; |
| 7585 this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight; |
| 7586 newPhysicalSize += this._physicalSizes[pidx]; |
| 7587 this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0; |
| 7588 }, itemSet); |
| 7589 this._viewportHeight = this._scrollTargetHeight; |
| 7590 if (this.grid) { |
| 7591 this._updateGridMetrics(); |
| 7592 this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow)
* this._rowHeight; |
| 7593 } else { |
| 7594 this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalS
ize; |
| 7595 } |
| 7596 if (this._physicalAverageCount !== prevAvgCount) { |
| 7597 this._physicalAverage = Math.round((prevPhysicalAvg * prevAvgCount + new
PhysicalSize) / this._physicalAverageCount); |
| 7598 } |
| 7599 }, |
| 7600 _updateGridMetrics: function() { |
| 7601 this._viewportWidth = this.$.items.offsetWidth; |
| 7602 this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoun
dingClientRect().width : DEFAULT_GRID_SIZE; |
| 7603 this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetH
eight : DEFAULT_GRID_SIZE; |
| 7604 this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / thi
s._itemWidth) : this._itemsPerRow; |
| 7605 }, |
| 7606 _positionItems: function() { |
| 7607 this._adjustScrollPosition(); |
| 7608 var y = this._physicalTop; |
| 7609 if (this.grid) { |
| 7610 var totalItemWidth = this._itemsPerRow * this._itemWidth; |
| 7611 var rowOffset = (this._viewportWidth - totalItemWidth) / 2; |
| 7612 this._iterateItems(function(pidx, vidx) { |
| 7613 var modulus = vidx % this._itemsPerRow; |
| 7614 var x = Math.floor(modulus * this._itemWidth + rowOffset); |
| 7615 this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]); |
| 7616 if (this._shouldRenderNextRow(vidx)) { |
| 7617 y += this._rowHeight; |
| 7618 } |
| 7619 }); |
| 7620 } else { |
| 7621 this._iterateItems(function(pidx, vidx) { |
| 7622 this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]); |
| 7623 y += this._physicalSizes[pidx]; |
| 7624 }); |
| 7625 } |
| 7626 }, |
| 7627 _getPhysicalSizeIncrement: function(pidx) { |
| 7628 if (!this.grid) { |
| 7629 return this._physicalSizes[pidx]; |
| 7630 } |
| 7631 if (this._computeVidx(pidx) % this._itemsPerRow !== this._itemsPerRow - 1)
{ |
| 7632 return 0; |
| 7633 } |
| 7634 return this._rowHeight; |
| 7635 }, |
| 7636 _shouldRenderNextRow: function(vidx) { |
| 7637 return vidx % this._itemsPerRow === this._itemsPerRow - 1; |
| 7638 }, |
| 7639 _adjustScrollPosition: function() { |
| 7640 var deltaHeight = this._virtualStart === 0 ? this._physicalTop : Math.min(
this._scrollPosition + this._physicalTop, 0); |
| 7641 if (deltaHeight) { |
| 7642 this._physicalTop = this._physicalTop - deltaHeight; |
| 7643 if (!IOS_TOUCH_SCROLLING && this._physicalTop !== 0) { |
| 7644 this._resetScrollPosition(this._scrollTop - deltaHeight); |
| 7645 } |
| 7646 } |
| 7647 }, |
| 7648 _resetScrollPosition: function(pos) { |
| 7649 if (this.scrollTarget) { |
| 7650 this._scrollTop = pos; |
| 7651 this._scrollPosition = this._scrollTop; |
| 7652 } |
| 7653 }, |
| 7654 _updateScrollerSize: function(forceUpdate) { |
| 7655 if (this.grid) { |
| 7656 this._estScrollHeight = this._virtualRowCount * this._rowHeight; |
| 7657 } else { |
| 7658 this._estScrollHeight = this._physicalBottom + Math.max(this._virtualCou
nt - this._physicalCount - this._virtualStart, 0) * this._physicalAverage; |
| 7659 } |
| 7660 forceUpdate = forceUpdate || this._scrollHeight === 0; |
| 7661 forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight
- this._physicalSize; |
| 7662 forceUpdate = forceUpdate || this.grid && this.$.items.style.height < this
._estScrollHeight; |
| 7663 if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >=
this._optPhysicalSize) { |
| 7664 this.$.items.style.height = this._estScrollHeight + 'px'; |
| 7665 this._scrollHeight = this._estScrollHeight; |
| 7666 } |
| 7667 }, |
| 7668 scrollToItem: function(item) { |
| 7669 return this.scrollToIndex(this.items.indexOf(item)); |
| 7670 }, |
| 7671 scrollToIndex: function(idx) { |
| 7672 if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) { |
| 7673 return; |
| 7674 } |
| 7675 Polymer.dom.flush(); |
| 7676 idx = Math.min(Math.max(idx, 0), this._virtualCount - 1); |
| 7677 if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) { |
| 7678 this._virtualStart = this.grid ? idx - this._itemsPerRow * 2 : idx - 1; |
| 7679 } |
| 7680 this._manageFocus(); |
| 7681 this._assignModels(); |
| 7682 this._updateMetrics(); |
| 7683 var estPhysicalTop = Math.floor(this._virtualStart / this._itemsPerRow) *
this._physicalAverage; |
| 7684 this._physicalTop = estPhysicalTop; |
| 7685 var currentTopItem = this._physicalStart; |
| 7686 var currentVirtualItem = this._virtualStart; |
| 7687 var targetOffsetTop = 0; |
| 7688 var hiddenContentSize = this._hiddenContentSize; |
| 7689 while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) { |
| 7690 targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(curre
ntTopItem); |
| 7691 currentTopItem = (currentTopItem + 1) % this._physicalCount; |
| 7692 currentVirtualItem++; |
| 7693 } |
| 7694 this._updateScrollerSize(true); |
| 7695 this._positionItems(); |
| 7696 this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + t
argetOffsetTop); |
| 7697 this._increasePoolIfNeeded(); |
| 7698 this._firstVisibleIndexVal = null; |
| 7699 this._lastVisibleIndexVal = null; |
| 7700 }, |
| 7701 _resetAverage: function() { |
| 7702 this._physicalAverage = 0; |
| 7703 this._physicalAverageCount = 0; |
| 7704 }, |
| 7705 _resizeHandler: function() { |
| 7706 if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100
) { |
| 7707 return; |
| 7708 } |
| 7709 Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() { |
| 7710 this.updateViewportBoundaries(); |
| 7711 this._render(); |
| 7712 if (this._itemsRendered && this._physicalItems && this._isVisible) { |
| 7713 this._resetAverage(); |
| 7714 this.scrollToIndex(this.firstVisibleIndex); |
| 7715 } |
| 7716 }.bind(this), 1)); |
| 7717 }, |
| 7718 _getModelFromItem: function(item) { |
| 7719 var key = this._collection.getKey(item); |
| 7720 var pidx = this._physicalIndexForKey[key]; |
| 7721 if (pidx != null) { |
| 7722 return this._physicalItems[pidx]._templateInstance; |
| 7723 } |
| 7724 return null; |
| 7725 }, |
| 7726 _getNormalizedItem: function(item) { |
| 7727 if (this._collection.getKey(item) === undefined) { |
| 7728 if (typeof item === 'number') { |
| 7729 item = this.items[item]; |
| 7730 if (!item) { |
| 7731 throw new RangeError('<item> not found'); |
| 7732 } |
| 7733 return item; |
| 7734 } |
| 7735 throw new TypeError('<item> should be a valid item'); |
| 7736 } |
| 7737 return item; |
| 7738 }, |
| 7739 selectItem: function(item) { |
| 7740 item = this._getNormalizedItem(item); |
| 7741 var model = this._getModelFromItem(item); |
| 7742 if (!this.multiSelection && this.selectedItem) { |
| 7743 this.deselectItem(this.selectedItem); |
| 7744 } |
| 7745 if (model) { |
| 7746 model[this.selectedAs] = true; |
| 7747 } |
| 7748 this.$.selector.select(item); |
| 7749 this.updateSizeForItem(item); |
| 7750 }, |
| 7751 deselectItem: function(item) { |
| 7752 item = this._getNormalizedItem(item); |
| 7753 var model = this._getModelFromItem(item); |
| 7754 if (model) { |
| 7755 model[this.selectedAs] = false; |
| 7756 } |
| 7757 this.$.selector.deselect(item); |
| 7758 this.updateSizeForItem(item); |
| 7759 }, |
| 7760 toggleSelectionForItem: function(item) { |
| 7761 item = this._getNormalizedItem(item); |
| 7762 if (this.$.selector.isSelected(item)) { |
| 7763 this.deselectItem(item); |
| 7764 } else { |
| 7765 this.selectItem(item); |
| 7766 } |
| 7767 }, |
| 7768 clearSelection: function() { |
| 7769 function unselect(item) { |
| 7770 var model = this._getModelFromItem(item); |
| 7771 if (model) { |
| 7772 model[this.selectedAs] = false; |
| 7773 } |
| 7774 } |
| 7775 if (Array.isArray(this.selectedItems)) { |
| 7776 this.selectedItems.forEach(unselect, this); |
| 7777 } else if (this.selectedItem) { |
| 7778 unselect.call(this, this.selectedItem); |
| 7779 } |
| 7780 this.$.selector.clearSelection(); |
| 7781 }, |
| 7782 _selectionEnabledChanged: function(selectionEnabled) { |
| 7783 var handler = selectionEnabled ? this.listen : this.unlisten; |
| 7784 handler.call(this, this, 'tap', '_selectionHandler'); |
| 7785 }, |
| 7786 _selectionHandler: function(e) { |
| 7787 var model = this.modelForElement(e.target); |
| 7788 if (!model) { |
| 7789 return; |
| 7790 } |
| 7791 var modelTabIndex, activeElTabIndex; |
| 7792 var target = Polymer.dom(e).path[0]; |
| 7793 var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).ac
tiveElement; |
| 7794 var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.i
ndexAs])]; |
| 7795 if (target.localName === 'input' || target.localName === 'button' || targe
t.localName === 'select') { |
| 7796 return; |
| 7797 } |
| 7798 modelTabIndex = model.tabIndex; |
| 7799 model.tabIndex = SECRET_TABINDEX; |
| 7800 activeElTabIndex = activeEl ? activeEl.tabIndex : -1; |
| 7801 model.tabIndex = modelTabIndex; |
| 7802 if (activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SE
CRET_TABINDEX) { |
| 7803 return; |
| 7804 } |
| 7805 this.toggleSelectionForItem(model[this.as]); |
| 7806 }, |
| 7807 _multiSelectionChanged: function(multiSelection) { |
| 7808 this.clearSelection(); |
| 7809 this.$.selector.multi = multiSelection; |
| 7810 }, |
| 7811 updateSizeForItem: function(item) { |
| 7812 item = this._getNormalizedItem(item); |
| 7813 var key = this._collection.getKey(item); |
| 7814 var pidx = this._physicalIndexForKey[key]; |
| 7815 if (pidx != null) { |
| 7816 this._updateMetrics([ pidx ]); |
| 7817 this._positionItems(); |
| 7818 } |
| 7819 }, |
| 7820 _manageFocus: function() { |
| 7821 var fidx = this._focusedIndex; |
| 7822 if (fidx >= 0 && fidx < this._virtualCount) { |
| 7823 if (this._isIndexRendered(fidx)) { |
| 7824 this._restoreFocusedItem(); |
| 7825 } else { |
| 7826 this._createFocusBackfillItem(); |
| 7827 } |
| 7828 } else if (this._virtualCount > 0 && this._physicalCount > 0) { |
| 7829 this._focusedIndex = this._virtualStart; |
| 7830 this._focusedItem = this._physicalItems[this._physicalStart]; |
| 7831 } |
| 7832 }, |
| 7833 _isIndexRendered: function(idx) { |
| 7834 return idx >= this._virtualStart && idx <= this._virtualEnd; |
| 7835 }, |
| 7836 _isIndexVisible: function(idx) { |
| 7837 return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex; |
| 7838 }, |
| 7839 _getPhysicalIndex: function(idx) { |
| 7840 return this._physicalIndexForKey[this._collection.getKey(this._getNormaliz
edItem(idx))]; |
| 7841 }, |
| 7842 _focusPhysicalItem: function(idx) { |
| 7843 if (idx < 0 || idx >= this._virtualCount) { |
| 7844 return; |
| 7845 } |
| 7846 this._restoreFocusedItem(); |
| 7847 if (!this._isIndexRendered(idx)) { |
| 7848 this.scrollToIndex(idx); |
| 7849 } |
| 7850 var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)]; |
| 7851 var model = physicalItem._templateInstance; |
| 7852 var focusable; |
| 7853 model.tabIndex = SECRET_TABINDEX; |
| 7854 if (physicalItem.tabIndex === SECRET_TABINDEX) { |
| 7855 focusable = physicalItem; |
| 7856 } |
| 7857 if (!focusable) { |
| 7858 focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECR
ET_TABINDEX + '"]'); |
| 7859 } |
| 7860 model.tabIndex = 0; |
| 7861 this._focusedIndex = idx; |
| 7862 focusable && focusable.focus(); |
| 7863 }, |
| 7864 _removeFocusedItem: function() { |
| 7865 if (this._offscreenFocusedItem) { |
| 7866 Polymer.dom(this).removeChild(this._offscreenFocusedItem); |
| 7867 } |
| 7868 this._offscreenFocusedItem = null; |
| 7869 this._focusBackfillItem = null; |
| 7870 this._focusedItem = null; |
| 7871 this._focusedIndex = -1; |
| 7872 }, |
| 7873 _createFocusBackfillItem: function() { |
| 7874 var pidx, fidx = this._focusedIndex; |
| 7875 if (this._offscreenFocusedItem || fidx < 0) { |
| 7876 return; |
| 7877 } |
| 7878 if (!this._focusBackfillItem) { |
| 7879 var stampedTemplate = this.stamp(null); |
| 7880 this._focusBackfillItem = stampedTemplate.root.querySelector('*'); |
| 7881 Polymer.dom(this).appendChild(stampedTemplate.root); |
| 7882 } |
| 7883 pidx = this._getPhysicalIndex(fidx); |
| 7884 if (pidx != null) { |
| 7885 this._offscreenFocusedItem = this._physicalItems[pidx]; |
| 7886 this._physicalItems[pidx] = this._focusBackfillItem; |
| 7887 this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem); |
| 7888 } |
| 7889 }, |
| 7890 _restoreFocusedItem: function() { |
| 7891 var pidx, fidx = this._focusedIndex; |
| 7892 if (!this._offscreenFocusedItem || this._focusedIndex < 0) { |
| 7893 return; |
| 7894 } |
| 7895 this._assignModels(); |
| 7896 pidx = this._getPhysicalIndex(fidx); |
| 7897 if (pidx != null) { |
| 7898 this._focusBackfillItem = this._physicalItems[pidx]; |
| 7899 this._physicalItems[pidx] = this._offscreenFocusedItem; |
| 7900 this._offscreenFocusedItem = null; |
| 7901 this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem); |
| 7902 } |
| 7903 }, |
| 7904 _didFocus: function(e) { |
| 7905 var targetModel = this.modelForElement(e.target); |
| 7906 var focusedModel = this._focusedItem ? this._focusedItem._templateInstance
: null; |
| 7907 var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null; |
| 7908 var fidx = this._focusedIndex; |
| 7909 if (!targetModel || !focusedModel) { |
| 7910 return; |
| 7911 } |
| 7912 if (focusedModel === targetModel) { |
| 7913 if (!this._isIndexVisible(fidx)) { |
| 7914 this.scrollToIndex(fidx); |
| 7915 } |
| 7916 } else { |
| 7917 this._restoreFocusedItem(); |
| 7918 focusedModel.tabIndex = -1; |
| 7919 targetModel.tabIndex = 0; |
| 7920 fidx = targetModel[this.indexAs]; |
| 7921 this._focusedIndex = fidx; |
| 7922 this._focusedItem = this._physicalItems[this._getPhysicalIndex(fidx)]; |
| 7923 if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) { |
| 7924 this._update(); |
| 7925 } |
| 7926 } |
| 7927 }, |
| 7928 _didMoveUp: function() { |
| 7929 this._focusPhysicalItem(this._focusedIndex - 1); |
| 7930 }, |
| 7931 _didMoveDown: function(e) { |
| 7932 e.detail.keyboardEvent.preventDefault(); |
| 7933 this._focusPhysicalItem(this._focusedIndex + 1); |
| 7934 }, |
| 7935 _didEnter: function(e) { |
| 7936 this._focusPhysicalItem(this._focusedIndex); |
| 7937 this._selectionHandler(e.detail.keyboardEvent); |
| 7938 } |
| 7939 }); |
| 7940 })(); |
| 7941 |
| 7942 Polymer({ |
| 7943 is: 'iron-scroll-threshold', |
| 7944 properties: { |
| 7945 upperThreshold: { |
| 7946 type: Number, |
| 7947 value: 100 |
| 7948 }, |
| 7949 lowerThreshold: { |
| 7950 type: Number, |
| 7951 value: 100 |
| 7952 }, |
| 7953 upperTriggered: { |
| 7954 type: Boolean, |
| 7955 value: false, |
| 7956 notify: true, |
| 7957 readOnly: true |
| 7958 }, |
| 7959 lowerTriggered: { |
| 7960 type: Boolean, |
| 7961 value: false, |
| 7962 notify: true, |
| 7963 readOnly: true |
| 7964 }, |
| 7965 horizontal: { |
| 7966 type: Boolean, |
| 7967 value: false |
| 7968 } |
| 7969 }, |
| 7970 behaviors: [ Polymer.IronScrollTargetBehavior ], |
| 7971 observers: [ '_setOverflow(scrollTarget)', '_initCheck(horizontal, isAttached)
' ], |
| 7972 get _defaultScrollTarget() { |
| 7973 return this; |
| 7974 }, |
| 7975 _setOverflow: function(scrollTarget) { |
| 7976 this.style.overflow = scrollTarget === this ? 'auto' : ''; |
| 7977 }, |
| 7978 _scrollHandler: function() { |
| 7979 var THROTTLE_THRESHOLD = 200; |
| 7980 if (!this.isDebouncerActive('_checkTheshold')) { |
| 7981 this.debounce('_checkTheshold', function() { |
| 7982 this.checkScrollThesholds(); |
| 7983 }, THROTTLE_THRESHOLD); |
| 7984 } |
| 7985 }, |
| 7986 _initCheck: function(horizontal, isAttached) { |
| 7987 if (isAttached) { |
| 7988 this.debounce('_init', function() { |
| 7989 this.clearTriggers(); |
| 7990 this.checkScrollThesholds(); |
| 7991 }); |
| 7992 } |
| 7993 }, |
| 7994 checkScrollThesholds: function() { |
| 7995 if (!this.scrollTarget || this.lowerTriggered && this.upperTriggered) { |
| 7996 return; |
| 7997 } |
| 7998 var upperScrollValue = this.horizontal ? this._scrollLeft : this._scrollTop; |
| 7999 var lowerScrollValue = this.horizontal ? this.scrollTarget.scrollWidth - thi
s._scrollTargetWidth - this._scrollLeft : this.scrollTarget.scrollHeight - this.
_scrollTargetHeight - this._scrollTop; |
| 8000 if (upperScrollValue <= this.upperThreshold && !this.upperTriggered) { |
| 8001 this._setUpperTriggered(true); |
| 8002 this.fire('upper-threshold'); |
| 8003 } |
| 8004 if (lowerScrollValue <= this.lowerThreshold && !this.lowerTriggered) { |
| 8005 this._setLowerTriggered(true); |
| 8006 this.fire('lower-threshold'); |
| 8007 } |
| 8008 }, |
| 8009 clearTriggers: function() { |
| 8010 this._setUpperTriggered(false); |
| 8011 this._setLowerTriggered(false); |
| 8012 } |
| 8013 }); |
| 8014 |
| 8015 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 8016 // Use of this source code is governed by a BSD-style license that can be |
| 8017 // found in the LICENSE file. |
| 8018 Polymer({ |
| 8019 is: 'history-list', |
| 8020 behaviors: [ HistoryListBehavior ], |
| 8021 properties: { |
| 8022 searchedTerm: { |
| 8023 type: String, |
| 8024 value: '' |
| 8025 }, |
| 8026 lastSearchedTerm_: String, |
| 8027 querying: Boolean, |
| 8028 historyData_: Array, |
| 8029 resultLoadingDisabled_: { |
| 8030 type: Boolean, |
| 8031 value: false |
| 8032 } |
| 8033 }, |
| 8034 listeners: { |
| 8035 'infinite-list.scroll': 'notifyListScroll_', |
| 8036 'remove-bookmark-stars': 'removeBookmarkStars_' |
| 8037 }, |
| 8038 attached: function() { |
| 8039 this.$['infinite-list'].notifyResize(); |
| 8040 }, |
| 8041 removeBookmarkStars_: function(e) { |
| 8042 var url = e.detail; |
| 8043 if (this.historyData_ === undefined) return; |
| 8044 for (var i = 0; i < this.historyData_.length; i++) { |
| 8045 if (this.historyData_[i].url == url) this.set('historyData_.' + i + '.star
red', false); |
| 8046 } |
| 8047 }, |
| 8048 disableResultLoading: function() { |
| 8049 this.resultLoadingDisabled_ = true; |
| 8050 }, |
| 8051 addNewResults: function(historyResults) { |
| 8052 var results = historyResults.slice(); |
| 8053 this.$['scroll-threshold'].clearTriggers(); |
| 8054 if (this.lastSearchedTerm_ != this.searchedTerm) { |
| 8055 this.resultLoadingDisabled_ = false; |
| 8056 if (this.historyData_) this.splice('historyData_', 0, this.historyData_.le
ngth); |
| 8057 this.fire('unselect-all'); |
| 8058 this.lastSearchedTerm_ = this.searchedTerm; |
| 8059 } |
| 8060 if (this.historyData_) { |
| 8061 results.unshift('historyData_'); |
| 8062 this.push.apply(this, results); |
| 8063 } else { |
| 8064 this.set('historyData_', results); |
| 8065 } |
| 8066 }, |
| 8067 loadMoreData_: function() { |
| 8068 if (this.resultLoadingDisabled_ || this.querying) return; |
| 8069 this.fire('load-more-history'); |
| 8070 }, |
| 8071 needsTimeGap_: function(item, index, length) { |
| 8072 return md_history.HistoryItem.needsTimeGap(this.historyData_, index, this.se
archedTerm); |
| 8073 }, |
| 8074 isCardStart_: function(item, i, length) { |
| 8075 if (length == 0 || i > length - 1) return false; |
| 8076 return i == 0 || this.historyData_[i].dateRelativeDay != this.historyData_[i
- 1].dateRelativeDay; |
| 8077 }, |
| 8078 isCardEnd_: function(item, i, length) { |
| 8079 if (length == 0 || i > length - 1) return false; |
| 8080 return i == length - 1 || this.historyData_[i].dateRelativeDay != this.histo
ryData_[i + 1].dateRelativeDay; |
| 8081 }, |
| 8082 isFirstItem_: function(index) { |
| 8083 return index == 0; |
| 8084 }, |
| 8085 notifyListScroll_: function() { |
| 8086 this.fire('history-list-scrolled'); |
| 8087 }, |
| 8088 pathForItem_: function(index) { |
| 8089 return 'historyData_.' + index; |
| 8090 } |
| 8091 }); |
| 8092 |
| 8093 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 8094 // Use of this source code is governed by a BSD-style license that can be |
| 8095 // found in the LICENSE file. |
| 8096 Polymer({ |
| 8097 is: 'history-list-container', |
| 8098 properties: { |
| 8099 selectedPage_: String, |
| 8100 grouped: Boolean, |
| 8101 queryState: Object, |
| 8102 queryResult: Object |
| 8103 }, |
| 8104 observers: [ 'groupedRangeChanged_(queryState.range)' ], |
| 8105 listeners: { |
| 8106 'history-list-scrolled': 'closeMenu_', |
| 8107 'load-more-history': 'loadMoreHistory_', |
| 8108 'toggle-menu': 'toggleMenu_' |
| 8109 }, |
| 8110 historyResult: function(info, results) { |
| 8111 this.initializeResults_(info, results); |
| 8112 this.closeMenu_(); |
| 8113 if (this.selectedPage_ == 'grouped-list') { |
| 8114 this.$$('#grouped-list').historyData = results; |
| 8115 return; |
| 8116 } |
| 8117 var list = this.$['infinite-list']; |
| 8118 list.addNewResults(results); |
| 8119 if (info.finished) list.disableResultLoading(); |
| 8120 }, |
| 8121 queryHistory: function(incremental) { |
| 8122 var queryState = this.queryState; |
| 8123 var noResults = !this.queryResult || this.queryResult.results == null; |
| 8124 if (queryState.queryingDisabled || !this.queryState.searchTerm && noResults)
{ |
| 8125 return; |
| 8126 } |
| 8127 if (!incremental && this.$.dialog.open) this.$.dialog.close(); |
| 8128 this.set('queryState.querying', true); |
| 8129 this.set('queryState.incremental', incremental); |
| 8130 var lastVisitTime = 0; |
| 8131 if (incremental) { |
| 8132 var lastVisit = this.queryResult.results.slice(-1)[0]; |
| 8133 lastVisitTime = lastVisit ? lastVisit.time : 0; |
| 8134 } |
| 8135 var maxResults = queryState.range == HistoryRange.ALL_TIME ? RESULTS_PER_PAG
E : 0; |
| 8136 chrome.send('queryHistory', [ queryState.searchTerm, queryState.groupedOffse
t, queryState.range, lastVisitTime, maxResults ]); |
| 8137 }, |
| 8138 unselectAllItems: function(count) { |
| 8139 this.getSelectedList_().unselectAllItems(count); |
| 8140 }, |
| 8141 deleteSelectedWithPrompt: function() { |
| 8142 if (!loadTimeData.getBoolean('allowDeletingHistory')) return; |
| 8143 this.$.dialog.showModal(); |
| 8144 }, |
| 8145 groupedRangeChanged_: function(range) { |
| 8146 this.selectedPage_ = this.queryState.range == HistoryRange.ALL_TIME ? 'infin
ite-list' : 'grouped-list'; |
| 8147 this.queryHistory(false); |
| 8148 }, |
| 8149 loadMoreHistory_: function() { |
| 8150 this.queryHistory(true); |
| 8151 }, |
| 8152 initializeResults_: function(info, results) { |
| 8153 if (results.length == 0) return; |
| 8154 var currentDate = results[0].dateRelativeDay; |
| 8155 for (var i = 0; i < results.length; i++) { |
| 8156 results[i].selected = false; |
| 8157 results[i].readableTimestamp = info.term == '' ? results[i].dateTimeOfDay
: results[i].dateShort; |
| 8158 if (results[i].dateRelativeDay != currentDate) { |
| 8159 currentDate = results[i].dateRelativeDay; |
| 8160 } |
| 8161 } |
| 8162 }, |
| 8163 onDialogConfirmTap_: function() { |
| 8164 this.getSelectedList_().deleteSelected(); |
| 8165 this.$.dialog.close(); |
| 8166 }, |
| 8167 onDialogCancelTap_: function() { |
| 8168 this.$.dialog.close(); |
| 8169 }, |
| 8170 closeMenu_: function() { |
| 8171 this.$.sharedMenu.closeMenu(); |
| 8172 }, |
| 8173 toggleMenu_: function(e) { |
| 8174 var target = e.detail.target; |
| 8175 this.$.sharedMenu.toggleMenu(target, e.detail.item); |
| 8176 }, |
| 8177 onMoreFromSiteTap_: function() { |
| 8178 var menu = this.$.sharedMenu; |
| 8179 this.fire('search-domain', { |
| 8180 domain: menu.itemData.domain |
| 8181 }); |
| 8182 menu.closeMenu(); |
| 8183 }, |
| 8184 onRemoveFromHistoryTap_: function() { |
| 8185 var menu = this.$.sharedMenu; |
| 8186 md_history.BrowserService.getInstance().deleteItems([ menu.itemData ]).then(
function(items) { |
| 8187 this.getSelectedList_().removeItemsByPath(items[0].path); |
| 8188 this.fire('unselect-all'); |
| 8189 }.bind(this)); |
| 8190 menu.closeMenu(); |
| 8191 }, |
| 8192 getSelectedList_: function() { |
| 8193 return this.$.content.selectedItem; |
| 8194 } |
| 8195 }); |
| 8196 |
| 8197 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 8198 // Use of this source code is governed by a BSD-style license that can be |
| 8199 // found in the LICENSE file. |
| 8200 Polymer({ |
| 8201 is: 'history-synced-device-card', |
| 8202 properties: { |
| 8203 device: String, |
| 8204 lastUpdateTime: String, |
| 8205 tabs: { |
| 8206 type: Array, |
| 8207 value: function() { |
| 8208 return []; |
| 8209 }, |
| 8210 observer: 'updateIcons_' |
| 8211 }, |
| 8212 separatorIndexes: Array, |
| 8213 cardOpen_: { |
| 8214 type: Boolean, |
| 8215 value: true |
| 8216 }, |
| 8217 searchTerm: String, |
| 8218 sessionTag: String |
| 8219 }, |
| 8220 openTab_: function(e) { |
| 8221 var tab = e.model.tab; |
| 8222 md_history.BrowserService.getInstance().openForeignSessionTab(this.sessionTa
g, tab.windowId, tab.sessionId, e); |
| 8223 e.preventDefault(); |
| 8224 }, |
| 8225 toggleTabCard: function() { |
| 8226 this.$.collapse.toggle(); |
| 8227 this.$['dropdown-indicator'].icon = this.$.collapse.opened ? 'cr:expand-less
' : 'cr:expand-more'; |
| 8228 }, |
| 8229 updateIcons_: function() { |
| 8230 this.async(function() { |
| 8231 var icons = Polymer.dom(this.root).querySelectorAll('.website-icon'); |
| 8232 for (var i = 0; i < this.tabs.length; i++) { |
| 8233 icons[i].style.backgroundImage = cr.icon.getFaviconImageSet(this.tabs[i]
.url); |
| 8234 } |
| 8235 }); |
| 8236 }, |
| 8237 isWindowSeparatorIndex_: function(index, separatorIndexes) { |
| 8238 return this.separatorIndexes.indexOf(index) != -1; |
| 8239 }, |
| 8240 getCollapseTitle_: function(cardOpen) { |
| 8241 return cardOpen ? loadTimeData.getString('collapseSessionButton') : loadTime
Data.getString('expandSessionButton'); |
| 8242 }, |
| 8243 onMenuButtonTap_: function(e) { |
| 8244 this.fire('toggle-menu', { |
| 8245 target: Polymer.dom(e).localTarget, |
| 8246 tag: this.sessionTag |
| 8247 }); |
| 8248 e.stopPropagation(); |
| 8249 } |
| 8250 }); |
| 8251 |
| 8252 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 8253 // Use of this source code is governed by a BSD-style license that can be |
| 8254 // found in the LICENSE file. |
| 8255 var ForeignDeviceInternal; |
| 8256 |
| 8257 Polymer({ |
| 8258 is: 'history-synced-device-manager', |
| 8259 properties: { |
| 8260 sessionList: { |
| 8261 type: Array, |
| 8262 observer: 'updateSyncedDevices' |
| 8263 }, |
| 8264 searchTerm: { |
| 8265 type: String, |
| 8266 observer: 'searchTermChanged' |
| 8267 }, |
| 8268 syncedDevices_: { |
| 8269 type: Array, |
| 8270 value: function() { |
| 8271 return []; |
| 8272 } |
| 8273 }, |
| 8274 signInState_: { |
| 8275 type: Boolean, |
| 8276 value: loadTimeData.getBoolean('isUserSignedIn') |
| 8277 }, |
| 8278 guestSession_: { |
| 8279 type: Boolean, |
| 8280 value: loadTimeData.getBoolean('isGuestSession') |
| 8281 }, |
| 8282 fetchingSyncedTabs_: { |
| 8283 type: Boolean, |
| 8284 value: false |
| 8285 } |
| 8286 }, |
| 8287 listeners: { |
| 8288 'toggle-menu': 'onToggleMenu_' |
| 8289 }, |
| 8290 attached: function() { |
| 8291 chrome.send('otherDevicesInitialized'); |
| 8292 }, |
| 8293 createInternalDevice_: function(session) { |
| 8294 var tabs = []; |
| 8295 var separatorIndexes = []; |
| 8296 for (var i = 0; i < session.windows.length; i++) { |
| 8297 var windowId = session.windows[i].sessionId; |
| 8298 var newTabs = session.windows[i].tabs; |
| 8299 if (newTabs.length == 0) continue; |
| 8300 newTabs.forEach(function(tab) { |
| 8301 tab.windowId = windowId; |
| 8302 }); |
| 8303 var windowAdded = false; |
| 8304 if (!this.searchTerm) { |
| 8305 tabs = tabs.concat(newTabs); |
| 8306 windowAdded = true; |
| 8307 } else { |
| 8308 var searchText = this.searchTerm.toLowerCase(); |
| 8309 for (var j = 0; j < newTabs.length; j++) { |
| 8310 var tab = newTabs[j]; |
| 8311 if (tab.title.toLowerCase().indexOf(searchText) != -1) { |
| 8312 tabs.push(tab); |
| 8313 windowAdded = true; |
| 8314 } |
| 8315 } |
| 8316 } |
| 8317 if (windowAdded && i != session.windows.length - 1) separatorIndexes.push(
tabs.length - 1); |
| 8318 } |
| 8319 return { |
| 8320 device: session.name, |
| 8321 lastUpdateTime: '– ' + session.modifiedTime, |
| 8322 separatorIndexes: separatorIndexes, |
| 8323 timestamp: session.timestamp, |
| 8324 tabs: tabs, |
| 8325 tag: session.tag |
| 8326 }; |
| 8327 }, |
| 8328 onSignInTap_: function() { |
| 8329 chrome.send('SyncSetupShowSetupUI'); |
| 8330 chrome.send('SyncSetupStartSignIn', [ false ]); |
| 8331 }, |
| 8332 onToggleMenu_: function(e) { |
| 8333 this.$.menu.toggleMenu(e.detail.target, e.detail.tag); |
| 8334 }, |
| 8335 onOpenAllTap_: function() { |
| 8336 md_history.BrowserService.getInstance().openForeignSessionAllTabs(this.$.men
u.itemData); |
| 8337 this.$.menu.closeMenu(); |
| 8338 }, |
| 8339 onDeleteSessionTap_: function() { |
| 8340 md_history.BrowserService.getInstance().deleteForeignSession(this.$.menu.ite
mData); |
| 8341 this.$.menu.closeMenu(); |
| 8342 }, |
| 8343 clearDisplayedSyncedDevices_: function() { |
| 8344 this.syncedDevices_ = []; |
| 8345 }, |
| 8346 showNoSyncedMessage: function(signInState, syncedDevicesLength, guestSession)
{ |
| 8347 if (guestSession) return true; |
| 8348 return signInState && syncedDevicesLength == 0; |
| 8349 }, |
| 8350 showSignInGuide: function(signInState, guestSession) { |
| 8351 return !signInState && !guestSession; |
| 8352 }, |
| 8353 noSyncedTabsMessage: function(fetchingSyncedTabs) { |
| 8354 return loadTimeData.getString(fetchingSyncedTabs ? 'loading' : 'noSyncedResu
lts'); |
| 8355 }, |
| 8356 updateSyncedDevices: function(sessionList) { |
| 8357 this.fetchingSyncedTabs_ = false; |
| 8358 if (!sessionList) return; |
| 8359 var updateCount = Math.min(sessionList.length, this.syncedDevices_.length); |
| 8360 for (var i = 0; i < updateCount; i++) { |
| 8361 var oldDevice = this.syncedDevices_[i]; |
| 8362 if (oldDevice.tag != sessionList[i].tag || oldDevice.timestamp != sessionL
ist[i].timestamp) { |
| 8363 this.splice('syncedDevices_', i, 1, this.createInternalDevice_(sessionLi
st[i])); |
| 8364 } |
| 8365 } |
| 8366 for (var i = updateCount; i < sessionList.length; i++) { |
| 8367 this.push('syncedDevices_', this.createInternalDevice_(sessionList[i])); |
| 8368 } |
| 8369 }, |
| 8370 updateSignInState: function(isUserSignedIn) { |
| 8371 if (this.signInState_ == isUserSignedIn) return; |
| 8372 this.signInState_ = isUserSignedIn; |
| 8373 if (!isUserSignedIn) { |
| 8374 this.clearDisplayedSyncedDevices_(); |
| 8375 return; |
| 8376 } |
| 8377 this.fetchingSyncedTabs_ = true; |
| 8378 }, |
| 8379 searchTermChanged: function(searchTerm) { |
| 8380 this.clearDisplayedSyncedDevices_(); |
| 8381 this.updateSyncedDevices(this.sessionList); |
| 8382 } |
| 8383 }); |
| 8384 |
| 8385 Polymer({ |
| 8386 is: 'iron-selector', |
| 8387 behaviors: [ Polymer.IronMultiSelectableBehavior ] |
| 8388 }); |
| 8389 |
| 8390 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 8391 // Use of this source code is governed by a BSD-style license that can be |
| 8392 // found in the LICENSE file. |
| 8393 Polymer({ |
| 8394 is: 'history-side-bar', |
| 8395 properties: { |
| 8396 selectedPage: { |
| 8397 type: String, |
| 8398 notify: true |
| 8399 }, |
| 8400 route: Object, |
| 8401 showFooter: Boolean, |
| 8402 drawer: { |
| 8403 type: Boolean, |
| 8404 reflectToAttribute: true |
| 8405 } |
| 8406 }, |
| 8407 onSelectorActivate_: function() { |
| 8408 this.fire('history-close-drawer'); |
| 8409 }, |
| 8410 onClearBrowsingDataTap_: function(e) { |
| 8411 md_history.BrowserService.getInstance().openClearBrowsingData(); |
| 8412 e.preventDefault(); |
| 8413 }, |
| 8414 getQueryString_: function(route) { |
| 8415 return window.location.search; |
| 8416 } |
| 8417 }); |
| 8418 |
| 8419 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 8420 // Use of this source code is governed by a BSD-style license that can be |
| 8421 // found in the LICENSE file. |
| 8422 Polymer({ |
| 8423 is: 'history-app', |
| 8424 properties: { |
| 8425 showSidebarFooter: Boolean, |
| 8426 selectedPage_: { |
| 8427 type: String, |
| 8428 value: 'history', |
| 8429 observer: 'unselectAll' |
| 8430 }, |
| 8431 grouped_: { |
| 8432 type: Boolean, |
| 8433 reflectToAttribute: true |
| 8434 }, |
| 8435 queryState_: { |
| 8436 type: Object, |
| 8437 value: function() { |
| 8438 return { |
| 8439 incremental: false, |
| 8440 querying: true, |
| 8441 queryingDisabled: false, |
| 8442 _range: HistoryRange.ALL_TIME, |
| 8443 searchTerm: '', |
| 8444 groupedOffset: 0, |
| 8445 set range(val) { |
| 8446 this._range = Number(val); |
| 8447 }, |
| 8448 get range() { |
| 8449 return this._range; |
| 8450 } |
| 8451 }; |
| 8452 } |
| 8453 }, |
| 8454 queryResult_: { |
| 8455 type: Object, |
| 8456 value: function() { |
| 8457 return { |
| 8458 info: null, |
| 8459 results: null, |
| 8460 sessionList: null |
| 8461 }; |
| 8462 } |
| 8463 }, |
| 8464 routeData_: Object, |
| 8465 queryParams_: Object, |
| 8466 hasDrawer_: Boolean |
| 8467 }, |
| 8468 observers: [ 'routeDataChanged_(routeData_.page)', 'selectedPageChanged_(selec
tedPage_)', 'searchTermChanged_(queryState_.searchTerm)', 'searchQueryParamChang
ed_(queryParams_.q)' ], |
| 8469 listeners: { |
| 8470 'cr-menu-tap': 'onMenuTap_', |
| 8471 'history-checkbox-select': 'checkboxSelected', |
| 8472 'unselect-all': 'unselectAll', |
| 8473 'delete-selected': 'deleteSelected', |
| 8474 'search-domain': 'searchDomain_', |
| 8475 'history-close-drawer': 'closeDrawer_' |
| 8476 }, |
| 8477 ready: function() { |
| 8478 this.grouped_ = loadTimeData.getBoolean('groupByDomain'); |
| 8479 cr.ui.decorate('command', cr.ui.Command); |
| 8480 document.addEventListener('canExecute', this.onCanExecute_.bind(this)); |
| 8481 document.addEventListener('command', this.onCommand_.bind(this)); |
| 8482 if (window.location.hash) { |
| 8483 window.location.href = window.location.href.split('#')[0] + '?' + window.l
ocation.hash.substr(1); |
| 8484 } |
| 8485 }, |
| 8486 onMenuTap_: function() { |
| 8487 var drawer = this.$$('#drawer'); |
| 8488 if (drawer) drawer.toggle(); |
| 8489 }, |
| 8490 checkboxSelected: function(e) { |
| 8491 var toolbar = this.$.toolbar; |
| 8492 toolbar.count += e.detail.countAddition; |
| 8493 }, |
| 8494 unselectAll: function() { |
| 8495 var listContainer = this.$['history']; |
| 8496 var toolbar = this.$.toolbar; |
| 8497 listContainer.unselectAllItems(toolbar.count); |
| 8498 toolbar.count = 0; |
| 8499 }, |
| 8500 deleteSelected: function() { |
| 8501 this.$.history.deleteSelectedWithPrompt(); |
| 8502 }, |
| 8503 historyResult: function(info, results) { |
| 8504 this.set('queryState_.querying', false); |
| 8505 this.set('queryResult_.info', info); |
| 8506 this.set('queryResult_.results', results); |
| 8507 var listContainer = this.$['history']; |
| 8508 listContainer.historyResult(info, results); |
| 8509 }, |
| 8510 searchDomain_: function(e) { |
| 8511 this.$.toolbar.setSearchTerm(e.detail.domain); |
| 8512 }, |
| 8513 onCanExecute_: function(e) { |
| 8514 e = e; |
| 8515 switch (e.command.id) { |
| 8516 case 'find-command': |
| 8517 e.canExecute = true; |
| 8518 break; |
| 8519 |
| 8520 case 'slash-command': |
| 8521 e.canExecute = !this.$.toolbar.searchBar.isSearchFocused(); |
| 8522 break; |
| 8523 |
| 8524 case 'delete-command': |
| 8525 e.canExecute = this.$.toolbar.count > 0; |
| 8526 break; |
| 8527 } |
| 8528 }, |
| 8529 searchTermChanged_: function(searchTerm) { |
| 8530 this.set('queryParams_.q', searchTerm || null); |
| 8531 this.$['history'].queryHistory(false); |
| 8532 }, |
| 8533 searchQueryParamChanged_: function(searchQuery) { |
| 8534 this.$.toolbar.setSearchTerm(searchQuery || ''); |
| 8535 }, |
| 8536 onCommand_: function(e) { |
| 8537 if (e.command.id == 'find-command' || e.command.id == 'slash-command') this.
$.toolbar.showSearchField(); |
| 8538 if (e.command.id == 'delete-command') this.deleteSelected(); |
| 8539 }, |
| 8540 setForeignSessions: function(sessionList, isTabSyncEnabled) { |
| 8541 if (!isTabSyncEnabled) return; |
| 8542 this.set('queryResult_.sessionList', sessionList); |
| 8543 }, |
| 8544 updateSignInState: function(isUserSignedIn) { |
| 8545 var syncedDeviceManagerElem = this.$$('history-synced-device-manager'); |
| 8546 if (syncedDeviceManagerElem) syncedDeviceManagerElem.updateSignInState(isUse
rSignedIn); |
| 8547 }, |
| 8548 syncedTabsSelected_: function(selectedPage) { |
| 8549 return selectedPage == 'syncedTabs'; |
| 8550 }, |
| 8551 shouldShowSpinner_: function(querying, incremental, searchTerm) { |
| 8552 return querying && !incremental && searchTerm != ''; |
| 8553 }, |
| 8554 routeDataChanged_: function(page) { |
| 8555 this.selectedPage_ = page; |
| 8556 }, |
| 8557 selectedPageChanged_: function(selectedPage) { |
| 8558 this.set('routeData_.page', selectedPage); |
| 8559 }, |
| 8560 getSelectedPage_: function(selectedPage, items) { |
| 8561 return selectedPage; |
| 8562 }, |
| 8563 closeDrawer_: function() { |
| 8564 var drawer = this.$$('#drawer'); |
| 8565 if (drawer) drawer.close(); |
| 8566 } |
| 8567 }); |
OLD | NEW |