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

Side by Side Diff: appengine/swarming/elements/build/index-build.html

Issue 2177353002: Add top level app element (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@hello-oauth
Patch Set: Actually delete stats Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 <!DOCTYPE html><html><head><!-- 1 <!DOCTYPE html><html><head><!--
2 @license 2 @license
3 Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt
9 --><!--
10 @license
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. 11 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt 12 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 13 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt 14 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt
7 Code distributed by Google as part of the polymer project is also 15 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt 16 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt
9 --><!-- 17 --><!--
10 @license 18 @license
11 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 19 Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
12 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt 20 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
(...skipping 9139 matching lines...) Expand 10 before | Expand all | Expand 10 after
9152 this.generateRequest(); 9160 this.generateRequest();
9153 } 9161 }
9154 }, this.debounceDuration); 9162 }, this.debounceDuration);
9155 }, 9163 },
9156 9164
9157 }); 9165 });
9158 </script> 9166 </script>
9159 9167
9160 9168
9161 <script> 9169 <script>
9170 Polymer.AppLayout = Polymer.AppLayout || {};
9171
9172 Polymer.AppLayout._scrollEffects = Polymer.AppLayout._scrollEffects || {};
9173
9174 Polymer.AppLayout.scrollTimingFunction = function easeOutQuad(t, b, c, d) {
9175 t /= d;
9176 return -c * t*(t-2) + b;
9177 };
9178
9179 /**
9180 * Registers a scroll effect to be used in elements that implement the
9181 * `Polymer.AppScrollEffectsBehavior` behavior.
9182 *
9183 * @param {string} effectName The effect name.
9184 * @param {Object} effectDef The effect definition.
9185 */
9186 Polymer.AppLayout.registerEffect = function registerEffect(effectName, effectD ef) {
9187 if (Polymer.AppLayout._scrollEffects[effectName] != null) {
9188 throw new Error('effect `'+ effectName + '` is already registered.');
9189 }
9190 Polymer.AppLayout._scrollEffects[effectName] = effectDef;
9191 };
9192
9193 /**
9194 * Scrolls to a particular set of coordinates in a scroll target.
9195 * If the scroll target is not defined, then it would use the main document as the target.
9196 *
9197 * To scroll in a smooth fashion, you can set the option `behavior: 'smooth'`. e.g.
9198 *
9199 * ```js
9200 * Polymer.AppLayout.scroll({top: 0, behavior: 'smooth'});
9201 * ```
9202 *
9203 * To scroll in a silent mode, without notifying scroll changes to any app-lay out elements,
9204 * you can set the option `behavior: 'silent'`. This is particularly useful we you are using
9205 * `app-header` and you desire to scroll to the top of a scrolling region with out running
9206 * scroll effects. e.g.
9207 *
9208 * ```js
9209 * Polymer.AppLayout.scroll({top: 0, behavior: 'silent'});
9210 * ```
9211 *
9212 * @param {Object} options {top: Number, left: Number, behavior: String(smooth | silent)}
9213 */
9214 Polymer.AppLayout.scroll = function scroll(options) {
9215 options = options || {};
9216
9217 var docEl = document.documentElement;
9218 var target = options.target || docEl;
9219 var hasNativeScrollBehavior = 'scrollBehavior' in target.style && target.scr oll;
9220 var scrollClassName = 'app-layout-silent-scroll';
9221 var scrollTop = options.top || 0;
9222 var scrollLeft = options.left || 0;
9223 var scrollTo = target === docEl ? window.scrollTo :
9224 function scrollTo(scrollLeft, scrollTop) {
9225 target.scrollLeft = scrollLeft;
9226 target.scrollTop = scrollTop;
9227 };
9228
9229 if (options.behavior === 'smooth') {
9230
9231 if (hasNativeScrollBehavior) {
9232
9233 target.scroll(options);
9234
9235 } else {
9236
9237 var timingFn = Polymer.AppLayout.scrollTimingFunction;
9238 var startTime = Date.now();
9239 var currentScrollTop = target === docEl ? window.pageYOffset : target.sc rollTop;
9240 var currentScrollLeft = target === docEl ? window.pageXOffset : target.s crollLeft;
9241 var deltaScrollTop = scrollTop - currentScrollTop;
9242 var deltaScrollLeft = scrollLeft - currentScrollLeft;
9243 var duration = 300;
9244 var updateFrame = (function updateFrame() {
9245 var now = Date.now();
9246 var elapsedTime = now - startTime;
9247
9248 if (elapsedTime < duration) {
9249 scrollTo(timingFn(elapsedTime, currentScrollLeft, deltaScrollLeft, d uration),
9250 timingFn(elapsedTime, currentScrollTop, deltaScrollTop, duration ));
9251 requestAnimationFrame(updateFrame);
9252 } else {
9253 scrollTo(scrollLeft, scrollTop);
9254 }
9255 }).bind(this);
9256
9257 updateFrame();
9258 }
9259
9260 } else if (options.behavior === 'silent') {
9261
9262 docEl.classList.add(scrollClassName);
9263
9264 // Browsers keep the scroll momentum even if the bottom of the scrolling c ontent
9265 // was reached. This means that calling scroll({top: 0, behavior: 'silent' }) when
9266 // the momentum is still going will result in more scroll events and thus scroll effects.
9267 // This seems to only apply when using document scrolling.
9268 // Therefore, when should we remove the class from the document element?
9269
9270 clearInterval(Polymer.AppLayout._scrollTimer);
9271
9272 Polymer.AppLayout._scrollTimer = setTimeout(function() {
9273 docEl.classList.remove(scrollClassName);
9274 Polymer.AppLayout._scrollTimer = null;
9275 }, 100);
9276
9277 scrollTo(scrollLeft, scrollTop);
9278
9279 } else {
9280
9281 scrollTo(scrollLeft, scrollTop);
9282
9283 }
9284 };
9285
9286 </script>
9287
9288
9289 <style>
9290 /* IE 10 support for HTML5 hidden attr */
9291 [hidden] {
9292 display: none !important;
9293 }
9294 </style>
9295
9296 <style is="custom-style">
9297 :root {
9298
9299 --layout: {
9300 display: -ms-flexbox;
9301 display: -webkit-flex;
9302 display: flex;
9303 };
9304
9305 --layout-inline: {
9306 display: -ms-inline-flexbox;
9307 display: -webkit-inline-flex;
9308 display: inline-flex;
9309 };
9310
9311 --layout-horizontal: {
9312 @apply(--layout);
9313
9314 -ms-flex-direction: row;
9315 -webkit-flex-direction: row;
9316 flex-direction: row;
9317 };
9318
9319 --layout-horizontal-reverse: {
9320 @apply(--layout);
9321
9322 -ms-flex-direction: row-reverse;
9323 -webkit-flex-direction: row-reverse;
9324 flex-direction: row-reverse;
9325 };
9326
9327 --layout-vertical: {
9328 @apply(--layout);
9329
9330 -ms-flex-direction: column;
9331 -webkit-flex-direction: column;
9332 flex-direction: column;
9333 };
9334
9335 --layout-vertical-reverse: {
9336 @apply(--layout);
9337
9338 -ms-flex-direction: column-reverse;
9339 -webkit-flex-direction: column-reverse;
9340 flex-direction: column-reverse;
9341 };
9342
9343 --layout-wrap: {
9344 -ms-flex-wrap: wrap;
9345 -webkit-flex-wrap: wrap;
9346 flex-wrap: wrap;
9347 };
9348
9349 --layout-wrap-reverse: {
9350 -ms-flex-wrap: wrap-reverse;
9351 -webkit-flex-wrap: wrap-reverse;
9352 flex-wrap: wrap-reverse;
9353 };
9354
9355 --layout-flex-auto: {
9356 -ms-flex: 1 1 auto;
9357 -webkit-flex: 1 1 auto;
9358 flex: 1 1 auto;
9359 };
9360
9361 --layout-flex-none: {
9362 -ms-flex: none;
9363 -webkit-flex: none;
9364 flex: none;
9365 };
9366
9367 --layout-flex: {
9368 -ms-flex: 1 1 0.000000001px;
9369 -webkit-flex: 1;
9370 flex: 1;
9371 -webkit-flex-basis: 0.000000001px;
9372 flex-basis: 0.000000001px;
9373 };
9374
9375 --layout-flex-2: {
9376 -ms-flex: 2;
9377 -webkit-flex: 2;
9378 flex: 2;
9379 };
9380
9381 --layout-flex-3: {
9382 -ms-flex: 3;
9383 -webkit-flex: 3;
9384 flex: 3;
9385 };
9386
9387 --layout-flex-4: {
9388 -ms-flex: 4;
9389 -webkit-flex: 4;
9390 flex: 4;
9391 };
9392
9393 --layout-flex-5: {
9394 -ms-flex: 5;
9395 -webkit-flex: 5;
9396 flex: 5;
9397 };
9398
9399 --layout-flex-6: {
9400 -ms-flex: 6;
9401 -webkit-flex: 6;
9402 flex: 6;
9403 };
9404
9405 --layout-flex-7: {
9406 -ms-flex: 7;
9407 -webkit-flex: 7;
9408 flex: 7;
9409 };
9410
9411 --layout-flex-8: {
9412 -ms-flex: 8;
9413 -webkit-flex: 8;
9414 flex: 8;
9415 };
9416
9417 --layout-flex-9: {
9418 -ms-flex: 9;
9419 -webkit-flex: 9;
9420 flex: 9;
9421 };
9422
9423 --layout-flex-10: {
9424 -ms-flex: 10;
9425 -webkit-flex: 10;
9426 flex: 10;
9427 };
9428
9429 --layout-flex-11: {
9430 -ms-flex: 11;
9431 -webkit-flex: 11;
9432 flex: 11;
9433 };
9434
9435 --layout-flex-12: {
9436 -ms-flex: 12;
9437 -webkit-flex: 12;
9438 flex: 12;
9439 };
9440
9441 /* alignment in cross axis */
9442
9443 --layout-start: {
9444 -ms-flex-align: start;
9445 -webkit-align-items: flex-start;
9446 align-items: flex-start;
9447 };
9448
9449 --layout-center: {
9450 -ms-flex-align: center;
9451 -webkit-align-items: center;
9452 align-items: center;
9453 };
9454
9455 --layout-end: {
9456 -ms-flex-align: end;
9457 -webkit-align-items: flex-end;
9458 align-items: flex-end;
9459 };
9460
9461 --layout-baseline: {
9462 -ms-flex-align: baseline;
9463 -webkit-align-items: baseline;
9464 align-items: baseline;
9465 };
9466
9467 /* alignment in main axis */
9468
9469 --layout-start-justified: {
9470 -ms-flex-pack: start;
9471 -webkit-justify-content: flex-start;
9472 justify-content: flex-start;
9473 };
9474
9475 --layout-center-justified: {
9476 -ms-flex-pack: center;
9477 -webkit-justify-content: center;
9478 justify-content: center;
9479 };
9480
9481 --layout-end-justified: {
9482 -ms-flex-pack: end;
9483 -webkit-justify-content: flex-end;
9484 justify-content: flex-end;
9485 };
9486
9487 --layout-around-justified: {
9488 -ms-flex-pack: distribute;
9489 -webkit-justify-content: space-around;
9490 justify-content: space-around;
9491 };
9492
9493 --layout-justified: {
9494 -ms-flex-pack: justify;
9495 -webkit-justify-content: space-between;
9496 justify-content: space-between;
9497 };
9498
9499 --layout-center-center: {
9500 @apply(--layout-center);
9501 @apply(--layout-center-justified);
9502 };
9503
9504 /* self alignment */
9505
9506 --layout-self-start: {
9507 -ms-align-self: flex-start;
9508 -webkit-align-self: flex-start;
9509 align-self: flex-start;
9510 };
9511
9512 --layout-self-center: {
9513 -ms-align-self: center;
9514 -webkit-align-self: center;
9515 align-self: center;
9516 };
9517
9518 --layout-self-end: {
9519 -ms-align-self: flex-end;
9520 -webkit-align-self: flex-end;
9521 align-self: flex-end;
9522 };
9523
9524 --layout-self-stretch: {
9525 -ms-align-self: stretch;
9526 -webkit-align-self: stretch;
9527 align-self: stretch;
9528 };
9529
9530 --layout-self-baseline: {
9531 -ms-align-self: baseline;
9532 -webkit-align-self: baseline;
9533 align-self: baseline;
9534 };
9535
9536 /* multi-line alignment in main axis */
9537
9538 --layout-start-aligned: {
9539 -ms-flex-line-pack: start; /* IE10 */
9540 -ms-align-content: flex-start;
9541 -webkit-align-content: flex-start;
9542 align-content: flex-start;
9543 };
9544
9545 --layout-end-aligned: {
9546 -ms-flex-line-pack: end; /* IE10 */
9547 -ms-align-content: flex-end;
9548 -webkit-align-content: flex-end;
9549 align-content: flex-end;
9550 };
9551
9552 --layout-center-aligned: {
9553 -ms-flex-line-pack: center; /* IE10 */
9554 -ms-align-content: center;
9555 -webkit-align-content: center;
9556 align-content: center;
9557 };
9558
9559 --layout-between-aligned: {
9560 -ms-flex-line-pack: justify; /* IE10 */
9561 -ms-align-content: space-between;
9562 -webkit-align-content: space-between;
9563 align-content: space-between;
9564 };
9565
9566 --layout-around-aligned: {
9567 -ms-flex-line-pack: distribute; /* IE10 */
9568 -ms-align-content: space-around;
9569 -webkit-align-content: space-around;
9570 align-content: space-around;
9571 };
9572
9573 /*******************************
9574 Other Layout
9575 *******************************/
9576
9577 --layout-block: {
9578 display: block;
9579 };
9580
9581 --layout-invisible: {
9582 visibility: hidden !important;
9583 };
9584
9585 --layout-relative: {
9586 position: relative;
9587 };
9588
9589 --layout-fit: {
9590 position: absolute;
9591 top: 0;
9592 right: 0;
9593 bottom: 0;
9594 left: 0;
9595 };
9596
9597 --layout-scroll: {
9598 -webkit-overflow-scrolling: touch;
9599 overflow: auto;
9600 };
9601
9602 --layout-fullbleed: {
9603 margin: 0;
9604 height: 100vh;
9605 };
9606
9607 /* fixed position */
9608
9609 --layout-fixed-top: {
9610 position: fixed;
9611 top: 0;
9612 left: 0;
9613 right: 0;
9614 };
9615
9616 --layout-fixed-right: {
9617 position: fixed;
9618 top: 0;
9619 right: 0;
9620 bottom: 0;
9621 };
9622
9623 --layout-fixed-bottom: {
9624 position: fixed;
9625 right: 0;
9626 bottom: 0;
9627 left: 0;
9628 };
9629
9630 --layout-fixed-left: {
9631 position: fixed;
9632 top: 0;
9633 bottom: 0;
9634 left: 0;
9635 };
9636
9637 }
9638
9639 </style>
9640
9641
9642 <dom-module id="app-drawer" assetpath="bower_components/app-layout/app-drawer/">
9643 <template>
9644 <style>
9645 :host {
9646 position: fixed;
9647 top: -120px;
9648 right: 0;
9649 bottom: -120px;
9650 left: 0;
9651
9652 visibility: hidden;
9653
9654 transition: visibility 0.2s ease;
9655 }
9656
9657 :host([opened]) {
9658 visibility: visible;
9659 }
9660
9661 :host([persistent]) {
9662 width: var(--app-drawer-width, 256px);
9663 }
9664
9665 :host([persistent][position=left]) {
9666 right: auto;
9667 }
9668
9669 :host([persistent][position=right]) {
9670 left: auto;
9671 }
9672
9673 #contentContainer {
9674 position: absolute;
9675 top: 0;
9676 bottom: 0;
9677 left: 0;
9678
9679 width: var(--app-drawer-width, 256px);
9680 padding: 120px 0;
9681
9682 transition: 0.2s ease;
9683 transition-property: -webkit-transform;
9684 transition-property: transform;
9685 -webkit-transform: translate3d(-100%, 0, 0);
9686 transform: translate3d(-100%, 0, 0);
9687
9688 background-color: #FFF;
9689
9690 @apply(--app-drawer-content-container);
9691 }
9692
9693 :host([position=right]) > #contentContainer {
9694 right: 0;
9695 left: auto;
9696
9697 -webkit-transform: translate3d(100%, 0, 0);
9698 transform: translate3d(100%, 0, 0);
9699 }
9700
9701 :host([swipe-open]) > #contentContainer::after {
9702 position: fixed;
9703 top: 0;
9704 bottom: 0;
9705 left: 100%;
9706
9707 visibility: visible;
9708
9709 width: 20px;
9710
9711 content: '';
9712 }
9713
9714 :host([swipe-open][position=right]) > #contentContainer::after {
9715 right: 100%;
9716 left: auto;
9717 }
9718
9719 :host([opened]) > #contentContainer {
9720 -webkit-transform: translate3d(0, 0, 0);
9721 transform: translate3d(0, 0, 0);
9722 }
9723
9724 #scrim {
9725 position: absolute;
9726 top: 0;
9727 right: 0;
9728 bottom: 0;
9729 left: 0;
9730
9731 transition: opacity 0.2s ease;
9732 -webkit-transform: translateZ(0);
9733 transform: translateZ(0);
9734
9735 opacity: 0;
9736 background: var(--app-drawer-scrim-background, rgba(0, 0, 0, 0.5));
9737 }
9738
9739 :host([opened]) > #scrim {
9740 opacity: 1;
9741 }
9742
9743 :host([opened][persistent]) > #scrim {
9744 visibility: hidden;
9745 /**
9746 * NOTE(keanulee): Keep both opacity: 0 and visibility: hidden to preven t the
9747 * scrim from showing when toggling between closed and opened/persistent .
9748 */
9749
9750 opacity: 0;
9751 }
9752 </style>
9753
9754 <div id="scrim" on-tap="close"></div>
9755
9756 <div id="contentContainer">
9757 <content></content>
9758 </div>
9759 </template>
9760
9761 <script>
9762
9763 Polymer({
9764 is: 'app-drawer',
9765
9766 properties: {
9767 /**
9768 * The opened state of the drawer.
9769 */
9770 opened: {
9771 type: Boolean,
9772 value: false,
9773 notify: true,
9774 reflectToAttribute: true
9775 },
9776
9777 /**
9778 * The drawer does not have a scrim and cannot be swiped close.
9779 */
9780 persistent: {
9781 type: Boolean,
9782 value: false,
9783 reflectToAttribute: true
9784 },
9785
9786 /**
9787 * The alignment of the drawer on the screen ('left', 'right', 'start' o r 'end').
9788 * 'start' computes to left and 'end' to right in LTR layout and vice ve rsa in RTL
9789 * layout.
9790 */
9791 align: {
9792 type: String,
9793 value: 'left'
9794 },
9795
9796 /**
9797 * The computed, read-only position of the drawer on the screen ('left' or 'right').
9798 */
9799 position: {
9800 type: String,
9801 readOnly: true,
9802 reflectToAttribute: true
9803 },
9804
9805 /**
9806 * Create an area at the edge of the screen to swipe open the drawer.
9807 */
9808 swipeOpen: {
9809 type: Boolean,
9810 value: false,
9811 reflectToAttribute: true
9812 },
9813
9814 /**
9815 * Trap keyboard focus when the drawer is opened and not persistent.
9816 */
9817 noFocusTrap: {
9818 type: Boolean,
9819 value: false
9820 }
9821 },
9822
9823 observers: [
9824 'resetLayout(position, isAttached)',
9825 '_resetPosition(align, isAttached)'
9826 ],
9827
9828 _translateOffset: 0,
9829
9830 _trackDetails: null,
9831
9832 _drawerState: 0,
9833
9834 _boundEscKeydownHandler: null,
9835
9836 _firstTabStop: null,
9837
9838 _lastTabStop: null,
9839
9840 ready: function() {
9841 // Only transition the drawer after its first render (e.g. app-drawer-la yout
9842 // may need to set the initial opened state which should not be transiti oned).
9843 this._setTransitionDuration('0s');
9844 },
9845
9846 attached: function() {
9847 // Only transition the drawer after its first render (e.g. app-drawer-la yout
9848 // may need to set the initial opened state which should not be transiti oned).
9849 Polymer.RenderStatus.afterNextRender(this, function() {
9850 this._setTransitionDuration('');
9851 this._boundEscKeydownHandler = this._escKeydownHandler.bind(this);
9852 this._resetDrawerState();
9853
9854 this.addEventListener('transitionend', this._transitionend.bind(this)) ;
9855 this.addEventListener('keydown', this._tabKeydownHandler.bind(this))
9856
9857 // Only listen for horizontal track so you can vertically scroll insid e the drawer.
9858 this.listen(this, 'track', '_track');
9859 this.setScrollDirection('y');
9860 });
9861 },
9862
9863 detached: function() {
9864 document.removeEventListener('keydown', this._boundEscKeydownHandler);
9865 },
9866
9867 /**
9868 * Opens the drawer.
9869 */
9870 open: function() {
9871 this.opened = true;
9872 },
9873
9874 /**
9875 * Closes the drawer.
9876 */
9877 close: function() {
9878 this.opened = false;
9879 },
9880
9881 /**
9882 * Toggles the drawer open and close.
9883 */
9884 toggle: function() {
9885 this.opened = !this.opened;
9886 },
9887
9888 /**
9889 * Gets the width of the drawer.
9890 *
9891 * @return {number} The width of the drawer in pixels.
9892 */
9893 getWidth: function() {
9894 return this.$.contentContainer.offsetWidth;
9895 },
9896
9897 /**
9898 * Resets the layout. The event fired is used by app-drawer-layout to posi tion the
9899 * content.
9900 *
9901 * @method resetLayout
9902 */
9903 resetLayout: function() {
9904 this.fire('app-drawer-reset-layout');
9905 },
9906
9907 _isRTL: function() {
9908 return window.getComputedStyle(this).direction === 'rtl';
9909 },
9910
9911 _resetPosition: function() {
9912 switch (this.align) {
9913 case 'start':
9914 this._setPosition(this._isRTL() ? 'right' : 'left');
9915 return;
9916 case 'end':
9917 this._setPosition(this._isRTL() ? 'left' : 'right');
9918 return;
9919 }
9920 this._setPosition(this.align);
9921 },
9922
9923 _escKeydownHandler: function(event) {
9924 var ESC_KEYCODE = 27;
9925 if (event.keyCode === ESC_KEYCODE) {
9926 // Prevent any side effects if app-drawer closes.
9927 event.preventDefault();
9928 this.close();
9929 }
9930 },
9931
9932 _track: function(event) {
9933 if (this.persistent) {
9934 return;
9935 }
9936
9937 // Disable user selection on desktop.
9938 event.preventDefault();
9939
9940 switch (event.detail.state) {
9941 case 'start':
9942 this._trackStart(event);
9943 break;
9944 case 'track':
9945 this._trackMove(event);
9946 break;
9947 case 'end':
9948 this._trackEnd(event);
9949 break;
9950 }
9951 },
9952
9953 _trackStart: function(event) {
9954 this._drawerState = this._DRAWER_STATE.TRACKING;
9955
9956 // Disable transitions since style attributes will reflect user track ev ents.
9957 this._setTransitionDuration('0s');
9958 this.style.visibility = 'visible';
9959
9960 var rect = this.$.contentContainer.getBoundingClientRect();
9961 if (this.position === 'left') {
9962 this._translateOffset = rect.left;
9963 } else {
9964 this._translateOffset = rect.right - window.innerWidth;
9965 }
9966
9967 this._trackDetails = [];
9968 },
9969
9970 _trackMove: function(event) {
9971 this._translateDrawer(event.detail.dx + this._translateOffset);
9972
9973 // Use Date.now() since event.timeStamp is inconsistent across browsers (e.g. most
9974 // browsers use milliseconds but FF 44 uses microseconds).
9975 this._trackDetails.push({
9976 dx: event.detail.dx,
9977 timeStamp: Date.now()
9978 });
9979 },
9980
9981 _trackEnd: function(event) {
9982 var x = event.detail.dx + this._translateOffset;
9983 var drawerWidth = this.getWidth();
9984 var isPositionLeft = this.position === 'left';
9985 var isInEndState = isPositionLeft ? (x >= 0 || x <= -drawerWidth) :
9986 (x <= 0 || x >= drawerWidth);
9987
9988 if (!isInEndState) {
9989 // No longer need the track events after this method returns - allow t hem to be GC'd.
9990 var trackDetails = this._trackDetails;
9991 this._trackDetails = null;
9992
9993 this._flingDrawer(event, trackDetails);
9994 if (this._drawerState === this._DRAWER_STATE.FLINGING) {
9995 return;
9996 }
9997 }
9998
9999 // If the drawer is not flinging, toggle the opened state based on the p osition of
10000 // the drawer.
10001 var halfWidth = drawerWidth / 2;
10002 if (event.detail.dx < -halfWidth) {
10003 this.opened = this.position === 'right';
10004 } else if (event.detail.dx > halfWidth) {
10005 this.opened = this.position === 'left';
10006 }
10007
10008 // Trigger app-drawer-transitioned now since there will be no transition end event.
10009 if (isInEndState) {
10010 this._resetDrawerState();
10011 }
10012
10013 this._setTransitionDuration('');
10014 this._resetDrawerTranslate();
10015 this.style.visibility = '';
10016 },
10017
10018 _calculateVelocity: function(event, trackDetails) {
10019 // Find the oldest track event that is within 100ms using binary search.
10020 var now = Date.now();
10021 var timeLowerBound = now - 100;
10022 var trackDetail;
10023 var min = 0;
10024 var max = trackDetails.length - 1;
10025
10026 while (min <= max) {
10027 // Floor of average of min and max.
10028 var mid = (min + max) >> 1;
10029 var d = trackDetails[mid];
10030 if (d.timeStamp >= timeLowerBound) {
10031 trackDetail = d;
10032 max = mid - 1;
10033 } else {
10034 min = mid + 1;
10035 }
10036 }
10037
10038 if (trackDetail) {
10039 var dx = event.detail.dx - trackDetail.dx;
10040 var dt = (now - trackDetail.timeStamp) || 1;
10041 return dx / dt;
10042 }
10043 return 0;
10044 },
10045
10046 _flingDrawer: function(event, trackDetails) {
10047 var velocity = this._calculateVelocity(event, trackDetails);
10048
10049 // Do not fling if velocity is not above a threshold.
10050 if (Math.abs(velocity) < this._MIN_FLING_THRESHOLD) {
10051 return;
10052 }
10053
10054 this._drawerState = this._DRAWER_STATE.FLINGING;
10055
10056 var x = event.detail.dx + this._translateOffset;
10057 var drawerWidth = this.getWidth();
10058 var isPositionLeft = this.position === 'left';
10059 var isVelocityPositive = velocity > 0;
10060 var isClosingLeft = !isVelocityPositive && isPositionLeft;
10061 var isClosingRight = isVelocityPositive && !isPositionLeft;
10062 var dx;
10063 if (isClosingLeft) {
10064 dx = -(x + drawerWidth);
10065 } else if (isClosingRight) {
10066 dx = (drawerWidth - x);
10067 } else {
10068 dx = -x;
10069 }
10070
10071 // Enforce a minimum transition velocity to make the drawer feel snappy.
10072 if (isVelocityPositive) {
10073 velocity = Math.max(velocity, this._MIN_TRANSITION_VELOCITY);
10074 this.opened = this.position === 'left';
10075 } else {
10076 velocity = Math.min(velocity, -this._MIN_TRANSITION_VELOCITY);
10077 this.opened = this.position === 'right';
10078 }
10079
10080 // Calculate the amount of time needed to finish the transition based on the
10081 // initial slope of the timing function.
10082 this._setTransitionDuration((this._FLING_INITIAL_SLOPE * dx / velocity) + 'ms');
10083 this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);
10084
10085 this._resetDrawerTranslate();
10086 },
10087
10088 _transitionend: function(event) {
10089 // contentContainer will transition on opened state changed, and scrim w ill
10090 // transition on persistent state changed when opened - these are the
10091 // transitions we are interested in.
10092 var target = Polymer.dom(event).rootTarget;
10093 if (target === this.$.contentContainer || target === this.$.scrim) {
10094
10095 // If the drawer was flinging, we need to reset the style attributes.
10096 if (this._drawerState === this._DRAWER_STATE.FLINGING) {
10097 this._setTransitionDuration('');
10098 this._setTransitionTimingFunction('');
10099 this.style.visibility = '';
10100 }
10101
10102 this._resetDrawerState();
10103 }
10104 },
10105
10106 _setTransitionDuration: function(duration) {
10107 this.$.contentContainer.style.transitionDuration = duration;
10108 this.$.scrim.style.transitionDuration = duration;
10109 },
10110
10111 _setTransitionTimingFunction: function(timingFunction) {
10112 this.$.contentContainer.style.transitionTimingFunction = timingFunction;
10113 this.$.scrim.style.transitionTimingFunction = timingFunction;
10114 },
10115
10116 _translateDrawer: function(x) {
10117 var drawerWidth = this.getWidth();
10118
10119 if (this.position === 'left') {
10120 x = Math.max(-drawerWidth, Math.min(x, 0));
10121 this.$.scrim.style.opacity = 1 + x / drawerWidth;
10122 } else {
10123 x = Math.max(0, Math.min(x, drawerWidth));
10124 this.$.scrim.style.opacity = 1 - x / drawerWidth;
10125 }
10126
10127 this.translate3d(x + 'px', '0', '0', this.$.contentContainer);
10128 },
10129
10130 _resetDrawerTranslate: function() {
10131 this.$.scrim.style.opacity = '';
10132 this.transform('', this.$.contentContainer);
10133 },
10134
10135 _resetDrawerState: function() {
10136 var oldState = this._drawerState;
10137 if (this.opened) {
10138 this._drawerState = this.persistent ?
10139 this._DRAWER_STATE.OPENED_PERSISTENT : this._DRAWER_STATE.OPENED;
10140 } else {
10141 this._drawerState = this._DRAWER_STATE.CLOSED;
10142 }
10143
10144 if (oldState !== this._drawerState) {
10145 if (this._drawerState === this._DRAWER_STATE.OPENED) {
10146 this._setKeyboardFocusTrap();
10147 document.addEventListener('keydown', this._boundEscKeydownHandler);
10148 document.body.style.overflow = 'hidden';
10149 } else {
10150 document.removeEventListener('keydown', this._boundEscKeydownHandler );
10151 document.body.style.overflow = '';
10152 }
10153
10154 // Don't fire the event on initial load.
10155 if (oldState !== this._DRAWER_STATE.INIT) {
10156 this.fire('app-drawer-transitioned');
10157 }
10158 }
10159 },
10160
10161 _setKeyboardFocusTrap: function() {
10162 if (this.noFocusTrap) {
10163 return;
10164 }
10165
10166 // NOTE: Unless we use /deep/ (which we shouldn't since it's deprecated) , this will
10167 // not select focusable elements inside shadow roots.
10168 var focusableElementsSelector = [
10169 'a[href]:not([tabindex="-1"])',
10170 'area[href]:not([tabindex="-1"])',
10171 'input:not([disabled]):not([tabindex="-1"])',
10172 'select:not([disabled]):not([tabindex="-1"])',
10173 'textarea:not([disabled]):not([tabindex="-1"])',
10174 'button:not([disabled]):not([tabindex="-1"])',
10175 'iframe:not([tabindex="-1"])',
10176 '[tabindex]:not([tabindex="-1"])',
10177 '[contentEditable=true]:not([tabindex="-1"])'
10178 ].join(',');
10179 var focusableElements = Polymer.dom(this).querySelectorAll(focusableElem entsSelector);
10180
10181 if (focusableElements.length > 0) {
10182 this._firstTabStop = focusableElements[0];
10183 this._lastTabStop = focusableElements[focusableElements.length - 1];
10184 } else {
10185 // Reset saved tab stops when there are no focusable elements in the d rawer.
10186 this._firstTabStop = null;
10187 this._lastTabStop = null;
10188 }
10189
10190 // Focus on app-drawer if it has non-zero tabindex. Otherwise, focus the first focusable
10191 // element in the drawer, if it exists. Use the tabindex attribute since the this.tabIndex
10192 // property in IE/Edge returns 0 (instead of -1) when the attribute is n ot set.
10193 var tabindex = this.getAttribute('tabindex');
10194 if (tabindex && parseInt(tabindex, 10) > -1) {
10195 this.focus();
10196 } else if (this._firstTabStop) {
10197 this._firstTabStop.focus();
10198 }
10199 },
10200
10201 _tabKeydownHandler: function(event) {
10202 if (this.noFocusTrap) {
10203 return;
10204 }
10205
10206 var TAB_KEYCODE = 9;
10207 if (this._drawerState === this._DRAWER_STATE.OPENED && event.keyCode === TAB_KEYCODE) {
10208 if (event.shiftKey) {
10209 if (this._firstTabStop && Polymer.dom(event).localTarget === this._f irstTabStop) {
10210 event.preventDefault();
10211 this._lastTabStop.focus();
10212 }
10213 } else {
10214 if (this._lastTabStop && Polymer.dom(event).localTarget === this._la stTabStop) {
10215 event.preventDefault();
10216 this._firstTabStop.focus();
10217 }
10218 }
10219 }
10220 },
10221
10222 _MIN_FLING_THRESHOLD: 0.2,
10223
10224 _MIN_TRANSITION_VELOCITY: 1.2,
10225
10226 _FLING_TIMING_FUNCTION: 'cubic-bezier(0.667, 1, 0.667, 1)',
10227
10228 _FLING_INITIAL_SLOPE: 1.5,
10229
10230 _DRAWER_STATE: {
10231 INIT: 0,
10232 OPENED: 1,
10233 OPENED_PERSISTENT: 2,
10234 CLOSED: 3,
10235 TRACKING: 4,
10236 FLINGING: 5
10237 }
10238
10239 /**
10240 * Fired when the layout of app-drawer has changed.
10241 *
10242 * @event app-drawer-reset-layout
10243 */
10244
10245 /**
10246 * Fired when app-drawer has finished transitioning.
10247 *
10248 * @event app-drawer-transitioned
10249 */
10250 });
10251 </script>
10252 </dom-module>
10253
10254
10255 <script>
10256
10257 Polymer({
10258
10259 is: 'iron-media-query',
10260
10261 properties: {
10262
10263 /**
10264 * The Boolean return value of the media query.
10265 */
10266 queryMatches: {
10267 type: Boolean,
10268 value: false,
10269 readOnly: true,
10270 notify: true
10271 },
10272
10273 /**
10274 * The CSS media query to evaluate.
10275 */
10276 query: {
10277 type: String,
10278 observer: 'queryChanged'
10279 },
10280
10281 /**
10282 * If true, the query attribute is assumed to be a complete media query
10283 * string rather than a single media feature.
10284 */
10285 full: {
10286 type: Boolean,
10287 value: false
10288 },
10289
10290 /**
10291 * @type {function(MediaQueryList)}
10292 */
10293 _boundMQHandler: {
10294 value: function() {
10295 return this.queryHandler.bind(this);
10296 }
10297 },
10298
10299 /**
10300 * @type {MediaQueryList}
10301 */
10302 _mq: {
10303 value: null
10304 }
10305 },
10306
10307 attached: function() {
10308 this.style.display = 'none';
10309 this.queryChanged();
10310 },
10311
10312 detached: function() {
10313 this._remove();
10314 },
10315
10316 _add: function() {
10317 if (this._mq) {
10318 this._mq.addListener(this._boundMQHandler);
10319 }
10320 },
10321
10322 _remove: function() {
10323 if (this._mq) {
10324 this._mq.removeListener(this._boundMQHandler);
10325 }
10326 this._mq = null;
10327 },
10328
10329 queryChanged: function() {
10330 this._remove();
10331 var query = this.query;
10332 if (!query) {
10333 return;
10334 }
10335 if (!this.full && query[0] !== '(') {
10336 query = '(' + query + ')';
10337 }
10338 this._mq = window.matchMedia(query);
10339 this._add();
10340 this.queryHandler(this._mq);
10341 },
10342
10343 queryHandler: function(mq) {
10344 this._setQueryMatches(mq.matches);
10345 }
10346
10347 });
10348
10349 </script>
10350 <script>
10351 /**
10352 * `IronResizableBehavior` is a behavior that can be used in Polymer elements to
10353 * coordinate the flow of resize events between "resizers" (elements that cont rol the
10354 * size or hidden state of their children) and "resizables" (elements that nee d to be
10355 * notified when they are resized or un-hidden by their parents in order to ta ke
10356 * action on their new measurements).
10357 *
10358 * Elements that perform measurement should add the `IronResizableBehavior` be havior to
10359 * their element definition and listen for the `iron-resize` event on themselv es.
10360 * This event will be fired when they become showing after having been hidden,
10361 * when they are resized explicitly by another resizable, or when the window h as been
10362 * resized.
10363 *
10364 * Note, the `iron-resize` event is non-bubbling.
10365 *
10366 * @polymerBehavior Polymer.IronResizableBehavior
10367 * @demo demo/index.html
10368 **/
10369 Polymer.IronResizableBehavior = {
10370 properties: {
10371 /**
10372 * The closest ancestor element that implements `IronResizableBehavior`.
10373 */
10374 _parentResizable: {
10375 type: Object,
10376 observer: '_parentResizableChanged'
10377 },
10378
10379 /**
10380 * True if this element is currently notifying its descedant elements of
10381 * resize.
10382 */
10383 _notifyingDescendant: {
10384 type: Boolean,
10385 value: false
10386 }
10387 },
10388
10389 listeners: {
10390 'iron-request-resize-notifications': '_onIronRequestResizeNotifications'
10391 },
10392
10393 created: function() {
10394 // We don't really need property effects on these, and also we want them
10395 // to be created before the `_parentResizable` observer fires:
10396 this._interestedResizables = [];
10397 this._boundNotifyResize = this.notifyResize.bind(this);
10398 },
10399
10400 attached: function() {
10401 this.fire('iron-request-resize-notifications', null, {
10402 node: this,
10403 bubbles: true,
10404 cancelable: true
10405 });
10406
10407 if (!this._parentResizable) {
10408 window.addEventListener('resize', this._boundNotifyResize);
10409 this.notifyResize();
10410 }
10411 },
10412
10413 detached: function() {
10414 if (this._parentResizable) {
10415 this._parentResizable.stopResizeNotificationsFor(this);
10416 } else {
10417 window.removeEventListener('resize', this._boundNotifyResize);
10418 }
10419
10420 this._parentResizable = null;
10421 },
10422
10423 /**
10424 * Can be called to manually notify a resizable and its descendant
10425 * resizables of a resize change.
10426 */
10427 notifyResize: function() {
10428 if (!this.isAttached) {
10429 return;
10430 }
10431
10432 this._interestedResizables.forEach(function(resizable) {
10433 if (this.resizerShouldNotify(resizable)) {
10434 this._notifyDescendant(resizable);
10435 }
10436 }, this);
10437
10438 this._fireResize();
10439 },
10440
10441 /**
10442 * Used to assign the closest resizable ancestor to this resizable
10443 * if the ancestor detects a request for notifications.
10444 */
10445 assignParentResizable: function(parentResizable) {
10446 this._parentResizable = parentResizable;
10447 },
10448
10449 /**
10450 * Used to remove a resizable descendant from the list of descendants
10451 * that should be notified of a resize change.
10452 */
10453 stopResizeNotificationsFor: function(target) {
10454 var index = this._interestedResizables.indexOf(target);
10455
10456 if (index > -1) {
10457 this._interestedResizables.splice(index, 1);
10458 this.unlisten(target, 'iron-resize', '_onDescendantIronResize');
10459 }
10460 },
10461
10462 /**
10463 * This method can be overridden to filter nested elements that should or
10464 * should not be notified by the current element. Return true if an element
10465 * should be notified, or false if it should not be notified.
10466 *
10467 * @param {HTMLElement} element A candidate descendant element that
10468 * implements `IronResizableBehavior`.
10469 * @return {boolean} True if the `element` should be notified of resize.
10470 */
10471 resizerShouldNotify: function(element) { return true; },
10472
10473 _onDescendantIronResize: function(event) {
10474 if (this._notifyingDescendant) {
10475 event.stopPropagation();
10476 return;
10477 }
10478
10479 // NOTE(cdata): In ShadowDOM, event retargetting makes echoing of the
10480 // otherwise non-bubbling event "just work." We do it manually here for
10481 // the case where Polymer is not using shadow roots for whatever reason:
10482 if (!Polymer.Settings.useShadow) {
10483 this._fireResize();
10484 }
10485 },
10486
10487 _fireResize: function() {
10488 this.fire('iron-resize', null, {
10489 node: this,
10490 bubbles: false
10491 });
10492 },
10493
10494 _onIronRequestResizeNotifications: function(event) {
10495 var target = event.path ? event.path[0] : event.target;
10496
10497 if (target === this) {
10498 return;
10499 }
10500
10501 if (this._interestedResizables.indexOf(target) === -1) {
10502 this._interestedResizables.push(target);
10503 this.listen(target, 'iron-resize', '_onDescendantIronResize');
10504 }
10505
10506 target.assignParentResizable(this);
10507 this._notifyDescendant(target);
10508
10509 event.stopPropagation();
10510 },
10511
10512 _parentResizableChanged: function(parentResizable) {
10513 if (parentResizable) {
10514 window.removeEventListener('resize', this._boundNotifyResize);
10515 }
10516 },
10517
10518 _notifyDescendant: function(descendant) {
10519 // NOTE(cdata): In IE10, attached is fired on children first, so it's
10520 // important not to notify them if the parent is not attached yet (or
10521 // else they will get redundantly notified when the parent attaches).
10522 if (!this.isAttached) {
10523 return;
10524 }
10525
10526 this._notifyingDescendant = true;
10527 descendant.notifyResize();
10528 this._notifyingDescendant = false;
10529 }
10530 };
10531 </script>
10532
10533
10534
10535 <dom-module id="app-drawer-layout" assetpath="bower_components/app-layout/app-dr awer-layout/">
10536 <template>
10537 <style>
10538 :host {
10539 display: block;
10540 }
10541
10542 :host([fullbleed]) {
10543 @apply(--layout-fit);
10544 }
10545
10546 #contentContainer {
10547 position: relative;
10548
10549 height: 100%;
10550
10551 transition: var(--app-drawer-layout-content-transition, none);
10552 }
10553
10554 #contentContainer:not(.narrow) > ::content [drawer-toggle] {
10555 display: none;
10556 }
10557 </style>
10558
10559 <div id="contentContainer">
10560 <content select=":not(app-drawer)"></content>
10561 </div>
10562
10563 <content id="drawerContent" select="app-drawer"></content>
10564
10565 <iron-media-query query="[[_computeMediaQuery(forceNarrow, responsiveWidth)] ]" on-query-matches-changed="_onQueryMatchesChanged"></iron-media-query>
10566 </template>
10567
10568 <script>
10569 Polymer({
10570 is: 'app-drawer-layout',
10571
10572 behaviors: [
10573 Polymer.IronResizableBehavior
10574 ],
10575
10576 properties: {
10577 /**
10578 * If true, ignore `responsiveWidth` setting and force the narrow layout .
10579 */
10580 forceNarrow: {
10581 type: Boolean,
10582 value: false
10583 },
10584
10585 /**
10586 * If the viewport's width is smaller than this value, the panel will ch ange to narrow
10587 * layout. In the mode the drawer will be closed.
10588 */
10589 responsiveWidth: {
10590 type: String,
10591 value: '640px'
10592 },
10593
10594 /**
10595 * Returns true if it is in narrow layout. This is useful if you need to show/hide
10596 * elements based on the layout.
10597 */
10598 narrow: {
10599 type: Boolean,
10600 readOnly: true,
10601 notify: true
10602 }
10603 },
10604
10605 listeners: {
10606 'tap': '_tapHandler',
10607 'app-drawer-reset-layout': 'resetLayout'
10608 },
10609
10610 observers: [
10611 'resetLayout(narrow, isAttached)'
10612 ],
10613
10614 /**
10615 * A reference to the app-drawer element.
10616 *
10617 * @property drawer
10618 */
10619 get drawer() {
10620 return Polymer.dom(this.$.drawerContent).getDistributedNodes()[0];
10621 },
10622
10623 _tapHandler: function(e) {
10624 var target = Polymer.dom(e).localTarget;
10625 if (target && target.hasAttribute('drawer-toggle')) {
10626 this.drawer.toggle();
10627 }
10628 },
10629
10630 resetLayout: function() {
10631 this.debounce('_resetLayout', function() {
10632 var drawer = this.drawer;
10633 var contentContainer = this.$.contentContainer;
10634
10635 if (this.narrow) {
10636 drawer.opened = drawer.persistent = false;
10637 contentContainer.classList.add('narrow');
10638
10639 contentContainer.style.marginLeft = '';
10640 contentContainer.style.marginRight = '';
10641 } else {
10642 drawer.opened = drawer.persistent = true;
10643 contentContainer.classList.remove('narrow');
10644
10645 var drawerWidth = this.drawer.getWidth();
10646 if (drawer.position == 'right') {
10647 contentContainer.style.marginLeft = '';
10648 contentContainer.style.marginRight = drawerWidth + 'px';
10649 } else {
10650 contentContainer.style.marginLeft = drawerWidth + 'px';
10651 contentContainer.style.marginRight = '';
10652 }
10653 }
10654
10655 this.notifyResize();
10656 });
10657 },
10658
10659 _onQueryMatchesChanged: function(event) {
10660 this._setNarrow(event.detail.value);
10661 },
10662
10663 _computeMediaQuery: function(forceNarrow, responsiveWidth) {
10664 return forceNarrow ? '(min-width: 0px)' : '(max-width: ' + responsiveWid th + ')';
10665 }
10666 });
10667 </script>
10668 </dom-module>
10669
10670
10671 <dom-module id="app-grid-style" assetpath="bower_components/app-layout/app-grid/ ">
10672 <template>
10673 <style>
10674
10675 :host {
10676 /**
10677 * The width for the expandible item is:
10678 * ((100% - subPixelAdjustment) / columns * itemColumns - gutter * (colu mns - itemColumns)
10679 *
10680 * - subPixelAdjustment: 0.1px (Required for IE 11)
10681 * - gutter: var(--app-grid-gutter)
10682 * - columns: var(--app-grid-columns)
10683 * - itemColumn: var(--app-grid-expandible-item-columns)
10684 */
10685 --app-grid-expandible-item: {
10686 -webkit-flex-basis: calc((100% - 0.1px) / var(--app-grid-columns, 1) * var(--app-grid-expandible-item-columns, 1) - (var(--app-grid-gutter, 0px) * (va r(--app-grid-columns, 1) - var(--app-grid-expandible-item-columns, 1)))) !import ant;
10687 flex-basis: calc((100% - 0.1px) / var(--app-grid-columns, 1) * var(--a pp-grid-expandible-item-columns, 1) - (var(--app-grid-gutter, 0px) * (var(--app- grid-columns, 1) - var(--app-grid-expandible-item-columns, 1)))) !important;
10688 max-width: calc((100% - 0.1px) / var(--app-grid-columns, 1) * var(--ap p-grid-expandible-item-columns, 1) - (var(--app-grid-gutter, 0px) * (var(--app-g rid-columns, 1) - var(--app-grid-expandible-item-columns, 1)))) !important;
10689
10690 };
10691 }
10692
10693 .app-grid {
10694 display: -ms-flexbox;
10695 display: -webkit-flex;
10696 display: flex;
10697
10698 -ms-flex-direction: row;
10699 -webkit-flex-direction: row;
10700 flex-direction: row;
10701
10702 -ms-flex-wrap: wrap;
10703 -webkit-flex-wrap: wrap;
10704 flex-wrap: wrap;
10705
10706 margin-top: var(--app-grid-gutter, 0px);
10707 margin-left: var(--app-grid-gutter, 0px);
10708 }
10709
10710 .app-grid > * {
10711 /* Required for IE 10 */
10712 -ms-flex: 1 1 100%;
10713 -webkit-flex: 1;
10714 flex: 1;
10715
10716 /* The width for an item is: (100% - subPixelAdjustment - gutter * colum ns) / columns */
10717 -webkit-flex-basis: calc((100% - 0.1px - (var(--app-grid-gutter, 0px) * var(--app-grid-columns, 1))) / var(--app-grid-columns, 1));
10718 flex-basis: calc((100% - 0.1px - (var(--app-grid-gutter, 0px) * var(--ap p-grid-columns, 1))) / var(--app-grid-columns, 1));
10719
10720 max-width: calc((100% - 0.1px - (var(--app-grid-gutter, 0px) * var(--app -grid-columns, 1))) / var(--app-grid-columns, 1));
10721 margin-bottom: var(--app-grid-gutter, 0px);
10722 margin-right: var(--app-grid-gutter, 0px);
10723 height: var(--app-grid-item-height);
10724 box-sizing: border-box;
10725 }
10726
10727 .app-grid[has-aspect-ratio] > * {
10728 position: relative;
10729 }
10730
10731 .app-grid[has-aspect-ratio] > *::before {
10732 display: block;
10733 content: "";
10734 padding-top: var(--app-grid-item-height, 100%);
10735 }
10736
10737 .app-grid[has-aspect-ratio] > * > * {
10738 position: absolute;
10739 top: 0;
10740 right: 0;
10741 bottom: 0;
10742 left: 0;
10743 }
10744
10745 </style>
10746 </template>
10747 </dom-module>
10748 <script>
10749
10750 /**
10751 * `Polymer.IronScrollTargetBehavior` allows an element to respond to scroll e vents from a
10752 * designated scroll target.
10753 *
10754 * Elements that consume this behavior can override the `_scrollHandler`
10755 * method to add logic on the scroll event.
10756 *
10757 * @demo demo/scrolling-region.html Scrolling Region
10758 * @demo demo/document.html Document Element
10759 * @polymerBehavior
10760 */
10761 Polymer.IronScrollTargetBehavior = {
10762
10763 properties: {
10764
10765 /**
10766 * Specifies the element that will handle the scroll event
10767 * on the behalf of the current element. This is typically a reference to an element,
10768 * but there are a few more posibilities:
10769 *
10770 * ### Elements id
10771 *
10772 *```html
10773 * <div id="scrollable-element" style="overflow: auto;">
10774 * <x-element scroll-target="scrollable-element">
10775 * <!-- Content-->
10776 * </x-element>
10777 * </div>
10778 *```
10779 * In this case, the `scrollTarget` will point to the outer div element.
10780 *
10781 * ### Document scrolling
10782 *
10783 * For document scrolling, you can use the reserved word `document`:
10784 *
10785 *```html
10786 * <x-element scroll-target="document">
10787 * <!-- Content -->
10788 * </x-element>
10789 *```
10790 *
10791 * ### Elements reference
10792 *
10793 *```js
10794 * appHeader.scrollTarget = document.querySelector('#scrollable-element');
10795 *```
10796 *
10797 * @type {HTMLElement}
10798 */
10799 scrollTarget: {
10800 type: HTMLElement,
10801 value: function() {
10802 return this._defaultScrollTarget;
10803 }
10804 }
10805 },
10806
10807 observers: [
10808 '_scrollTargetChanged(scrollTarget, isAttached)'
10809 ],
10810
10811 _scrollTargetChanged: function(scrollTarget, isAttached) {
10812 var eventTarget;
10813
10814 if (this._oldScrollTarget) {
10815 eventTarget = this._oldScrollTarget === this._doc ? window : this._oldSc rollTarget;
10816 eventTarget.removeEventListener('scroll', this._boundScrollHandler);
10817 this._oldScrollTarget = null;
10818 }
10819
10820 if (!isAttached) {
10821 return;
10822 }
10823 // Support element id references
10824 if (scrollTarget === 'document') {
10825
10826 this.scrollTarget = this._doc;
10827
10828 } else if (typeof scrollTarget === 'string') {
10829
10830 this.scrollTarget = this.domHost ? this.domHost.$[scrollTarget] :
10831 Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
10832
10833 } else if (this._isValidScrollTarget()) {
10834
10835 eventTarget = scrollTarget === this._doc ? window : scrollTarget;
10836 this._boundScrollHandler = this._boundScrollHandler || this._scrollHandl er.bind(this);
10837 this._oldScrollTarget = scrollTarget;
10838
10839 eventTarget.addEventListener('scroll', this._boundScrollHandler);
10840 }
10841 },
10842
10843 /**
10844 * Runs on every scroll event. Consumer of this behavior may override this m ethod.
10845 *
10846 * @protected
10847 */
10848 _scrollHandler: function scrollHandler() {},
10849
10850 /**
10851 * The default scroll target. Consumers of this behavior may want to customi ze
10852 * the default scroll target.
10853 *
10854 * @type {Element}
10855 */
10856 get _defaultScrollTarget() {
10857 return this._doc;
10858 },
10859
10860 /**
10861 * Shortcut for the document element
10862 *
10863 * @type {Element}
10864 */
10865 get _doc() {
10866 return this.ownerDocument.documentElement;
10867 },
10868
10869 /**
10870 * Gets the number of pixels that the content of an element is scrolled upwa rd.
10871 *
10872 * @type {number}
10873 */
10874 get _scrollTop() {
10875 if (this._isValidScrollTarget()) {
10876 return this.scrollTarget === this._doc ? window.pageYOffset : this.scrol lTarget.scrollTop;
10877 }
10878 return 0;
10879 },
10880
10881 /**
10882 * Gets the number of pixels that the content of an element is scrolled to t he left.
10883 *
10884 * @type {number}
10885 */
10886 get _scrollLeft() {
10887 if (this._isValidScrollTarget()) {
10888 return this.scrollTarget === this._doc ? window.pageXOffset : this.scrol lTarget.scrollLeft;
10889 }
10890 return 0;
10891 },
10892
10893 /**
10894 * Sets the number of pixels that the content of an element is scrolled upwa rd.
10895 *
10896 * @type {number}
10897 */
10898 set _scrollTop(top) {
10899 if (this.scrollTarget === this._doc) {
10900 window.scrollTo(window.pageXOffset, top);
10901 } else if (this._isValidScrollTarget()) {
10902 this.scrollTarget.scrollTop = top;
10903 }
10904 },
10905
10906 /**
10907 * Sets the number of pixels that the content of an element is scrolled to t he left.
10908 *
10909 * @type {number}
10910 */
10911 set _scrollLeft(left) {
10912 if (this.scrollTarget === this._doc) {
10913 window.scrollTo(left, window.pageYOffset);
10914 } else if (this._isValidScrollTarget()) {
10915 this.scrollTarget.scrollLeft = left;
10916 }
10917 },
10918
10919 /**
10920 * Scrolls the content to a particular place.
10921 *
10922 * @method scroll
10923 * @param {number} left The left position
10924 * @param {number} top The top position
10925 */
10926 scroll: function(left, top) {
10927 if (this.scrollTarget === this._doc) {
10928 window.scrollTo(left, top);
10929 } else if (this._isValidScrollTarget()) {
10930 this.scrollTarget.scrollLeft = left;
10931 this.scrollTarget.scrollTop = top;
10932 }
10933 },
10934
10935 /**
10936 * Gets the width of the scroll target.
10937 *
10938 * @type {number}
10939 */
10940 get _scrollTargetWidth() {
10941 if (this._isValidScrollTarget()) {
10942 return this.scrollTarget === this._doc ? window.innerWidth : this.scroll Target.offsetWidth;
10943 }
10944 return 0;
10945 },
10946
10947 /**
10948 * Gets the height of the scroll target.
10949 *
10950 * @type {number}
10951 */
10952 get _scrollTargetHeight() {
10953 if (this._isValidScrollTarget()) {
10954 return this.scrollTarget === this._doc ? window.innerHeight : this.scrol lTarget.offsetHeight;
10955 }
10956 return 0;
10957 },
10958
10959 /**
10960 * Returns true if the scroll target is a valid HTMLElement.
10961 *
10962 * @return {boolean}
10963 */
10964 _isValidScrollTarget: function() {
10965 return this.scrollTarget instanceof HTMLElement;
10966 }
10967 };
10968
10969 </script>
10970 <script>
10971 /**
10972 * `Polymer.AppScrollEffectsBehavior` provides an interface that allows an ele ment to use scrolls effects.
10973 *
10974 * ### Importing the app-layout effects
10975 *
10976 * app-layout provides a set of scroll effects that can be used by explicitly importing
10977 * `app-scroll-effects.html`:
10978 *
10979 * ```html
10980 * <link rel="import" href="/bower_components/app-layout/app-scroll-effects/ap p-scroll-effects.html">
10981 * ```
10982 *
10983 * The scroll effects can also be used by individually importing
10984 * `app-layout/app-scroll-effects/effects/[effectName].html`. For example:
10985 *
10986 * ```html
10987 * <link rel="import" href="/bower_components/app-layout/app-scroll-effects/e ffects/waterfall.html">
10988 * ```
10989 *
10990 * ### Consuming effects
10991 *
10992 * Effects can be consumed via the `effects` property. For example:
10993 *
10994 * ```html
10995 * <app-header effects="waterfall"></app-header>
10996 * ```
10997 *
10998 * ### Creating scroll effects
10999 *
11000 * You may want to create a custom scroll effect if you need to modify the CSS of an element
11001 * based on the scroll position.
11002 *
11003 * A scroll effect definition is an object with `setUp()`, `tearDown()` and `r un()` functions.
11004 *
11005 * To register the effect, you can use `Polymer.AppLayout.registerEffect(effec tName, effectDef)`
11006 * For example, let's define an effect that resizes the header's logo:
11007 *
11008 * ```js
11009 * Polymer.AppLayout.registerEffect('resizable-logo', {
11010 * setUp: function(config) {
11011 * // the effect's config is passed to the setUp.
11012 * this._fxResizeLogo = { logo: Polymer.dom(this).querySelector('[logo]') };
11013 * },
11014 *
11015 * run: function(progress) {
11016 * // the progress of the effect
11017 * this.transform('scale3d(' + progress + ', '+ progress +', 1)', this._ fxResizeLogo.logo);
11018 * },
11019 *
11020 * tearDown: function() {
11021 * // clean up and reset of states
11022 * delete this._fxResizeLogo;
11023 * }
11024 * });
11025 * ```
11026 * Now, you can consume the effect:
11027 *
11028 * ```html
11029 * <app-header id="appHeader" effects="resizable-logo">
11030 * <img logo src="logo.svg">
11031 * </app-header>
11032 * ```
11033 *
11034 * ### Imperative API
11035 *
11036 * ```js
11037 * var logoEffect = appHeader.createEffect('resizable-logo', effectConfig);
11038 * // run the effect: logoEffect.run(progress);
11039 * // tear down the effect: logoEffect.tearDown();
11040 * ```
11041 *
11042 * ### Configuring effects
11043 *
11044 * For effects installed via the `effects` property, their configuration can b e set
11045 * via the `effectsConfig` property. For example:
11046 *
11047 * ```html
11048 * <app-header effects="waterfall"
11049 * effects-config='{"waterfall": {"startsAt": 0, "endsAt": 0.5}}'>
11050 * </app-header>
11051 * ```
11052 *
11053 * All effects have a `startsAt` and `endsAt` config property. They specify at what
11054 * point the effect should start and end. This value goes from 0 to 1 inclusiv e.
11055 *
11056 * @polymerBehavior
11057 */
11058 Polymer.AppScrollEffectsBehavior = [
11059 Polymer.IronScrollTargetBehavior,
11060 {
11061
11062 properties: {
11063
11064 /**
11065 * A space-separated list of the effects names that will be triggered when the user scrolls.
11066 * e.g. `waterfall parallax-background` installs the `waterfall` and `para llax-background`.
11067 */
11068 effects: {
11069 type: String
11070 },
11071
11072 /**
11073 * An object that configurates the effects installed via the `effects` pro perty. e.g.
11074 * ```js
11075 * element.effectsConfig = {
11076 * "blend-background": {
11077 * "startsAt": 0.5
11078 * }
11079 * };
11080 * ```
11081 * Every effect has at least two config properties: `startsAt` and `endsAt `.
11082 * These properties indicate when the event should start and end respectiv ely
11083 * and relative to the overall element progress. So for example, if `blend -background`
11084 * starts at `0.5`, the effect will only start once the current element re aches 0.5
11085 * of its progress. In this context, the progress is a value in the range of `[0, 1]`
11086 * that indicates where this element is on the screen relative to the view port.
11087 */
11088 effectsConfig: {
11089 type: Object,
11090 value: function() {
11091 return {};
11092 }
11093 },
11094
11095 /**
11096 * Disables CSS transitions and scroll effects on the element.
11097 */
11098 disabled: {
11099 type: Boolean,
11100 reflectToAttribute: true,
11101 value: false
11102 }
11103 },
11104
11105 observers: [
11106 '_effectsChanged(effects, effectsConfig, isAttached)'
11107 ],
11108
11109 /**
11110 * Updates the scroll state. This method should be overridden
11111 * by the consumer of this behavior.
11112 *
11113 * @method _updateScrollState
11114 */
11115 _updateScrollState: function() {},
11116
11117 /**
11118 * Returns true if the current element is on the screen.
11119 * That is, visible in the current viewport. This method should be
11120 * overridden by the consumer of this behavior.
11121 *
11122 * @method isOnScreen
11123 * @return {boolean}
11124 */
11125 isOnScreen: function() {
11126 return false;
11127 },
11128
11129 /**
11130 * Returns true if there's content below the current element. This method
11131 * should be overridden by the consumer of this behavior.
11132 *
11133 * @method isContentBelow
11134 * @return {boolean}
11135 */
11136 isContentBelow: function() {
11137 return false;
11138 },
11139
11140 /**
11141 * List of effects handlers that will take place during scroll.
11142 *
11143 * @type {Array<Function>}
11144 */
11145 _effectsRunFn: null,
11146
11147 /**
11148 * List of the effects definitions installed via the `effects` property.
11149 *
11150 * @type {Array<Object>}
11151 */
11152 _effects: null,
11153
11154 /**
11155 * The clamped value of `_scrollTop`.
11156 * @type number
11157 */
11158 get _clampedScrollTop() {
11159 return Math.max(0, this._scrollTop);
11160 },
11161
11162 detached: function() {
11163 this._tearDownEffects();
11164 },
11165
11166 /**
11167 * Creates an effect object from an effect's name that can be used to run
11168 * effects programmatically.
11169 *
11170 * @method createEffect
11171 * @param {string} effectName The effect's name registered via `Polymer.AppL ayout.registerEffect`.
11172 * @param {Object=} effectConfig The effect config object. (Optional)
11173 * @return {Object} An effect object with the following functions:
11174 *
11175 * * `effect.setUp()`, Sets up the requirements for the effect.
11176 * This function is called automatically before the `effect` function returns.
11177 * * `effect.run(progress, y)`, Runs the effect given a `progress`.
11178 * * `effect.tearDown()`, Cleans up any DOM nodes or element references use d by the effect.
11179 *
11180 * Example:
11181 * ```js
11182 * var parallax = element.createEffect('parallax-background');
11183 * // runs the effect
11184 * parallax.run(0.5, 0);
11185 * ```
11186 */
11187 createEffect: function(effectName, effectConfig) {
11188 var effectDef = Polymer.AppLayout._scrollEffects[effectName];
11189 if (!effectDef) {
11190 throw new ReferenceError(this._getUndefinedMsg(effectName));
11191 }
11192 var prop = this._boundEffect(effectDef, effectConfig || {});
11193 prop.setUp();
11194 return prop;
11195 },
11196
11197 /**
11198 * Called when `effects` or `effectsConfig` changes.
11199 */
11200 _effectsChanged: function(effects, effectsConfig, isAttached) {
11201 this._tearDownEffects();
11202
11203 if (effects === '' || !isAttached) {
11204 return;
11205 }
11206 effects.split(' ').forEach(function(effectName) {
11207 var effectDef;
11208 if (effectName !== '') {
11209 if ((effectDef = Polymer.AppLayout._scrollEffects[effectName])) {
11210 this._effects.push(this._boundEffect(effectDef, effectsConfig[effect Name]));
11211 } else {
11212 this._warn(this._logf('_effectsChanged', this._getUndefinedMsg(effec tName)));
11213 }
11214 }
11215 }, this);
11216
11217 this._setUpEffect();
11218 },
11219
11220 /**
11221 * Forces layout
11222 */
11223 _layoutIfDirty: function() {
11224 return this.offsetWidth;
11225 },
11226
11227 /**
11228 * Returns an effect object bound to the current context.
11229 *
11230 * @param {Object} effectDef
11231 * @param {Object=} effectsConfig The effect config object if the effect acc epts config values. (Optional)
11232 */
11233 _boundEffect: function(effectDef, effectsConfig) {
11234 effectsConfig = effectsConfig || {};
11235 var startsAt = parseFloat(effectsConfig.startsAt || 0);
11236 var endsAt = parseFloat(effectsConfig.endsAt || 1);
11237 var deltaS = endsAt - startsAt;
11238 var noop = Function();
11239 // fast path if possible
11240 var runFn = (startsAt === 0 && endsAt === 1) ? effectDef.run :
11241 function(progress, y) {
11242 effectDef.run.call(this,
11243 Math.max(0, (progress - startsAt) / deltaS), y);
11244 };
11245 return {
11246 setUp: effectDef.setUp ? effectDef.setUp.bind(this, effectsConfig) : noo p,
11247 run: effectDef.run ? runFn.bind(this) : noop,
11248 tearDown: effectDef.tearDown ? effectDef.tearDown.bind(this) : noop
11249 };
11250 },
11251
11252 /**
11253 * Sets up the effects.
11254 */
11255 _setUpEffect: function() {
11256 if (this.isAttached && this._effects) {
11257 this._effectsRunFn = [];
11258 this._effects.forEach(function(effectDef) {
11259 // install the effect only if no error was reported
11260 if (effectDef.setUp() !== false) {
11261 this._effectsRunFn.push(effectDef.run);
11262 }
11263 }, this);
11264 }
11265 },
11266
11267 /**
11268 * Tears down the effects.
11269 */
11270 _tearDownEffects: function() {
11271 if (this._effects) {
11272 this._effects.forEach(function(effectDef) {
11273 effectDef.tearDown();
11274 });
11275 }
11276 this._effectsRunFn = [];
11277 this._effects = [];
11278 },
11279
11280 /**
11281 * Runs the effects.
11282 *
11283 * @param {number} p The progress
11284 * @param {number} y The top position of the current element relative to the viewport.
11285 */
11286 _runEffects: function(p, y) {
11287 if (this._effectsRunFn) {
11288 this._effectsRunFn.forEach(function(run) {
11289 run(p, y);
11290 });
11291 }
11292 },
11293
11294 /**
11295 * Overrides the `_scrollHandler`.
11296 */
11297 _scrollHandler: function() {
11298 if (!this.disabled) {
11299 this._updateScrollState(this._clampedScrollTop);
11300 }
11301 },
11302
11303 /**
11304 * Override this method to return a reference to a node in the local DOM.
11305 * The node is consumed by a scroll effect.
11306 *
11307 * @param {string} id The id for the node.
11308 */
11309 _getDOMRef: function(id) {
11310 this._warn(this._logf('_getDOMRef', '`'+ id +'` is undefined'));
11311 },
11312
11313 _getUndefinedMsg: function(effectName) {
11314 return 'Scroll effect `' + effectName + '` is undefined. ' +
11315 'Did you forget to import app-layout/app-scroll-effects/effects/' + ef fectName + '.html ?';
11316 }
11317
11318 }];
11319
11320 </script>
11321
11322
11323 <dom-module id="app-header" assetpath="bower_components/app-layout/app-header/">
11324 <template>
11325 <style>
11326 :host {
11327 position: relative;
11328 display: block;
11329 transition-timing-function: linear;
11330 transition-property: -webkit-transform;
11331 transition-property: transform;
11332 }
11333
11334 :host::after {
11335 position: absolute;
11336 right: 0px;
11337 bottom: -5px;
11338 left: 0px;
11339 width: 100%;
11340 height: 5px;
11341 content: "";
11342 transition: opacity 0.4s;
11343 pointer-events: none;
11344 opacity: 0;
11345 box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4);
11346 will-change: opacity;
11347 @apply(--app-header-shadow);
11348 }
11349
11350 :host([shadow])::after {
11351 opacity: 1;
11352 }
11353
11354 #contentContainer > ::content [condensed-title] {
11355 -webkit-transform-origin: left top;
11356 transform-origin: left top;
11357 white-space: nowrap;
11358 opacity: 0;
11359 }
11360
11361 #contentContainer > ::content [main-title] {
11362 -webkit-transform-origin: left top;
11363 transform-origin: left top;
11364 white-space: nowrap;
11365 }
11366
11367 #background {
11368 @apply(--layout-fit);
11369 overflow: hidden;
11370 }
11371
11372 #backgroundFrontLayer,
11373 #backgroundRearLayer {
11374 @apply(--layout-fit);
11375 height: 100%;
11376 pointer-events: none;
11377 background-size: cover;
11378 }
11379
11380 #backgroundFrontLayer {
11381 @apply(--app-header-background-front-layer);
11382 }
11383
11384 #backgroundRearLayer {
11385 opacity: 0;
11386 @apply(--app-header-background-rear-layer);
11387 }
11388
11389 #contentContainer {
11390 position: relative;
11391 width: 100%;
11392 height: 100%;
11393 }
11394
11395 :host([disabled]),
11396 :host([disabled])::after,
11397 :host([disabled]) #backgroundFrontLayer,
11398 :host([disabled]) #backgroundRearLayer,
11399 :host([disabled]) ::content > app-toolbar:first-of-type,
11400 :host([disabled]) ::content > [sticky],
11401 /* Silent scrolling should not run CSS transitions */
11402 :host-context(.app-layout-silent-scroll),
11403 :host-context(.app-layout-silent-scroll)::after,
11404 :host-context(.app-layout-silent-scroll) #backgroundFrontLayer,
11405 :host-context(.app-layout-silent-scroll) #backgroundRearLayer,
11406 :host-context(.app-layout-silent-scroll) ::content > app-toolbar:first-of- type,
11407 :host-context(.app-layout-silent-scroll) ::content > [sticky] {
11408 transition: none !important;
11409 }
11410 </style>
11411 <div id="contentContainer">
11412 <content id="content"></content>
11413 </div>
11414 </template>
11415
11416 <script>
11417 Polymer({
11418 is: 'app-header',
11419
11420 behaviors: [
11421 Polymer.AppScrollEffectsBehavior,
11422 Polymer.IronResizableBehavior
11423 ],
11424
11425 properties: {
11426 /**
11427 * If true, the header will automatically collapse when scrolling down.
11428 * That is, the `sticky` element remains visible when the header is full y condensed
11429 * whereas the rest of the elements will collapse below `sticky` element .
11430 *
11431 * By default, the `sticky` element is the first toolbar in the light DO M:
11432 *
11433 *```html
11434 * <app-header condenses>
11435 * <app-toolbar>This toolbar remains on top</app-toolbar>
11436 * <app-toolbar></app-toolbar>
11437 * <app-toolbar></app-toolbar>
11438 * </app-header>
11439 * ```
11440 *
11441 * Additionally, you can specify which toolbar or element remains visibl e in condensed mode
11442 * by adding the `sticky` attribute to that element. For example: if we want the last
11443 * toolbar to remain visible, we can add the `sticky` attribute to it.
11444 *
11445 *```html
11446 * <app-header condenses>
11447 * <app-toolbar></app-toolbar>
11448 * <app-toolbar></app-toolbar>
11449 * <app-toolbar sticky>This toolbar remains on top</app-toolbar>
11450 * </app-header>
11451 * ```
11452 *
11453 * Note the `sticky` element must be a direct child of `app-header`.
11454 */
11455 condenses: {
11456 type: Boolean,
11457 value: false
11458 },
11459
11460 /**
11461 * Mantains the header fixed at the top so it never moves away.
11462 */
11463 fixed: {
11464 type: Boolean,
11465 value: false
11466 },
11467
11468 /**
11469 * Slides back the header when scrolling back up.
11470 */
11471 reveals: {
11472 type: Boolean,
11473 value: false
11474 },
11475
11476 /**
11477 * Displays a shadow below the header.
11478 */
11479 shadow: {
11480 type: Boolean,
11481 reflectToAttribute: true,
11482 value: false
11483 }
11484 },
11485
11486 observers: [
11487 'resetLayout(isAttached, condenses, fixed)'
11488 ],
11489
11490 listeners: {
11491 'iron-resize': '_resizeHandler'
11492 },
11493
11494 /**
11495 * A cached offsetHeight of the current element.
11496 *
11497 * @type {number}
11498 */
11499 _height: 0,
11500
11501 /**
11502 * The distance in pixels the header will be translated to when scrolling.
11503 *
11504 * @type {number}
11505 */
11506 _dHeight: 0,
11507
11508 /**
11509 * The offsetTop of `_stickyEl`
11510 *
11511 * @type {number}
11512 */
11513 _stickyElTop: 0,
11514
11515 /**
11516 * The element that remains visible when the header condenses.
11517 *
11518 * @type {HTMLElement}
11519 */
11520 _stickyEl: null,
11521
11522 /**
11523 * The header's top value used for the `transformY`
11524 *
11525 * @type {number}
11526 */
11527 _top: 0,
11528
11529 /**
11530 * The current scroll progress.
11531 *
11532 * @type {number}
11533 */
11534 _progress: 0,
11535
11536 _wasScrollingDown: false,
11537 _initScrollTop: 0,
11538 _initTimestamp: 0,
11539 _lastTimestamp: 0,
11540 _lastScrollTop: 0,
11541
11542 /**
11543 * The distance the header is allowed to move away.
11544 *
11545 * @type {number}
11546 */
11547 get _maxHeaderTop() {
11548 return this.fixed ? this._dHeight : this._height + 5;
11549 },
11550
11551 /**
11552 * Returns a reference to the sticky element.
11553 *
11554 * @return {HTMLElement}?
11555 */
11556 _getStickyEl: function() {
11557 /** @type {HTMLElement} */
11558 var stickyEl;
11559 var nodes = Polymer.dom(this.$.content).getDistributedNodes();
11560
11561 for (var i = 0; i < nodes.length; i++) {
11562 if (nodes[i].nodeType === Node.ELEMENT_NODE) {
11563 var node = /** @type {HTMLElement} */ (nodes[i]);
11564 if (node.hasAttribute('sticky')) {
11565 stickyEl = node;
11566 break;
11567 } else if (!stickyEl) {
11568 stickyEl = node;
11569 }
11570 }
11571 }
11572 return stickyEl;
11573 },
11574
11575 /**
11576 * Resets the layout. If you changed the size of app-header via CSS
11577 * you can notify the changes by either firing the `iron-resize` event
11578 * or calling `resetLayout` directly.
11579 *
11580 * @method resetLayout
11581 */
11582 resetLayout: function() {
11583 this.fire('app-header-reset-layout');
11584
11585 this.debounce('_resetLayout', function() {
11586 // noop if the header isn't visible
11587 if (this.offsetWidth === 0 && this.offsetHeight === 0) {
11588 return;
11589 }
11590
11591 var scrollTop = this._clampedScrollTop;
11592 var firstSetup = this._height === 0 || scrollTop === 0;
11593 var currentDisabled = this.disabled;
11594
11595 this._height = this.offsetHeight;
11596 this._stickyEl = this._getStickyEl();
11597 this.disabled = true;
11598
11599 // prepare for measurement
11600 if (!firstSetup) {
11601 this._updateScrollState(0, true);
11602 }
11603
11604 if (this._mayMove()) {
11605 this._dHeight = this._stickyEl ? this._height - this._stickyEl.offse tHeight : 0;
11606 } else {
11607 this._dHeight = 0;
11608 }
11609
11610 this._stickyElTop = this._stickyEl ? this._stickyEl.offsetTop : 0;
11611 this._setUpEffect();
11612
11613 if (firstSetup) {
11614 this._updateScrollState(scrollTop, true);
11615 } else {
11616 this._updateScrollState(this._lastScrollTop, true);
11617 this._layoutIfDirty();
11618 }
11619 // restore no transition
11620 this.disabled = currentDisabled;
11621 });
11622 },
11623
11624 /**
11625 * Updates the scroll state.
11626 *
11627 * @param {number} scrollTop
11628 * @param {boolean=} forceUpdate (default: false)
11629 */
11630 _updateScrollState: function(scrollTop, forceUpdate) {
11631 if (this._height === 0) {
11632 return;
11633 }
11634
11635 var progress = 0;
11636 var top = 0;
11637 var lastTop = this._top;
11638 var lastScrollTop = this._lastScrollTop;
11639 var maxHeaderTop = this._maxHeaderTop;
11640 var dScrollTop = scrollTop - this._lastScrollTop;
11641 var absDScrollTop = Math.abs(dScrollTop);
11642 var isScrollingDown = scrollTop > this._lastScrollTop;
11643 var now = Date.now();
11644
11645 if (this._mayMove()) {
11646 top = this._clamp(this.reveals ? lastTop + dScrollTop : scrollTop, 0, maxHeaderTop);
11647 }
11648
11649 if (scrollTop >= this._dHeight) {
11650 top = this.condenses && !this.fixed ? Math.max(this._dHeight, top) : t op;
11651 this.style.transitionDuration = '0ms';
11652 }
11653
11654 if (this.reveals && !this.disabled && absDScrollTop < 100) {
11655 // set the initial scroll position
11656 if (now - this._initTimestamp > 300 || this._wasScrollingDown !== isSc rollingDown) {
11657 this._initScrollTop = scrollTop;
11658 this._initTimestamp = now;
11659 }
11660
11661 if (scrollTop >= maxHeaderTop) {
11662 // check if the header is allowed to snap
11663 if (Math.abs(this._initScrollTop - scrollTop) > 30 || absDScrollTop > 10) {
11664 if (isScrollingDown && scrollTop >= maxHeaderTop) {
11665 top = maxHeaderTop;
11666 } else if (!isScrollingDown && scrollTop >= this._dHeight) {
11667 top = this.condenses && !this.fixed ? this._dHeight : 0;
11668 }
11669 var scrollVelocity = dScrollTop / (now - this._lastTimestamp);
11670 this.style.transitionDuration = this._clamp((top - lastTop) / scro llVelocity, 0, 300) + 'ms';
11671 } else {
11672 top = this._top;
11673 }
11674 }
11675 }
11676
11677 if (this._dHeight === 0) {
11678 progress = scrollTop > 0 ? 1 : 0;
11679 } else {
11680 progress = top / this._dHeight;
11681 }
11682
11683 if (!forceUpdate) {
11684 this._lastScrollTop = scrollTop;
11685 this._top = top;
11686 this._wasScrollingDown = isScrollingDown;
11687 this._lastTimestamp = now;
11688 }
11689
11690 if (forceUpdate || progress !== this._progress || lastTop !== top || scr ollTop === 0) {
11691 this._progress = progress;
11692 this._runEffects(progress, top);
11693 this._transformHeader(top);
11694 }
11695 },
11696
11697 /**
11698 * Returns true if the current header is allowed to move as the user scrol ls.
11699 *
11700 * @return {boolean}
11701 */
11702 _mayMove: function() {
11703 return this.condenses || !this.fixed;
11704 },
11705
11706 /**
11707 * Returns true if the current header will condense based on the size of t he header
11708 * and the `consenses` property.
11709 *
11710 * @return {boolean}
11711 */
11712 willCondense: function() {
11713 return this._dHeight > 0 && this.condenses;
11714 },
11715
11716 /**
11717 * Returns true if the current element is on the screen.
11718 * That is, visible in the current viewport.
11719 *
11720 * @method isOnScreen
11721 * @return {boolean}
11722 */
11723 isOnScreen: function() {
11724 return this._height !== 0 && this._top < this._height;
11725 },
11726
11727 /**
11728 * Returns true if there's content below the current element.
11729 *
11730 * @method isContentBelow
11731 * @return {boolean}
11732 */
11733 isContentBelow: function() {
11734 if (this._top === 0) {
11735 return this._clampedScrollTop > 0;
11736 }
11737 return this._clampedScrollTop - this._maxHeaderTop >= 0;
11738 },
11739
11740 /**
11741 * Transforms the header.
11742 *
11743 * @param {number} y
11744 */
11745 _transformHeader: function(y) {
11746 this.translate3d(0, (-y) + 'px', 0);
11747 if (this._stickyEl && this.condenses && y >= this._stickyElTop) {
11748 this.translate3d(0, (Math.min(y, this._dHeight) - this._stickyElTop) + 'px', 0,
11749 this._stickyEl);
11750 }
11751 },
11752
11753 _resizeHandler: function() {
11754 this.resetLayout();
11755 },
11756
11757 _clamp: function(v, min, max) {
11758 return Math.min(max, Math.max(min, v));
11759 },
11760
11761 _ensureBgContainers: function() {
11762 if (!this._bgContainer) {
11763 this._bgContainer = document.createElement('div');
11764 this._bgContainer.id = 'background';
11765
11766 this._bgRear = document.createElement('div');
11767 this._bgRear.id = 'backgroundRearLayer';
11768 this._bgContainer.appendChild(this._bgRear);
11769
11770 this._bgFront = document.createElement('div');
11771 this._bgFront.id = 'backgroundFrontLayer';
11772 this._bgContainer.appendChild(this._bgFront);
11773
11774 Polymer.dom(this.root).insertBefore(this._bgContainer, this.$.contentC ontainer);
11775 }
11776 },
11777
11778 _getDOMRef: function(id) {
11779 switch (id) {
11780 case 'backgroundFrontLayer':
11781 this._ensureBgContainers();
11782 return this._bgFront;
11783 case 'backgroundRearLayer':
11784 this._ensureBgContainers();
11785 return this._bgRear;
11786 case 'background':
11787 this._ensureBgContainers();
11788 return this._bgContainer;
11789 case 'mainTitle':
11790 return Polymer.dom(this).querySelector('[main-title]');
11791 case 'condensedTitle':
11792 return Polymer.dom(this).querySelector('[condensed-title]');
11793 }
11794 return null;
11795 },
11796
11797 /**
11798 * Returns an object containing the progress value of the scroll effects
11799 * and the top position of the header.
11800 *
11801 * @method getScrollState
11802 * @return {Object}
11803 */
11804 getScrollState: function() {
11805 return { progress: this._progress, top: this._top };
11806 }
11807
11808 /**
11809 * Fires when the layout of `app-header` changed.
11810 *
11811 * @event app-header-reset-layout
11812 */
11813 });
11814 </script>
11815 </dom-module>
11816
11817
11818 <dom-module id="app-header-layout" assetpath="bower_components/app-layout/app-he ader-layout/">
11819 <template>
11820 <style>
11821 :host {
11822 display: block;
11823 /**
11824 * Force app-header-layout to have its own stacking context so that its parent can
11825 * control the stacking of it relative to other elements (e.g. app-drawe r-layout).
11826 * This could be done using `isolation: isolate`, but that's not well su pported
11827 * across browsers.
11828 */
11829 position: relative;
11830 z-index: 0;
11831 }
11832
11833 :host > ::content > app-header {
11834 @apply(--layout-fixed-top);
11835 z-index: 1;
11836 }
11837
11838 :host([has-scrolling-region]) {
11839 height: 100%;
11840 }
11841
11842 :host([has-scrolling-region]) > ::content > app-header {
11843 position: absolute;
11844 }
11845
11846 :host([has-scrolling-region]) > #contentContainer {
11847 @apply(--layout-fit);
11848 overflow-y: auto;
11849 -webkit-overflow-scrolling: touch;
11850 }
11851
11852 :host([fullbleed]) {
11853 @apply(--layout-vertical);
11854 @apply(--layout-fit);
11855 }
11856
11857 :host([fullbleed]) > #contentContainer {
11858 @apply(--layout-vertical);
11859 @apply(--layout-flex);
11860 }
11861
11862 #contentContainer {
11863 /* Create a stacking context here so that all children appear below the header. */
11864 position: relative;
11865 z-index: 0;
11866 }
11867
11868 </style>
11869
11870 <content id="header" select="app-header"></content>
11871
11872 <div id="contentContainer">
11873 <content></content>
11874 </div>
11875
11876 </template>
11877
11878 <script>
11879 Polymer({
11880 is: 'app-header-layout',
11881
11882 behaviors: [
11883 Polymer.IronResizableBehavior
11884 ],
11885
11886 properties: {
11887 /**
11888 * If true, the current element will have its own scrolling region.
11889 * Otherwise, it will use the document scroll to control the header.
11890 */
11891 hasScrollingRegion: {
11892 type: Boolean,
11893 value: false,
11894 reflectToAttribute: true
11895 }
11896 },
11897
11898 listeners: {
11899 'iron-resize': '_resizeHandler',
11900 'app-header-reset-layout': 'resetLayout'
11901 },
11902
11903 observers: [
11904 'resetLayout(isAttached, hasScrollingRegion)'
11905 ],
11906
11907 /**
11908 * A reference to the app-header element.
11909 *
11910 * @property header
11911 */
11912 get header() {
11913 return Polymer.dom(this.$.header).getDistributedNodes()[0];
11914 },
11915
11916 /**
11917 * Resets the layout. This method is automatically called when the element is attached
11918 * to the DOM.
11919 *
11920 * @method resetLayout
11921 */
11922 resetLayout: function() {
11923 this._updateScroller();
11924 this.debounce('_resetLayout', this._updateContentPosition);
11925 },
11926
11927 _updateContentPosition: function() {
11928 var header = this.header;
11929 if (!this.isAttached || !header) {
11930 return;
11931 }
11932 // Get header height here so that style reads are batched together befor e style writes
11933 // (i.e. getBoundingClientRect() below).
11934 var headerHeight = header.offsetHeight;
11935 // Update the header position.
11936 if (!this.hasScrollingRegion) {
11937 var rect = this.getBoundingClientRect();
11938 var rightOffset = document.documentElement.clientWidth - rect.right;
11939 header.style.left = rect.left + 'px';
11940 header.style.right = rightOffset + 'px';
11941 } else {
11942 header.style.left = '';
11943 header.style.right = '';
11944 }
11945 // Update the content container position.
11946 var containerStyle = this.$.contentContainer.style;
11947 if (header.fixed && !header.willCondense() && this.hasScrollingRegion) {
11948 // If the header size does not change and we're using a scrolling regi on, exclude
11949 // the header area from the scrolling region so that the header doesn' t overlap
11950 // the scrollbar.
11951 containerStyle.marginTop = headerHeight + 'px';
11952 containerStyle.paddingTop = '';
11953 } else {
11954 containerStyle.paddingTop = headerHeight + 'px';
11955 containerStyle.marginTop = '';
11956 }
11957 },
11958
11959 _updateScroller: function() {
11960 if (!this.isAttached) {
11961 return;
11962 }
11963 var header = this.header;
11964 if (header) {
11965 header.scrollTarget = this.hasScrollingRegion ?
11966 this.$.contentContainer : this.ownerDocument.documentElement;
11967 }
11968 },
11969
11970 _resizeHandler: function() {
11971 this.resetLayout();
11972 }
11973 });
11974 </script>
11975 </dom-module>
11976
11977
11978 <dom-module id="app-scrollpos-control" assetpath="bower_components/app-layout/ap p-scrollpos-control/">
11979 <script>
11980 Polymer({
11981 is: 'app-scrollpos-control',
11982
11983 behaviors: [
11984 Polymer.IronScrollTargetBehavior
11985 ],
11986
11987 properties: {
11988 /**
11989 * The selected page.
11990 */
11991 selected: {
11992 type: String,
11993 observer: '_selectedChanged'
11994 },
11995
11996 /**
11997 * Reset the scroll position to 0.
11998 */
11999 reset: {
12000 type: Boolean,
12001 value: false
12002 }
12003 },
12004
12005 observers: [
12006 '_updateScrollPos(selected, reset)'
12007 ],
12008
12009 created: function() {
12010 this._scrollposMap = {};
12011 },
12012
12013 _selectedChanged: function(selected, old) {
12014 if (old != null) {
12015 this._scrollposMap[old] = {x: this._scrollLeft, y: this._scrollTop};
12016 }
12017 },
12018
12019 _updateScrollPos: function(selected, reset) {
12020 this.debounce('_updateScrollPos', function() {
12021 var pos = this._scrollposMap[this.selected];
12022 if (pos != null && !this.reset) {
12023 this.scroll(pos.x, pos.y);
12024 } else {
12025 this.scroll(0, 0);
12026 }
12027 });
12028 }
12029 });
12030 </script>
12031 </dom-module>
12032
12033
12034 <dom-module id="app-toolbar" assetpath="bower_components/app-layout/app-toolbar/ ">
12035 <template>
12036 <style>
12037 :host {
12038 position: relative;
12039
12040 @apply(--layout-horizontal);
12041 @apply(--layout-center);
12042
12043 height: 64px;
12044 padding: 0 16px;
12045
12046 pointer-events: none;
12047
12048 font-size: var(--app-toolbar-font-size, 20px);
12049 }
12050
12051 :host > ::content > * {
12052 pointer-events: auto;
12053 }
12054
12055 :host > ::content > paper-icon-button {
12056 /* paper-icon-button/issues/33 */
12057 font-size: 0;
12058 }
12059
12060 :host > ::content > [main-title],
12061 :host > ::content > [condensed-title] {
12062 pointer-events: none;
12063 @apply(--layout-flex);
12064 }
12065
12066 :host > ::content > [bottom-item] {
12067 position: absolute;
12068 right: 0;
12069 bottom: 0;
12070 left: 0;
12071 }
12072
12073 :host > ::content > [top-item] {
12074 position: absolute;
12075 top: 0;
12076 right: 0;
12077 left: 0;
12078 }
12079
12080 :host > ::content > [spacer] {
12081 margin-left: 64px;
12082 }
12083 </style>
12084
12085 <content></content>
12086 </template>
12087
12088 <script>
12089 Polymer({
12090 is: 'app-toolbar'
12091 });
12092 </script>
12093 </dom-module>
12094
12095
12096 <dom-module id="app-box" assetpath="bower_components/app-layout/app-box/">
12097 <template>
12098 <style>
12099 :host {
12100 position: relative;
12101
12102 display: block;
12103 }
12104
12105 #background {
12106 @apply(--layout-fit);
12107
12108 overflow: hidden;
12109
12110 height: 100%;
12111 }
12112
12113 #backgroundFrontLayer {
12114 min-height: 100%;
12115
12116 pointer-events: none;
12117
12118 background-size: cover;
12119
12120 @apply(--app-box-background-front-layer);
12121 }
12122
12123 #contentContainer {
12124 position: relative;
12125
12126 width: 100%;
12127 height: 100%;
12128 }
12129
12130 :host([disabled]),
12131 :host([disabled]) #backgroundFrontLayer {
12132 transition: none !important;
12133 }
12134 </style>
12135
12136 <div id="background">
12137 <div id="backgroundFrontLayer">
12138 <content select="[background]"></content>
12139 </div>
12140 </div>
12141 <div id="contentContainer">
12142 <content id="content"></content>
12143 </div>
12144 </template>
12145
12146 <script>
12147 Polymer({
12148 is: 'app-box',
12149
12150 behaviors: [
12151 Polymer.AppScrollEffectsBehavior,
12152 Polymer.IronResizableBehavior
12153 ],
12154
12155 listeners: {
12156 'iron-resize': '_resizeHandler'
12157 },
12158
12159 /**
12160 * The current scroll progress.
12161 *
12162 * @type {number}
12163 */
12164 _progress: 0,
12165
12166 attached: function() {
12167 this.resetLayout();
12168 },
12169
12170 /**
12171 * Resets the layout. This method is automatically called when the element is attached to the DOM.
12172 *
12173 * @method resetLayout
12174 */
12175 resetLayout: function() {
12176 this.debounce('_resetLayout', function() {
12177 // noop if the box isn't in the rendered tree
12178 if (this.offsetWidth === 0 && this.offsetHeight === 0) {
12179 return;
12180 }
12181
12182 var scrollTop = this._clampedScrollTop;
12183 var savedDisabled = this.disabled;
12184
12185 this.disabled = true;
12186 this._elementTop = this._getElementTop();
12187 this._elementHeight = this.offsetHeight;
12188 this._cachedScrollTargetHeight = this._scrollTargetHeight;
12189 this._setUpEffect();
12190 this._updateScrollState(scrollTop);
12191 this.disabled = savedDisabled;
12192 }, 1);
12193 },
12194
12195 _getElementTop: function() {
12196 var currentNode = this;
12197 var top = 0;
12198
12199 while (currentNode && currentNode !== this.scrollTarget) {
12200 top += currentNode.offsetTop;
12201 currentNode = currentNode.offsetParent;
12202 }
12203 return top;
12204 },
12205
12206 _updateScrollState: function(scrollTop) {
12207 if (this.isOnScreen()) {
12208 var viewportTop = this._elementTop - scrollTop;
12209 this._progress = 1 - (viewportTop + this._elementHeight) / this._cache dScrollTargetHeight;
12210 this._runEffects(this._progress, scrollTop);
12211 }
12212 },
12213
12214 /**
12215 * Returns true if this app-box is on the screen.
12216 * That is, visible in the current viewport.
12217 *
12218 * @method isOnScreen
12219 * @return {boolean}
12220 */
12221 isOnScreen: function() {
12222 return this._elementTop < this._scrollTop + this._cachedScrollTargetHeig ht
12223 && this._elementTop + this._elementHeight > this._scrollTop;
12224 },
12225
12226 _resizeHandler: function() {
12227 this.resetLayout();
12228 },
12229
12230 _getDOMRef: function(id) {
12231 if (id === 'background') {
12232 return this.$.background;
12233 }
12234 if (id === 'backgroundFrontLayer') {
12235 return this.$.backgroundFrontLayer;
12236 }
12237 },
12238
12239 /**
12240 * Returns an object containing the progress value of the scroll effects.
12241 *
12242 * @method getScrollState
12243 * @return {Object}
12244 */
12245 getScrollState: function() {
12246 return { progress: this._progress };
12247 }
12248 });
12249 </script>
12250 </dom-module>
12251 <style is="custom-style">
12252
12253 :root {
12254
12255 /* Material Design color palette for Google products */
12256
12257 --google-red-100: #f4c7c3;
12258 --google-red-300: #e67c73;
12259 --google-red-500: #db4437;
12260 --google-red-700: #c53929;
12261
12262 --google-blue-100: #c6dafc;
12263 --google-blue-300: #7baaf7;
12264 --google-blue-500: #4285f4;
12265 --google-blue-700: #3367d6;
12266
12267 --google-green-100: #b7e1cd;
12268 --google-green-300: #57bb8a;
12269 --google-green-500: #0f9d58;
12270 --google-green-700: #0b8043;
12271
12272 --google-yellow-100: #fce8b2;
12273 --google-yellow-300: #f7cb4d;
12274 --google-yellow-500: #f4b400;
12275 --google-yellow-700: #f09300;
12276
12277 --google-grey-100: #f5f5f5;
12278 --google-grey-300: #e0e0e0;
12279 --google-grey-500: #9e9e9e;
12280 --google-grey-700: #616161;
12281
12282 /* Material Design color palette from online spec document */
12283
12284 --paper-red-50: #ffebee;
12285 --paper-red-100: #ffcdd2;
12286 --paper-red-200: #ef9a9a;
12287 --paper-red-300: #e57373;
12288 --paper-red-400: #ef5350;
12289 --paper-red-500: #f44336;
12290 --paper-red-600: #e53935;
12291 --paper-red-700: #d32f2f;
12292 --paper-red-800: #c62828;
12293 --paper-red-900: #b71c1c;
12294 --paper-red-a100: #ff8a80;
12295 --paper-red-a200: #ff5252;
12296 --paper-red-a400: #ff1744;
12297 --paper-red-a700: #d50000;
12298
12299 --paper-pink-50: #fce4ec;
12300 --paper-pink-100: #f8bbd0;
12301 --paper-pink-200: #f48fb1;
12302 --paper-pink-300: #f06292;
12303 --paper-pink-400: #ec407a;
12304 --paper-pink-500: #e91e63;
12305 --paper-pink-600: #d81b60;
12306 --paper-pink-700: #c2185b;
12307 --paper-pink-800: #ad1457;
12308 --paper-pink-900: #880e4f;
12309 --paper-pink-a100: #ff80ab;
12310 --paper-pink-a200: #ff4081;
12311 --paper-pink-a400: #f50057;
12312 --paper-pink-a700: #c51162;
12313
12314 --paper-purple-50: #f3e5f5;
12315 --paper-purple-100: #e1bee7;
12316 --paper-purple-200: #ce93d8;
12317 --paper-purple-300: #ba68c8;
12318 --paper-purple-400: #ab47bc;
12319 --paper-purple-500: #9c27b0;
12320 --paper-purple-600: #8e24aa;
12321 --paper-purple-700: #7b1fa2;
12322 --paper-purple-800: #6a1b9a;
12323 --paper-purple-900: #4a148c;
12324 --paper-purple-a100: #ea80fc;
12325 --paper-purple-a200: #e040fb;
12326 --paper-purple-a400: #d500f9;
12327 --paper-purple-a700: #aa00ff;
12328
12329 --paper-deep-purple-50: #ede7f6;
12330 --paper-deep-purple-100: #d1c4e9;
12331 --paper-deep-purple-200: #b39ddb;
12332 --paper-deep-purple-300: #9575cd;
12333 --paper-deep-purple-400: #7e57c2;
12334 --paper-deep-purple-500: #673ab7;
12335 --paper-deep-purple-600: #5e35b1;
12336 --paper-deep-purple-700: #512da8;
12337 --paper-deep-purple-800: #4527a0;
12338 --paper-deep-purple-900: #311b92;
12339 --paper-deep-purple-a100: #b388ff;
12340 --paper-deep-purple-a200: #7c4dff;
12341 --paper-deep-purple-a400: #651fff;
12342 --paper-deep-purple-a700: #6200ea;
12343
12344 --paper-indigo-50: #e8eaf6;
12345 --paper-indigo-100: #c5cae9;
12346 --paper-indigo-200: #9fa8da;
12347 --paper-indigo-300: #7986cb;
12348 --paper-indigo-400: #5c6bc0;
12349 --paper-indigo-500: #3f51b5;
12350 --paper-indigo-600: #3949ab;
12351 --paper-indigo-700: #303f9f;
12352 --paper-indigo-800: #283593;
12353 --paper-indigo-900: #1a237e;
12354 --paper-indigo-a100: #8c9eff;
12355 --paper-indigo-a200: #536dfe;
12356 --paper-indigo-a400: #3d5afe;
12357 --paper-indigo-a700: #304ffe;
12358
12359 --paper-blue-50: #e3f2fd;
12360 --paper-blue-100: #bbdefb;
12361 --paper-blue-200: #90caf9;
12362 --paper-blue-300: #64b5f6;
12363 --paper-blue-400: #42a5f5;
12364 --paper-blue-500: #2196f3;
12365 --paper-blue-600: #1e88e5;
12366 --paper-blue-700: #1976d2;
12367 --paper-blue-800: #1565c0;
12368 --paper-blue-900: #0d47a1;
12369 --paper-blue-a100: #82b1ff;
12370 --paper-blue-a200: #448aff;
12371 --paper-blue-a400: #2979ff;
12372 --paper-blue-a700: #2962ff;
12373
12374 --paper-light-blue-50: #e1f5fe;
12375 --paper-light-blue-100: #b3e5fc;
12376 --paper-light-blue-200: #81d4fa;
12377 --paper-light-blue-300: #4fc3f7;
12378 --paper-light-blue-400: #29b6f6;
12379 --paper-light-blue-500: #03a9f4;
12380 --paper-light-blue-600: #039be5;
12381 --paper-light-blue-700: #0288d1;
12382 --paper-light-blue-800: #0277bd;
12383 --paper-light-blue-900: #01579b;
12384 --paper-light-blue-a100: #80d8ff;
12385 --paper-light-blue-a200: #40c4ff;
12386 --paper-light-blue-a400: #00b0ff;
12387 --paper-light-blue-a700: #0091ea;
12388
12389 --paper-cyan-50: #e0f7fa;
12390 --paper-cyan-100: #b2ebf2;
12391 --paper-cyan-200: #80deea;
12392 --paper-cyan-300: #4dd0e1;
12393 --paper-cyan-400: #26c6da;
12394 --paper-cyan-500: #00bcd4;
12395 --paper-cyan-600: #00acc1;
12396 --paper-cyan-700: #0097a7;
12397 --paper-cyan-800: #00838f;
12398 --paper-cyan-900: #006064;
12399 --paper-cyan-a100: #84ffff;
12400 --paper-cyan-a200: #18ffff;
12401 --paper-cyan-a400: #00e5ff;
12402 --paper-cyan-a700: #00b8d4;
12403
12404 --paper-teal-50: #e0f2f1;
12405 --paper-teal-100: #b2dfdb;
12406 --paper-teal-200: #80cbc4;
12407 --paper-teal-300: #4db6ac;
12408 --paper-teal-400: #26a69a;
12409 --paper-teal-500: #009688;
12410 --paper-teal-600: #00897b;
12411 --paper-teal-700: #00796b;
12412 --paper-teal-800: #00695c;
12413 --paper-teal-900: #004d40;
12414 --paper-teal-a100: #a7ffeb;
12415 --paper-teal-a200: #64ffda;
12416 --paper-teal-a400: #1de9b6;
12417 --paper-teal-a700: #00bfa5;
12418
12419 --paper-green-50: #e8f5e9;
12420 --paper-green-100: #c8e6c9;
12421 --paper-green-200: #a5d6a7;
12422 --paper-green-300: #81c784;
12423 --paper-green-400: #66bb6a;
12424 --paper-green-500: #4caf50;
12425 --paper-green-600: #43a047;
12426 --paper-green-700: #388e3c;
12427 --paper-green-800: #2e7d32;
12428 --paper-green-900: #1b5e20;
12429 --paper-green-a100: #b9f6ca;
12430 --paper-green-a200: #69f0ae;
12431 --paper-green-a400: #00e676;
12432 --paper-green-a700: #00c853;
12433
12434 --paper-light-green-50: #f1f8e9;
12435 --paper-light-green-100: #dcedc8;
12436 --paper-light-green-200: #c5e1a5;
12437 --paper-light-green-300: #aed581;
12438 --paper-light-green-400: #9ccc65;
12439 --paper-light-green-500: #8bc34a;
12440 --paper-light-green-600: #7cb342;
12441 --paper-light-green-700: #689f38;
12442 --paper-light-green-800: #558b2f;
12443 --paper-light-green-900: #33691e;
12444 --paper-light-green-a100: #ccff90;
12445 --paper-light-green-a200: #b2ff59;
12446 --paper-light-green-a400: #76ff03;
12447 --paper-light-green-a700: #64dd17;
12448
12449 --paper-lime-50: #f9fbe7;
12450 --paper-lime-100: #f0f4c3;
12451 --paper-lime-200: #e6ee9c;
12452 --paper-lime-300: #dce775;
12453 --paper-lime-400: #d4e157;
12454 --paper-lime-500: #cddc39;
12455 --paper-lime-600: #c0ca33;
12456 --paper-lime-700: #afb42b;
12457 --paper-lime-800: #9e9d24;
12458 --paper-lime-900: #827717;
12459 --paper-lime-a100: #f4ff81;
12460 --paper-lime-a200: #eeff41;
12461 --paper-lime-a400: #c6ff00;
12462 --paper-lime-a700: #aeea00;
12463
12464 --paper-yellow-50: #fffde7;
12465 --paper-yellow-100: #fff9c4;
12466 --paper-yellow-200: #fff59d;
12467 --paper-yellow-300: #fff176;
12468 --paper-yellow-400: #ffee58;
12469 --paper-yellow-500: #ffeb3b;
12470 --paper-yellow-600: #fdd835;
12471 --paper-yellow-700: #fbc02d;
12472 --paper-yellow-800: #f9a825;
12473 --paper-yellow-900: #f57f17;
12474 --paper-yellow-a100: #ffff8d;
12475 --paper-yellow-a200: #ffff00;
12476 --paper-yellow-a400: #ffea00;
12477 --paper-yellow-a700: #ffd600;
12478
12479 --paper-amber-50: #fff8e1;
12480 --paper-amber-100: #ffecb3;
12481 --paper-amber-200: #ffe082;
12482 --paper-amber-300: #ffd54f;
12483 --paper-amber-400: #ffca28;
12484 --paper-amber-500: #ffc107;
12485 --paper-amber-600: #ffb300;
12486 --paper-amber-700: #ffa000;
12487 --paper-amber-800: #ff8f00;
12488 --paper-amber-900: #ff6f00;
12489 --paper-amber-a100: #ffe57f;
12490 --paper-amber-a200: #ffd740;
12491 --paper-amber-a400: #ffc400;
12492 --paper-amber-a700: #ffab00;
12493
12494 --paper-orange-50: #fff3e0;
12495 --paper-orange-100: #ffe0b2;
12496 --paper-orange-200: #ffcc80;
12497 --paper-orange-300: #ffb74d;
12498 --paper-orange-400: #ffa726;
12499 --paper-orange-500: #ff9800;
12500 --paper-orange-600: #fb8c00;
12501 --paper-orange-700: #f57c00;
12502 --paper-orange-800: #ef6c00;
12503 --paper-orange-900: #e65100;
12504 --paper-orange-a100: #ffd180;
12505 --paper-orange-a200: #ffab40;
12506 --paper-orange-a400: #ff9100;
12507 --paper-orange-a700: #ff6500;
12508
12509 --paper-deep-orange-50: #fbe9e7;
12510 --paper-deep-orange-100: #ffccbc;
12511 --paper-deep-orange-200: #ffab91;
12512 --paper-deep-orange-300: #ff8a65;
12513 --paper-deep-orange-400: #ff7043;
12514 --paper-deep-orange-500: #ff5722;
12515 --paper-deep-orange-600: #f4511e;
12516 --paper-deep-orange-700: #e64a19;
12517 --paper-deep-orange-800: #d84315;
12518 --paper-deep-orange-900: #bf360c;
12519 --paper-deep-orange-a100: #ff9e80;
12520 --paper-deep-orange-a200: #ff6e40;
12521 --paper-deep-orange-a400: #ff3d00;
12522 --paper-deep-orange-a700: #dd2c00;
12523
12524 --paper-brown-50: #efebe9;
12525 --paper-brown-100: #d7ccc8;
12526 --paper-brown-200: #bcaaa4;
12527 --paper-brown-300: #a1887f;
12528 --paper-brown-400: #8d6e63;
12529 --paper-brown-500: #795548;
12530 --paper-brown-600: #6d4c41;
12531 --paper-brown-700: #5d4037;
12532 --paper-brown-800: #4e342e;
12533 --paper-brown-900: #3e2723;
12534
12535 --paper-grey-50: #fafafa;
12536 --paper-grey-100: #f5f5f5;
12537 --paper-grey-200: #eeeeee;
12538 --paper-grey-300: #e0e0e0;
12539 --paper-grey-400: #bdbdbd;
12540 --paper-grey-500: #9e9e9e;
12541 --paper-grey-600: #757575;
12542 --paper-grey-700: #616161;
12543 --paper-grey-800: #424242;
12544 --paper-grey-900: #212121;
12545
12546 --paper-blue-grey-50: #eceff1;
12547 --paper-blue-grey-100: #cfd8dc;
12548 --paper-blue-grey-200: #b0bec5;
12549 --paper-blue-grey-300: #90a4ae;
12550 --paper-blue-grey-400: #78909c;
12551 --paper-blue-grey-500: #607d8b;
12552 --paper-blue-grey-600: #546e7a;
12553 --paper-blue-grey-700: #455a64;
12554 --paper-blue-grey-800: #37474f;
12555 --paper-blue-grey-900: #263238;
12556
12557 /* opacity for dark text on a light background */
12558 --dark-divider-opacity: 0.12;
12559 --dark-disabled-opacity: 0.38; /* or hint text or icon */
12560 --dark-secondary-opacity: 0.54;
12561 --dark-primary-opacity: 0.87;
12562
12563 /* opacity for light text on a dark background */
12564 --light-divider-opacity: 0.12;
12565 --light-disabled-opacity: 0.3; /* or hint text or icon */
12566 --light-secondary-opacity: 0.7;
12567 --light-primary-opacity: 1.0;
12568
12569 }
12570
12571 </style>
12572 <script>
12573
12574 /** @polymerBehavior */
12575 Polymer.PaperSpinnerBehavior = {
12576
12577 listeners: {
12578 'animationend': '__reset',
12579 'webkitAnimationEnd': '__reset'
12580 },
12581
12582 properties: {
12583 /**
12584 * Displays the spinner.
12585 */
12586 active: {
12587 type: Boolean,
12588 value: false,
12589 reflectToAttribute: true,
12590 observer: '__activeChanged'
12591 },
12592
12593 /**
12594 * Alternative text content for accessibility support.
12595 * If alt is present, it will add an aria-label whose content matches alt when active.
12596 * If alt is not present, it will default to 'loading' as the alt value.
12597 */
12598 alt: {
12599 type: String,
12600 value: 'loading',
12601 observer: '__altChanged'
12602 },
12603
12604 __coolingDown: {
12605 type: Boolean,
12606 value: false
12607 }
12608 },
12609
12610 __computeContainerClasses: function(active, coolingDown) {
12611 return [
12612 active || coolingDown ? 'active' : '',
12613 coolingDown ? 'cooldown' : ''
12614 ].join(' ');
12615 },
12616
12617 __activeChanged: function(active, old) {
12618 this.__setAriaHidden(!active);
12619 this.__coolingDown = !active && old;
12620 },
12621
12622 __altChanged: function(alt) {
12623 // user-provided `aria-label` takes precedence over prototype default
12624 if (alt === this.getPropertyInfo('alt').value) {
12625 this.alt = this.getAttribute('aria-label') || alt;
12626 } else {
12627 this.__setAriaHidden(alt==='');
12628 this.setAttribute('aria-label', alt);
12629 }
12630 },
12631
12632 __setAriaHidden: function(hidden) {
12633 var attr = 'aria-hidden';
12634 if (hidden) {
12635 this.setAttribute(attr, 'true');
12636 } else {
12637 this.removeAttribute(attr);
12638 }
12639 },
12640
12641 __reset: function() {
12642 this.active = false;
12643 this.__coolingDown = false;
12644 }
12645 };
12646 </script>
12647 <dom-module id="paper-spinner-styles" assetpath="bower_components/paper-spinner/ ">
12648 <template>
12649 <style>
12650 /*
12651 /**************************/
12652 /* STYLES FOR THE SPINNER */
12653 /**************************/
12654
12655 /*
12656 * Constants:
12657 * ARCSIZE = 270 degrees (amount of circle the arc takes up)
12658 * ARCTIME = 1333ms (time it takes to expand and contract arc)
12659 * ARCSTARTROT = 216 degrees (how much the start location of the arc
12660 * should rotate each time, 216 gives us a
12661 * 5 pointed star shape (it's 360/5 * 3).
12662 * For a 7 pointed star, we might do
12663 * 360/7 * 3 = 154.286)
12664 * SHRINK_TIME = 400ms
12665 */
12666
12667 :host {
12668 display: inline-block;
12669 position: relative;
12670 width: 28px;
12671 height: 28px;
12672
12673 /* 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
12674 --paper-spinner-container-rotation-duration: 1568ms;
12675
12676 /* ARCTIME */
12677 --paper-spinner-expand-contract-duration: 1333ms;
12678
12679 /* 4 * ARCTIME */
12680 --paper-spinner-full-cycle-duration: 5332ms;
12681
12682 /* SHRINK_TIME */
12683 --paper-spinner-cooldown-duration: 400ms;
12684 }
12685
12686 #spinnerContainer {
12687 width: 100%;
12688 height: 100%;
12689
12690 /* The spinner does not have any contents that would have to be
12691 * flipped if the direction changes. Always use ltr so that the
12692 * style works out correctly in both cases. */
12693 direction: ltr;
12694 }
12695
12696 #spinnerContainer.active {
12697 -webkit-animation: container-rotate var(--paper-spinner-container-rotati on-duration) linear infinite;
12698 animation: container-rotate var(--paper-spinner-container-rotation-durat ion) linear infinite;
12699 }
12700
12701 @-webkit-keyframes container-rotate {
12702 to { -webkit-transform: rotate(360deg) }
12703 }
12704
12705 @keyframes container-rotate {
12706 to { transform: rotate(360deg) }
12707 }
12708
12709 .spinner-layer {
12710 position: absolute;
12711 width: 100%;
12712 height: 100%;
12713 opacity: 0;
12714 white-space: nowrap;
12715 border-color: var(--paper-spinner-color, --google-blue-500);
12716 }
12717
12718 .layer-1 {
12719 border-color: var(--paper-spinner-layer-1-color, --google-blue-500);
12720 }
12721
12722 .layer-2 {
12723 border-color: var(--paper-spinner-layer-2-color, --google-red-500);
12724 }
12725
12726 .layer-3 {
12727 border-color: var(--paper-spinner-layer-3-color, --google-yellow-500);
12728 }
12729
12730 .layer-4 {
12731 border-color: var(--paper-spinner-layer-4-color, --google-green-500);
12732 }
12733
12734 /**
12735 * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
12736 *
12737 * iOS Safari (tested on iOS 8.1) does not handle animation-delay very wel l - it doesn't
12738 * guarantee that the animation will start _exactly_ after that value. So we avoid using
12739 * animation-delay and instead set custom keyframes for each color (as lay er-2undant as it
12740 * seems).
12741 */
12742 .active .spinner-layer {
12743 -webkit-animation-name: fill-unfill-rotate;
12744 -webkit-animation-duration: var(--paper-spinner-full-cycle-duration);
12745 -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
12746 -webkit-animation-iteration-count: infinite;
12747 animation-name: fill-unfill-rotate;
12748 animation-duration: var(--paper-spinner-full-cycle-duration);
12749 animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
12750 animation-iteration-count: infinite;
12751 opacity: 1;
12752 }
12753
12754 .active .spinner-layer.layer-1 {
12755 -webkit-animation-name: fill-unfill-rotate, layer-1-fade-in-out;
12756 animation-name: fill-unfill-rotate, layer-1-fade-in-out;
12757 }
12758
12759 .active .spinner-layer.layer-2 {
12760 -webkit-animation-name: fill-unfill-rotate, layer-2-fade-in-out;
12761 animation-name: fill-unfill-rotate, layer-2-fade-in-out;
12762 }
12763
12764 .active .spinner-layer.layer-3 {
12765 -webkit-animation-name: fill-unfill-rotate, layer-3-fade-in-out;
12766 animation-name: fill-unfill-rotate, layer-3-fade-in-out;
12767 }
12768
12769 .active .spinner-layer.layer-4 {
12770 -webkit-animation-name: fill-unfill-rotate, layer-4-fade-in-out;
12771 animation-name: fill-unfill-rotate, layer-4-fade-in-out;
12772 }
12773
12774 @-webkit-keyframes fill-unfill-rotate {
12775 12.5% { -webkit-transform: rotate(135deg) } /* 0.5 * ARCSIZE */
12776 25% { -webkit-transform: rotate(270deg) } /* 1 * ARCSIZE */
12777 37.5% { -webkit-transform: rotate(405deg) } /* 1.5 * ARCSIZE */
12778 50% { -webkit-transform: rotate(540deg) } /* 2 * ARCSIZE */
12779 62.5% { -webkit-transform: rotate(675deg) } /* 2.5 * ARCSIZE */
12780 75% { -webkit-transform: rotate(810deg) } /* 3 * ARCSIZE */
12781 87.5% { -webkit-transform: rotate(945deg) } /* 3.5 * ARCSIZE */
12782 to { -webkit-transform: rotate(1080deg) } /* 4 * ARCSIZE */
12783 }
12784
12785 @keyframes fill-unfill-rotate {
12786 12.5% { transform: rotate(135deg) } /* 0.5 * ARCSIZE */
12787 25% { transform: rotate(270deg) } /* 1 * ARCSIZE */
12788 37.5% { transform: rotate(405deg) } /* 1.5 * ARCSIZE */
12789 50% { transform: rotate(540deg) } /* 2 * ARCSIZE */
12790 62.5% { transform: rotate(675deg) } /* 2.5 * ARCSIZE */
12791 75% { transform: rotate(810deg) } /* 3 * ARCSIZE */
12792 87.5% { transform: rotate(945deg) } /* 3.5 * ARCSIZE */
12793 to { transform: rotate(1080deg) } /* 4 * ARCSIZE */
12794 }
12795
12796 @-webkit-keyframes layer-1-fade-in-out {
12797 0% { opacity: 1 }
12798 25% { opacity: 1 }
12799 26% { opacity: 0 }
12800 89% { opacity: 0 }
12801 90% { opacity: 1 }
12802 to { opacity: 1 }
12803 }
12804
12805 @keyframes layer-1-fade-in-out {
12806 0% { opacity: 1 }
12807 25% { opacity: 1 }
12808 26% { opacity: 0 }
12809 89% { opacity: 0 }
12810 90% { opacity: 1 }
12811 to { opacity: 1 }
12812 }
12813
12814 @-webkit-keyframes layer-2-fade-in-out {
12815 0% { opacity: 0 }
12816 15% { opacity: 0 }
12817 25% { opacity: 1 }
12818 50% { opacity: 1 }
12819 51% { opacity: 0 }
12820 to { opacity: 0 }
12821 }
12822
12823 @keyframes layer-2-fade-in-out {
12824 0% { opacity: 0 }
12825 15% { opacity: 0 }
12826 25% { opacity: 1 }
12827 50% { opacity: 1 }
12828 51% { opacity: 0 }
12829 to { opacity: 0 }
12830 }
12831
12832 @-webkit-keyframes layer-3-fade-in-out {
12833 0% { opacity: 0 }
12834 40% { opacity: 0 }
12835 50% { opacity: 1 }
12836 75% { opacity: 1 }
12837 76% { opacity: 0 }
12838 to { opacity: 0 }
12839 }
12840
12841 @keyframes layer-3-fade-in-out {
12842 0% { opacity: 0 }
12843 40% { opacity: 0 }
12844 50% { opacity: 1 }
12845 75% { opacity: 1 }
12846 76% { opacity: 0 }
12847 to { opacity: 0 }
12848 }
12849
12850 @-webkit-keyframes layer-4-fade-in-out {
12851 0% { opacity: 0 }
12852 65% { opacity: 0 }
12853 75% { opacity: 1 }
12854 90% { opacity: 1 }
12855 to { opacity: 0 }
12856 }
12857
12858 @keyframes layer-4-fade-in-out {
12859 0% { opacity: 0 }
12860 65% { opacity: 0 }
12861 75% { opacity: 1 }
12862 90% { opacity: 1 }
12863 to { opacity: 0 }
12864 }
12865
12866 .circle-clipper {
12867 display: inline-block;
12868 position: relative;
12869 width: 50%;
12870 height: 100%;
12871 overflow: hidden;
12872 border-color: inherit;
12873 }
12874
12875 /**
12876 * Patch the gap that appear between the two adjacent div.circle-clipper w hile the
12877 * spinner is rotating (appears on Chrome 50, Safari 9.1.1, and Edge).
12878 */
12879 .spinner-layer::after {
12880 left: 45%;
12881 width: 10%;
12882 border-top-style: solid;
12883 }
12884
12885 .spinner-layer::after,
12886 .circle-clipper::after {
12887 content: '';
12888 box-sizing: border-box;
12889 position: absolute;
12890 top: 0;
12891 border-width: var(--paper-spinner-stroke-width, 3px);
12892 border-color: inherit;
12893 border-radius: 50%;
12894 }
12895
12896 .circle-clipper::after {
12897 bottom: 0;
12898 width: 200%;
12899 border-style: solid;
12900 border-bottom-color: transparent !important;
12901 }
12902
12903 .circle-clipper.left::after {
12904 left: 0;
12905 border-right-color: transparent !important;
12906 -webkit-transform: rotate(129deg);
12907 transform: rotate(129deg);
12908 }
12909
12910 .circle-clipper.right::after {
12911 left: -100%;
12912 border-left-color: transparent !important;
12913 -webkit-transform: rotate(-129deg);
12914 transform: rotate(-129deg);
12915 }
12916
12917 .active .gap-patch::after,
12918 .active .circle-clipper::after {
12919 -webkit-animation-duration: var(--paper-spinner-expand-contract-duration );
12920 -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
12921 -webkit-animation-iteration-count: infinite;
12922 animation-duration: var(--paper-spinner-expand-contract-duration);
12923 animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);
12924 animation-iteration-count: infinite;
12925 }
12926
12927 .active .circle-clipper.left::after {
12928 -webkit-animation-name: left-spin;
12929 animation-name: left-spin;
12930 }
12931
12932 .active .circle-clipper.right::after {
12933 -webkit-animation-name: right-spin;
12934 animation-name: right-spin;
12935 }
12936
12937 @-webkit-keyframes left-spin {
12938 0% { -webkit-transform: rotate(130deg) }
12939 50% { -webkit-transform: rotate(-5deg) }
12940 to { -webkit-transform: rotate(130deg) }
12941 }
12942
12943 @keyframes left-spin {
12944 0% { transform: rotate(130deg) }
12945 50% { transform: rotate(-5deg) }
12946 to { transform: rotate(130deg) }
12947 }
12948
12949 @-webkit-keyframes right-spin {
12950 0% { -webkit-transform: rotate(-130deg) }
12951 50% { -webkit-transform: rotate(5deg) }
12952 to { -webkit-transform: rotate(-130deg) }
12953 }
12954
12955 @keyframes right-spin {
12956 0% { transform: rotate(-130deg) }
12957 50% { transform: rotate(5deg) }
12958 to { transform: rotate(-130deg) }
12959 }
12960
12961 #spinnerContainer.cooldown {
12962 -webkit-animation: container-rotate var(--paper-spinner-container-rotati on-duration) linear infinite, fade-out var(--paper-spinner-cooldown-duration) cu bic-bezier(0.4, 0.0, 0.2, 1);
12963 animation: container-rotate var(--paper-spinner-container-rotation-durat ion) linear infinite, fade-out var(--paper-spinner-cooldown-duration) cubic-bezi er(0.4, 0.0, 0.2, 1);
12964 }
12965
12966 @-webkit-keyframes fade-out {
12967 0% { opacity: 1 }
12968 to { opacity: 0 }
12969 }
12970
12971 @keyframes fade-out {
12972 0% { opacity: 1 }
12973 to { opacity: 0 }
12974 }
12975 </style>
12976 </template>
12977 </dom-module>
12978
12979
12980 <dom-module id="paper-spinner-lite" assetpath="bower_components/paper-spinner/">
12981 <template strip-whitespace="">
12982 <style include="paper-spinner-styles"></style>
12983
12984 <div id="spinnerContainer" class-name="[[__computeContainerClasses(active, _ _coolingDown)]]">
12985 <div class="spinner-layer">
12986 <div class="circle-clipper left"></div>
12987 <div class="circle-clipper right"></div>
12988 </div>
12989 </div>
12990 </template>
12991
12992 <script>
12993 Polymer({
12994 is: 'paper-spinner-lite',
12995
12996 behaviors: [
12997 Polymer.PaperSpinnerBehavior
12998 ]
12999 });
13000 </script>
13001 </dom-module>
13002
13003 <dom-module id="iron-flex" assetpath="bower_components/iron-flex-layout/">
13004 <template>
13005 <style>
13006 .layout.horizontal,
13007 .layout.vertical {
13008 display: -ms-flexbox;
13009 display: -webkit-flex;
13010 display: flex;
13011 }
13012
13013 .layout.inline {
13014 display: -ms-inline-flexbox;
13015 display: -webkit-inline-flex;
13016 display: inline-flex;
13017 }
13018
13019 .layout.horizontal {
13020 -ms-flex-direction: row;
13021 -webkit-flex-direction: row;
13022 flex-direction: row;
13023 }
13024
13025 .layout.vertical {
13026 -ms-flex-direction: column;
13027 -webkit-flex-direction: column;
13028 flex-direction: column;
13029 }
13030
13031 .layout.wrap {
13032 -ms-flex-wrap: wrap;
13033 -webkit-flex-wrap: wrap;
13034 flex-wrap: wrap;
13035 }
13036
13037 .layout.center,
13038 .layout.center-center {
13039 -ms-flex-align: center;
13040 -webkit-align-items: center;
13041 align-items: center;
13042 }
13043
13044 .layout.center-justified,
13045 .layout.center-center {
13046 -ms-flex-pack: center;
13047 -webkit-justify-content: center;
13048 justify-content: center;
13049 }
13050
13051 .flex {
13052 -ms-flex: 1 1 0.000000001px;
13053 -webkit-flex: 1;
13054 flex: 1;
13055 -webkit-flex-basis: 0.000000001px;
13056 flex-basis: 0.000000001px;
13057 }
13058
13059 .flex-auto {
13060 -ms-flex: 1 1 auto;
13061 -webkit-flex: 1 1 auto;
13062 flex: 1 1 auto;
13063 }
13064
13065 .flex-none {
13066 -ms-flex: none;
13067 -webkit-flex: none;
13068 flex: none;
13069 }
13070 </style>
13071 </template>
13072 </dom-module>
13073
13074
13075 <dom-module id="iron-flex-reverse" assetpath="bower_components/iron-flex-layout/ ">
13076 <template>
13077 <style>
13078 .layout.horizontal-reverse,
13079 .layout.vertical-reverse {
13080 display: -ms-flexbox;
13081 display: -webkit-flex;
13082 display: flex;
13083 }
13084
13085 .layout.horizontal-reverse {
13086 -ms-flex-direction: row-reverse;
13087 -webkit-flex-direction: row-reverse;
13088 flex-direction: row-reverse;
13089 }
13090
13091 .layout.vertical-reverse {
13092 -ms-flex-direction: column-reverse;
13093 -webkit-flex-direction: column-reverse;
13094 flex-direction: column-reverse;
13095 }
13096
13097 .layout.wrap-reverse {
13098 -ms-flex-wrap: wrap-reverse;
13099 -webkit-flex-wrap: wrap-reverse;
13100 flex-wrap: wrap-reverse;
13101 }
13102 </style>
13103 </template>
13104 </dom-module>
13105
13106
13107 <dom-module id="iron-flex-alignment" assetpath="bower_components/iron-flex-layou t/">
13108 <template>
13109 <style>
13110 /**
13111 * Alignment in cross axis.
13112 */
13113 .layout.start {
13114 -ms-flex-align: start;
13115 -webkit-align-items: flex-start;
13116 align-items: flex-start;
13117 }
13118
13119 .layout.center,
13120 .layout.center-center {
13121 -ms-flex-align: center;
13122 -webkit-align-items: center;
13123 align-items: center;
13124 }
13125
13126 .layout.end {
13127 -ms-flex-align: end;
13128 -webkit-align-items: flex-end;
13129 align-items: flex-end;
13130 }
13131
13132 .layout.baseline {
13133 -ms-flex-align: baseline;
13134 -webkit-align-items: baseline;
13135 align-items: baseline;
13136 }
13137
13138 /**
13139 * Alignment in main axis.
13140 */
13141 .layout.start-justified {
13142 -ms-flex-pack: start;
13143 -webkit-justify-content: flex-start;
13144 justify-content: flex-start;
13145 }
13146
13147 .layout.center-justified,
13148 .layout.center-center {
13149 -ms-flex-pack: center;
13150 -webkit-justify-content: center;
13151 justify-content: center;
13152 }
13153
13154 .layout.end-justified {
13155 -ms-flex-pack: end;
13156 -webkit-justify-content: flex-end;
13157 justify-content: flex-end;
13158 }
13159
13160 .layout.around-justified {
13161 -ms-flex-pack: distribute;
13162 -webkit-justify-content: space-around;
13163 justify-content: space-around;
13164 }
13165
13166 .layout.justified {
13167 -ms-flex-pack: justify;
13168 -webkit-justify-content: space-between;
13169 justify-content: space-between;
13170 }
13171
13172 /**
13173 * Self alignment.
13174 */
13175 .self-start {
13176 -ms-align-self: flex-start;
13177 -webkit-align-self: flex-start;
13178 align-self: flex-start;
13179 }
13180
13181 .self-center {
13182 -ms-align-self: center;
13183 -webkit-align-self: center;
13184 align-self: center;
13185 }
13186
13187 .self-end {
13188 -ms-align-self: flex-end;
13189 -webkit-align-self: flex-end;
13190 align-self: flex-end;
13191 }
13192
13193 .self-stretch {
13194 -ms-align-self: stretch;
13195 -webkit-align-self: stretch;
13196 align-self: stretch;
13197 }
13198
13199 .self-baseline {
13200 -ms-align-self: baseline;
13201 -webkit-align-self: baseline;
13202 align-self: baseline;
13203 };
13204
13205 /**
13206 * multi-line alignment in main axis.
13207 */
13208 .layout.start-aligned {
13209 -ms-flex-line-pack: start; /* IE10 */
13210 -ms-align-content: flex-start;
13211 -webkit-align-content: flex-start;
13212 align-content: flex-start;
13213 }
13214
13215 .layout.end-aligned {
13216 -ms-flex-line-pack: end; /* IE10 */
13217 -ms-align-content: flex-end;
13218 -webkit-align-content: flex-end;
13219 align-content: flex-end;
13220 }
13221
13222 .layout.center-aligned {
13223 -ms-flex-line-pack: center; /* IE10 */
13224 -ms-align-content: center;
13225 -webkit-align-content: center;
13226 align-content: center;
13227 }
13228
13229 .layout.between-aligned {
13230 -ms-flex-line-pack: justify; /* IE10 */
13231 -ms-align-content: space-between;
13232 -webkit-align-content: space-between;
13233 align-content: space-between;
13234 }
13235
13236 .layout.around-aligned {
13237 -ms-flex-line-pack: distribute; /* IE10 */
13238 -ms-align-content: space-around;
13239 -webkit-align-content: space-around;
13240 align-content: space-around;
13241 }
13242 </style>
13243 </template>
13244 </dom-module>
13245
13246 <dom-module id="iron-flex-factors" assetpath="bower_components/iron-flex-layout/ ">
13247 <template>
13248 <style>
13249 .flex,
13250 .flex-1 {
13251 -ms-flex: 1 1 0.000000001px;
13252 -webkit-flex: 1;
13253 flex: 1;
13254 -webkit-flex-basis: 0.000000001px;
13255 flex-basis: 0.000000001px;
13256 }
13257
13258 .flex-2 {
13259 -ms-flex: 2;
13260 -webkit-flex: 2;
13261 flex: 2;
13262 }
13263
13264 .flex-3 {
13265 -ms-flex: 3;
13266 -webkit-flex: 3;
13267 flex: 3;
13268 }
13269
13270 .flex-4 {
13271 -ms-flex: 4;
13272 -webkit-flex: 4;
13273 flex: 4;
13274 }
13275
13276 .flex-5 {
13277 -ms-flex: 5;
13278 -webkit-flex: 5;
13279 flex: 5;
13280 }
13281
13282 .flex-6 {
13283 -ms-flex: 6;
13284 -webkit-flex: 6;
13285 flex: 6;
13286 }
13287
13288 .flex-7 {
13289 -ms-flex: 7;
13290 -webkit-flex: 7;
13291 flex: 7;
13292 }
13293
13294 .flex-8 {
13295 -ms-flex: 8;
13296 -webkit-flex: 8;
13297 flex: 8;
13298 }
13299
13300 .flex-9 {
13301 -ms-flex: 9;
13302 -webkit-flex: 9;
13303 flex: 9;
13304 }
13305
13306 .flex-10 {
13307 -ms-flex: 10;
13308 -webkit-flex: 10;
13309 flex: 10;
13310 }
13311
13312 .flex-11 {
13313 -ms-flex: 11;
13314 -webkit-flex: 11;
13315 flex: 11;
13316 }
13317
13318 .flex-12 {
13319 -ms-flex: 12;
13320 -webkit-flex: 12;
13321 flex: 12;
13322 }
13323 </style>
13324 </template>
13325 </dom-module>
13326
13327
13328 <dom-module id="iron-positioning" assetpath="bower_components/iron-flex-layout/" >
13329 <template>
13330 <style>
13331 .block {
13332 display: block;
13333 }
13334
13335 /* IE 10 support for HTML5 hidden attr */
13336 [hidden] {
13337 display: none !important;
13338 }
13339
13340 .invisible {
13341 visibility: hidden !important;
13342 }
13343
13344 .relative {
13345 position: relative;
13346 }
13347
13348 .fit {
13349 position: absolute;
13350 top: 0;
13351 right: 0;
13352 bottom: 0;
13353 left: 0;
13354 }
13355
13356 body.fullbleed {
13357 margin: 0;
13358 height: 100vh;
13359 }
13360
13361 .scroll {
13362 -webkit-overflow-scrolling: touch;
13363 overflow: auto;
13364 }
13365
13366 /* fixed position */
13367 .fixed-bottom,
13368 .fixed-left,
13369 .fixed-right,
13370 .fixed-top {
13371 position: fixed;
13372 }
13373
13374 .fixed-top {
13375 top: 0;
13376 left: 0;
13377 right: 0;
13378 }
13379
13380 .fixed-right {
13381 top: 0;
13382 right: 0;
13383 bottom: 0;
13384 }
13385
13386 .fixed-bottom {
13387 right: 0;
13388 bottom: 0;
13389 left: 0;
13390 }
13391
13392 .fixed-left {
13393 top: 0;
13394 bottom: 0;
13395 left: 0;
13396 }
13397 </style>
13398 </template>
13399 </dom-module>
13400 <script>
9162 (function() { 13401 (function() {
9163 "use strict"; 13402 "use strict";
9164 /** 13403 /**
9165 `Polymer.IronJsonpLibraryBehavior` loads a jsonp library. 13404 `Polymer.IronJsonpLibraryBehavior` loads a jsonp library.
9166 Multiple components can request same library, only one copy will load. 13405 Multiple components can request same library, only one copy will load.
9167 13406
9168 Some libraries require a specific global function be defined. 13407 Some libraries require a specific global function be defined.
9169 If this is the case, specify the `callbackName` property. 13408 If this is the case, specify the `callbackName` property.
9170 13409
9171 You should use an HTML Import to load library dependencies 13410 You should use an HTML Import to load library dependencies
(...skipping 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after
10219 } 14458 }
10220 }); 14459 });
10221 })(); 14460 })();
10222 </script> 14461 </script>
10223 <dom-module id="auth-signin" assetpath="imp/common/"> 14462 <dom-module id="auth-signin" assetpath="imp/common/">
10224 <template> 14463 <template>
10225 <style> 14464 <style>
10226 #avatar { 14465 #avatar {
10227 border-radius: 5px; 14466 border-radius: 5px;
10228 } 14467 }
10229 #signinContainer { 14468 a {
10230 margin-top: 14px; 14469 color: white;
14470 }
14471 .center {
14472 vertical-align: middle;
10231 } 14473 }
10232 </style> 14474 </style>
10233 14475
10234 <google-signin-aware id="aware" client-id="[[clientId]]" scopes="email" on-g oogle-signin-aware-success="_onSignin" on-google-signin-aware-signed-out="_onSig nout"> 14476 <google-signin-aware id="aware" client-id="[[clientId]]" scopes="email" on-g oogle-signin-aware-success="_onSignin" on-google-signin-aware-signed-out="_onSig nout">
10235 </google-signin-aware> 14477 </google-signin-aware>
10236 14478
10237 <template is="dom-if" if="[[!signedIn]]"> 14479 <template is="dom-if" if="[[!signedIn]]">
10238 <div id="signinContainer"> 14480 <div id="signinContainer">
10239 <a on-tap="signIn" href="#">Sign in</a> 14481 <a on-tap="signIn" href="#">Sign in</a>
10240 </div> 14482 </div>
10241 </template> 14483 </template>
10242 14484
10243 <template is="dom-if" if="[[signedIn]]"> 14485 <template is="dom-if" if="[[signedIn]]">
10244 <img id="avatar" src="[[profile.imageUrl]]" width="30" height="30"> 14486 <img class="center" id="avatar" src="[[profile.imageUrl]]" width="30" heig ht="30">
10245 <span>[[profile.email]]</span> 14487 <span class="center">[[profile.email]]</span>
10246 <span>|</span> 14488 <span class="center">|</span>
10247 <a on-tap="signOut" href="#">Sign out</a> 14489 <a class="center" on-tap="signOut" href="#">Sign out</a>
10248 </template> 14490 </template>
10249 </template> 14491 </template>
10250 <script> 14492 <script>
10251 'use strict'; 14493 'use strict';
10252 Polymer({ 14494 Polymer({
10253 is: 'auth-signin', 14495 is: 'auth-signin',
10254 properties: { 14496 properties: {
10255 authHeaders: { 14497 authHeaders: {
10256 type: Object, 14498 type: Object,
10257 computed: "_makeHeader(authResponse)", 14499 computed: "_makeHeader(authResponse)",
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
10303 14545
10304 signIn: function() { 14546 signIn: function() {
10305 this.$.aware.signIn(); 14547 this.$.aware.signIn();
10306 }, 14548 },
10307 14549
10308 signOut: function() { 14550 signOut: function() {
10309 this.$.aware.signOut(); 14551 this.$.aware.signOut();
10310 } 14552 }
10311 }); 14553 });
10312 </script> 14554 </script>
14555 </dom-module><dom-module id="swarming-app" assetpath="imp/common/">
14556 <template>
14557 <style include="iron-flex">
14558 :host {
14559 position: absolute;
14560 top: 0;
14561 bottom: 0;
14562 left: 0;
14563 right: 0;
14564 }
14565
14566 app-toolbar {
14567 background-color: #4285f4;
14568 color: #fff;
14569 }
14570
14571 app-toolbar a {
14572 color: #fff;
14573 }
14574 .left {
14575 margin-right:15px;
14576 }
14577 .right {
14578 margin-left:15px;
14579 }
14580
14581 paper-spinner-lite {
14582 --paper-spinner-color: var(--google-yellow-500);
14583 }
14584 </style>
14585 <app-header-layout>
14586 <app-header fixed="">
14587 <app-toolbar>
14588 <div class="title left">[[name]]</div>
14589 <paper-spinner-lite class="left" active="[[busy]]"></paper-spinner-lit e>
14590
14591 <a class="left" href="/newui/">Home</a>
14592 <a class="left" href="/newui/botlist">Bot List</a>
14593 <div class="flex"></div>
14594
14595 <auth-signin class="right" client-id="20770472288-t5smpbpjptka4nd888fv 0ctd23ftba2o.apps.googleusercontent.com" auth-headers="{{auth_headers}}">
14596 </auth-signin>
14597 </app-toolbar>
14598 </app-header>
14599 <div on-swarming-busy-start="_busyStart()" on-swarming-busy-end="_busyEnd( )">
14600 <content></content>
14601 </div>
14602 </app-header-layout>
14603
14604 </template>
14605 <script>
14606 Polymer({
14607 is: 'swarming-app',
14608 properties: {
14609 auth_headers: {
14610 type: Object,
14611 notify: true,
14612 },
14613 busy: {
14614 type: Boolean,
14615 },
14616 name: {
14617 type: String,
14618 },
14619 },
14620
14621 });
14622 </script>
10313 </dom-module><dom-module id="swarming-index" assetpath="imp/index/"> 14623 </dom-module><dom-module id="swarming-index" assetpath="imp/index/">
10314 <template> 14624 <template>
10315 <style> 14625 <style>
10316 :host { 14626 :host {
10317 display: block; 14627 display: block;
10318 } 14628 }
10319 </style> 14629 </style>
10320 14630
10321 <h1>HELLO WORLD</h1><h1> 14631 <swarming-app auth_headers="{{auth_headers}}" name="Swarming" busy="[[busy]] ">
10322 14632
10323 14633 <iron-ajax id="request" url="/_ah/api/swarming/v1/server/details" headers= "[[auth_headers]]" handle-as="json" last-response="{{serverDetails}}" loading="{ {busy}}">
10324 <auth-signin auth-headers="{{auth}}" client-id="20770472288-t5smpbpjptka4nd8 88fv0ctd23ftba2o.apps.googleusercontent.com" on-auth-signin="signIn"> 14634 </iron-ajax>
10325 </auth-signin>
10326 14635
10327 <iron-ajax id="request" url="/_ah/api/swarming/v1/server/details" headers="[ [auth]]" handle-as="json" on-response="handleResponse"> 14636 <h1>HELLO WORLD</h1>
10328 </iron-ajax>
10329 14637
10330 </h1></template> 14638 <div>Server Version: [[serverDetails.server_version]]</div>
14639
14640 </swarming-app>
14641
14642 </template>
10331 <script> 14643 <script>
10332 Polymer({ 14644 Polymer({
10333 is: 'swarming-index', 14645 is: 'swarming-index',
10334 14646
14647 properties: {
14648 auth_headers: {
14649 type: Object,
14650 observer: "signIn",
14651 },
14652
14653 serverDetails: {
14654 type: String,
14655 }
14656 },
14657
10335 signIn: function(){ 14658 signIn: function(){
10336 this.$.request.generateRequest(); 14659 this.$.request.generateRequest();
10337 }, 14660 },
10338 14661
10339 handleResponse: function(a,b){
10340 console.log(this.$.request.lastResponse);
10341 }
10342 }); 14662 });
10343 </script> 14663 </script>
10344 </dom-module></div> 14664 </dom-module></div>
10345 <swarming-index></swarming-index> 14665 <swarming-index></swarming-index>
10346 14666
10347 14667
10348 </body></html> 14668 </body></html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698