mirror of
https://github.com/home-assistant/core.git
synced 2025-04-28 03:07:50 +00:00
20450 lines
805 KiB
HTML
20450 lines
805 KiB
HTML
<div hidden><!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<link href="//fonts.googleapis.com/css?family=RobotoDraft:regular,bold,italic,thin,light,bolditalic,black,medium&lang=en" rel="stylesheet" type="text/css">
|
||
</div>
|
||
<div hidden><!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
@group Paper Elements
|
||
|
||
Material Design: <a href="http://www.google.com/design/spec/components/buttons.html">Buttons</a>
|
||
|
||
`paper-button` is a button. When the user touches the button, a ripple effect emanates
|
||
from the point of contact. It may be flat or raised. A raised button is styled with a
|
||
shadow.
|
||
|
||
Example:
|
||
|
||
<paper-button>flat button</paper-button>
|
||
<paper-button raised>raised button</paper-button>
|
||
|
||
You may use custom DOM in the button body to create a variety of buttons. For example, to
|
||
create a button with an icon and some text:
|
||
|
||
<paper-button>
|
||
<core-icon icon="favorite">
|
||
custom button content
|
||
</paper-button>
|
||
|
||
Styling
|
||
-------
|
||
|
||
Style the button with CSS as you would a normal DOM element.
|
||
|
||
/* make #my-button green with yellow text */
|
||
#my-button {
|
||
background: green;
|
||
color: yellow;
|
||
}
|
||
|
||
By default, the ripple is the same color as the foreground at 25% opacity. You may
|
||
customize the color using this selector:
|
||
|
||
/* make #my-button use a blue ripple instead of foreground color */
|
||
#my-button::shadow #ripple {
|
||
color: blue;
|
||
}
|
||
|
||
The opacity of the ripple is not customizable via CSS.
|
||
|
||
@element paper-button
|
||
@extends paper-button-base
|
||
@status unstable
|
||
-->
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<style shim-shadowdom="">
|
||
/*******************************
|
||
Flex Layout
|
||
*******************************/
|
||
|
||
html /deep/ [layout][horizontal], html /deep/ [layout][vertical] {
|
||
display: -ms-flexbox;
|
||
display: -webkit-flex;
|
||
display: flex;
|
||
}
|
||
|
||
html /deep/ [layout][horizontal][inline], html /deep/ [layout][vertical][inline] {
|
||
display: -ms-inline-flexbox;
|
||
display: -webkit-inline-flex;
|
||
display: inline-flex;
|
||
}
|
||
|
||
html /deep/ [layout][horizontal] {
|
||
-ms-flex-direction: row;
|
||
-webkit-flex-direction: row;
|
||
flex-direction: row;
|
||
}
|
||
|
||
html /deep/ [layout][horizontal][reverse] {
|
||
-ms-flex-direction: row-reverse;
|
||
-webkit-flex-direction: row-reverse;
|
||
flex-direction: row-reverse;
|
||
}
|
||
|
||
html /deep/ [layout][vertical] {
|
||
-ms-flex-direction: column;
|
||
-webkit-flex-direction: column;
|
||
flex-direction: column;
|
||
}
|
||
|
||
html /deep/ [layout][vertical][reverse] {
|
||
-ms-flex-direction: column-reverse;
|
||
-webkit-flex-direction: column-reverse;
|
||
flex-direction: column-reverse;
|
||
}
|
||
|
||
html /deep/ [layout][wrap] {
|
||
-ms-flex-wrap: wrap;
|
||
-webkit-flex-wrap: wrap;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
html /deep/ [layout][wrap-reverse] {
|
||
-ms-flex-wrap: wrap-reverse;
|
||
-webkit-flex-wrap: wrap-reverse;
|
||
flex-wrap: wrap-reverse;
|
||
}
|
||
|
||
html /deep/ [flex] {
|
||
-ms-flex: 1 1 0.000000001px;
|
||
-webkit-flex: 1;
|
||
flex: 1;
|
||
-webkit-flex-basis: 0.000000001px;
|
||
flex-basis: 0.000000001px;
|
||
}
|
||
|
||
html /deep/ [vertical][layout] > [flex][auto-vertical], html /deep/ [vertical][layout]::shadow [flex][auto-vertical] {
|
||
-ms-flex: 1 1 auto;
|
||
-webkit-flex-basis: auto;
|
||
flex-basis: auto;
|
||
}
|
||
|
||
html /deep/ [flex][auto] {
|
||
-ms-flex: 1 1 auto;
|
||
-webkit-flex-basis: auto;
|
||
flex-basis: auto;
|
||
}
|
||
|
||
html /deep/ [flex][none] {
|
||
-ms-flex: none;
|
||
-webkit-flex: none;
|
||
flex: none;
|
||
}
|
||
|
||
html /deep/ [flex][one] {
|
||
-ms-flex: 1;
|
||
-webkit-flex: 1;
|
||
flex: 1;
|
||
}
|
||
|
||
html /deep/ [flex][two] {
|
||
-ms-flex: 2;
|
||
-webkit-flex: 2;
|
||
flex: 2;
|
||
}
|
||
|
||
html /deep/ [flex][three] {
|
||
-ms-flex: 3;
|
||
-webkit-flex: 3;
|
||
flex: 3;
|
||
}
|
||
|
||
html /deep/ [flex][four] {
|
||
-ms-flex: 4;
|
||
-webkit-flex: 4;
|
||
flex: 4;
|
||
}
|
||
|
||
html /deep/ [flex][five] {
|
||
-ms-flex: 5;
|
||
-webkit-flex: 5;
|
||
flex: 5;
|
||
}
|
||
|
||
html /deep/ [flex][six] {
|
||
-ms-flex: 6;
|
||
-webkit-flex: 6;
|
||
flex: 6;
|
||
}
|
||
|
||
html /deep/ [flex][seven] {
|
||
-ms-flex: 7;
|
||
-webkit-flex: 7;
|
||
flex: 7;
|
||
}
|
||
|
||
html /deep/ [flex][eight] {
|
||
-ms-flex: 8;
|
||
-webkit-flex: 8;
|
||
flex: 8;
|
||
}
|
||
|
||
html /deep/ [flex][nine] {
|
||
-ms-flex: 9;
|
||
-webkit-flex: 9;
|
||
flex: 9;
|
||
}
|
||
|
||
html /deep/ [flex][ten] {
|
||
-ms-flex: 10;
|
||
-webkit-flex: 10;
|
||
flex: 10;
|
||
}
|
||
|
||
html /deep/ [flex][eleven] {
|
||
-ms-flex: 11;
|
||
-webkit-flex: 11;
|
||
flex: 11;
|
||
}
|
||
|
||
html /deep/ [flex][twelve] {
|
||
-ms-flex: 12;
|
||
-webkit-flex: 12;
|
||
flex: 12;
|
||
}
|
||
|
||
/* alignment in cross axis */
|
||
|
||
html /deep/ [layout][start] {
|
||
-ms-flex-align: start;
|
||
-webkit-align-items: flex-start;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
html /deep/ [layout][center], html /deep/ [layout][center-center] {
|
||
-ms-flex-align: center;
|
||
-webkit-align-items: center;
|
||
align-items: center;
|
||
}
|
||
|
||
html /deep/ [layout][end] {
|
||
-ms-flex-align: end;
|
||
-webkit-align-items: flex-end;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
/* alignment in main axis */
|
||
|
||
html /deep/ [layout][start-justified] {
|
||
-ms-flex-pack: start;
|
||
-webkit-justify-content: flex-start;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
html /deep/ [layout][center-justified], html /deep/ [layout][center-center] {
|
||
-ms-flex-pack: center;
|
||
-webkit-justify-content: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
html /deep/ [layout][end-justified] {
|
||
-ms-flex-pack: end;
|
||
-webkit-justify-content: flex-end;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
html /deep/ [layout][around-justified] {
|
||
-ms-flex-pack: distribute;
|
||
-webkit-justify-content: space-around;
|
||
justify-content: space-around;
|
||
}
|
||
|
||
html /deep/ [layout][justified] {
|
||
-ms-flex-pack: justify;
|
||
-webkit-justify-content: space-between;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/* self alignment */
|
||
|
||
html /deep/ [self-start] {
|
||
-ms-align-self: flex-start;
|
||
-webkit-align-self: flex-start;
|
||
align-self: flex-start;
|
||
}
|
||
|
||
html /deep/ [self-center] {
|
||
-ms-align-self: center;
|
||
-webkit-align-self: center;
|
||
align-self: center;
|
||
}
|
||
|
||
html /deep/ [self-end] {
|
||
-ms-align-self: flex-end;
|
||
-webkit-align-self: flex-end;
|
||
align-self: flex-end;
|
||
}
|
||
|
||
html /deep/ [self-stretch] {
|
||
-ms-align-self: stretch;
|
||
-webkit-align-self: stretch;
|
||
align-self: stretch;
|
||
}
|
||
|
||
/*******************************
|
||
Other Layout
|
||
*******************************/
|
||
|
||
html /deep/ [block] {
|
||
display: block;
|
||
}
|
||
|
||
/* ie support for hidden */
|
||
html /deep/ [hidden] {
|
||
display: none !important;
|
||
}
|
||
|
||
html /deep/ [relative] {
|
||
position: relative;
|
||
}
|
||
|
||
html /deep/ [fit] {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
body[fullbleed] {
|
||
margin: 0;
|
||
height: 100vh;
|
||
}
|
||
|
||
/*******************************
|
||
Other
|
||
*******************************/
|
||
|
||
html /deep/ [segment], html /deep/ segment {
|
||
display: block;
|
||
position: relative;
|
||
-webkit-box-sizing: border-box;
|
||
-ms-box-sizing: border-box;
|
||
box-sizing: border-box;
|
||
margin: 1em 0.5em;
|
||
padding: 1em;
|
||
background-color: white;
|
||
-webkit-box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
|
||
box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
|
||
border-radius: 5px 5px 5px 5px;
|
||
}
|
||
|
||
</style>
|
||
|
||
<script>/**
|
||
* @license
|
||
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
* Code distributed by Google as part of the polymer project is also
|
||
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
// @version: 0.4.2
|
||
window.PolymerGestures={},function(a){var b=!1,c=document.createElement("meta");if(c.createShadowRoot){var d=c.createShadowRoot(),e=document.createElement("span");d.appendChild(e),c.addEventListener("testpath",function(a){a.path&&(b=a.path[0]===e),a.stopPropagation()});var f=new CustomEvent("testpath",{bubbles:!0});document.head.appendChild(c),e.dispatchEvent(f),c.parentNode.removeChild(c),d=e=null}c=null;var g={shadow:function(a){return a?a.shadowRoot||a.webkitShadowRoot:void 0},canTarget:function(a){return a&&Boolean(a.elementFromPoint)},targetingShadow:function(a){var b=this.shadow(a);return this.canTarget(b)?b:void 0},olderShadow:function(a){var b=a.olderShadowRoot;if(!b){var c=a.querySelector("shadow");c&&(b=c.olderShadowRoot)}return b},allShadows:function(a){for(var b=[],c=this.shadow(a);c;)b.push(c),c=this.olderShadow(c);return b},searchRoot:function(a,b,c){var d,e;return a?(d=a.elementFromPoint(b,c),d?e=this.targetingShadow(d):a!==document&&(e=this.olderShadow(a)),this.searchRoot(e,b,c)||d):void 0},owner:function(a){if(!a)return document;for(var b=a;b.parentNode;)b=b.parentNode;return b.nodeType!=Node.DOCUMENT_NODE&&b.nodeType!=Node.DOCUMENT_FRAGMENT_NODE&&(b=document),b},findTarget:function(a){if(b&&a.path&&a.path.length)return a.path[0];var c=a.clientX,d=a.clientY,e=this.owner(a.target);return e.elementFromPoint(c,d)||(e=document),this.searchRoot(e,c,d)},findTouchAction:function(a){var c;if(b&&a.path&&a.path.length){for(var d=a.path,e=0;e<d.length;e++)if(c=d[e],c.nodeType===Node.ELEMENT_NODE&&c.hasAttribute("touch-action"))return c.getAttribute("touch-action")}else for(c=a.target;c;){if(c.nodeType===Node.ELEMENT_NODE&&c.hasAttribute("touch-action"))return c.getAttribute("touch-action");c=c.parentNode||c.host}return"auto"},LCA:function(a,b){if(a===b)return a;if(a&&!b)return a;if(b&&!a)return b;if(!b&&!a)return document;if(a.contains&&a.contains(b))return a;if(b.contains&&b.contains(a))return b;var c=this.depth(a),d=this.depth(b),e=c-d;for(e>=0?a=this.walk(a,e):b=this.walk(b,-e);a&&b&&a!==b;)a=a.parentNode||a.host,b=b.parentNode||b.host;return a},walk:function(a,b){for(var c=0;a&&b>c;c++)a=a.parentNode||a.host;return a},depth:function(a){for(var b=0;a;)b++,a=a.parentNode||a.host;return b},deepContains:function(a,b){var c=this.LCA(a,b);return c===a},insideNode:function(a,b,c){var d=a.getBoundingClientRect();return d.left<=b&&b<=d.right&&d.top<=c&&c<=d.bottom},path:function(a){var c;if(b&&a.path&&a.path.length)c=a.path;else{c=[];for(var d=this.findTarget(a);d;)c.push(d),d=d.parentNode||d.host}return c}};a.targetFinding=g,a.findTarget=g.findTarget.bind(g),a.deepContains=g.deepContains.bind(g),a.insideNode=g.insideNode}(window.PolymerGestures),function(){function a(a){return"html /deep/ "+b(a)}function b(a){return'[touch-action="'+a+'"]'}function c(a){return"{ -ms-touch-action: "+a+"; touch-action: "+a+";}"}var d=["none","auto","pan-x","pan-y",{rule:"pan-x pan-y",selectors:["pan-x pan-y","pan-y pan-x"]},"manipulation"],e="",f="string"==typeof document.head.style.touchAction,g=!window.ShadowDOMPolyfill&&document.head.createShadowRoot;if(f){d.forEach(function(d){String(d)===d?(e+=b(d)+c(d)+"\n",g&&(e+=a(d)+c(d)+"\n")):(e+=d.selectors.map(b)+c(d.rule)+"\n",g&&(e+=d.selectors.map(a)+c(d.rule)+"\n"))});var h=document.createElement("style");h.textContent=e,document.head.appendChild(h)}}(),function(a){var b=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","pageX","pageY"],c=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0],d=function(){return function(){}},e={preventTap:d,makeBaseEvent:function(a,b){var c=document.createEvent("Event");return c.initEvent(a,b.bubbles||!1,b.cancelable||!1),c.preventTap=e.preventTap(c),c},makeGestureEvent:function(a,b){b=b||Object.create(null);for(var c,d=this.makeBaseEvent(a,b),e=0,f=Object.keys(b);e<f.length;e++)c=f[e],d[c]=b[c];return d},makePointerEvent:function(a,d){d=d||Object.create(null);for(var e,f=this.makeBaseEvent(a,d),g=0;g<b.length;g++)e=b[g],f[e]=d[e]||c[g];f.buttons=d.buttons||0;var h=0;return h=d.pressure?d.pressure:f.buttons?.5:0,f.x=f.clientX,f.y=f.clientY,f.pointerId=d.pointerId||0,f.width=d.width||0,f.height=d.height||0,f.pressure=h,f.tiltX=d.tiltX||0,f.tiltY=d.tiltY||0,f.pointerType=d.pointerType||"",f.hwTimestamp=d.hwTimestamp||0,f.isPrimary=d.isPrimary||!1,f._source=d._source||"",f}};a.eventFactory=e}(window.PolymerGestures),function(a){function b(){if(c){var a=new Map;return a.pointers=d,a}this.keys=[],this.values=[]}var c=window.Map&&window.Map.prototype.forEach,d=function(){return this.size};b.prototype={set:function(a,b){var c=this.keys.indexOf(a);c>-1?this.values[c]=b:(this.keys.push(a),this.values.push(b))},has:function(a){return this.keys.indexOf(a)>-1},"delete":function(a){var b=this.keys.indexOf(a);b>-1&&(this.keys.splice(b,1),this.values.splice(b,1))},get:function(a){var b=this.keys.indexOf(a);return this.values[b]},clear:function(){this.keys.length=0,this.values.length=0},forEach:function(a,b){this.values.forEach(function(c,d){a.call(b,c,this.keys[d],this)},this)},pointers:function(){return this.keys.length}},a.PointerMap=b}(window.PolymerGestures),function(a){var b,c=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","buttons","pointerId","width","height","pressure","tiltX","tiltY","pointerType","hwTimestamp","isPrimary","type","target","currentTarget","which","pageX","pageY","timeStamp","preventTap","tapPrevented","_source"],d=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0,0,0,0,0,0,"",0,!1,"",null,null,0,0,0,0,function(){},!1],e="undefined"!=typeof SVGElementInstance,f=a.eventFactory,g={IS_IOS:!1,pointermap:new a.PointerMap,requiredGestures:new a.PointerMap,eventMap:Object.create(null),eventSources:Object.create(null),eventSourceList:[],gestures:[],dependencyMap:{down:{listeners:0,index:-1},up:{listeners:0,index:-1}},gestureQueue:[],registerSource:function(a,b){var c=b,d=c.events;d&&(d.forEach(function(a){c[a]&&(this.eventMap[a]=c[a].bind(c))},this),this.eventSources[a]=c,this.eventSourceList.push(c))},registerGesture:function(a,b){var c=Object.create(null);c.listeners=0,c.index=this.gestures.length;for(var d,e=0;e<b.exposes.length;e++)d=b.exposes[e].toLowerCase(),this.dependencyMap[d]=c;this.gestures.push(b)},register:function(a,b){for(var c,d=this.eventSourceList.length,e=0;d>e&&(c=this.eventSourceList[e]);e++)c.register.call(c,a,b)},unregister:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.unregister.call(b,a)},down:function(a){this.requiredGestures.set(a.pointerId,b),this.fireEvent("down",a)},move:function(a){a.type="move",this.fillGestureQueue(a)},up:function(a){this.fireEvent("up",a),this.requiredGestures.delete(a.pointerId)},cancel:function(a){a.tapPrevented=!0,this.fireEvent("up",a),this.requiredGestures.delete(a.pointerId)},addGestureDependency:function(a,b){var c=a._pgEvents;if(c)for(var d,e,f,g=Object.keys(c),h=0;h<g.length;h++)f=g[h],c[f]>0&&(d=this.dependencyMap[f],e=d?d.index:-1,b[e]=!0)},eventHandler:function(c){var d=c.type;if("touchstart"===d||"mousedown"===d||"pointerdown"===d||"MSPointerDown"===d)if(c._handledByPG||(b={}),this.IS_IOS)for(var e,f=a.targetFinding.path(c),g=0;g<f.length;g++)e=f[g],this.addGestureDependency(e,b);else this.addGestureDependency(c.currentTarget,b);if(!c._handledByPG){var h=this.eventMap&&this.eventMap[d];h&&h(c),c._handledByPG=!0}},listen:function(a,b){for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)this.addEvent(a,c)},unlisten:function(a,b){for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)this.removeEvent(a,c)},addEvent:function(a,b){a.addEventListener(b,this.boundHandler)},removeEvent:function(a,b){a.removeEventListener(b,this.boundHandler)},makeEvent:function(a,b){var c=f.makePointerEvent(a,b);return c.preventDefault=b.preventDefault,c.tapPrevented=b.tapPrevented,c._target=c._target||b.target,c},fireEvent:function(a,b){var c=this.makeEvent(a,b);return this.dispatchEvent(c)},cloneEvent:function(a){for(var b,f=Object.create(null),g=0;g<c.length;g++)b=c[g],f[b]=a[b]||d[g],("target"===b||"relatedTarget"===b)&&e&&f[b]instanceof SVGElementInstance&&(f[b]=f[b].correspondingUseElement);return f.preventDefault=function(){a.preventDefault()},f},dispatchEvent:function(a){var b=a._target;if(b){b.dispatchEvent(a);var c=this.cloneEvent(a);c.target=b,this.fillGestureQueue(c)}},gestureTrigger:function(){for(var a,b,c=0;c<this.gestureQueue.length;c++){a=this.gestureQueue[c],b=a._requiredGestures;for(var d,e,f=0;f<this.gestures.length;f++)b[f]&&(d=this.gestures[f],e=d[a.type],e&&e.call(d,a))}this.gestureQueue.length=0},fillGestureQueue:function(a){this.gestureQueue.length||requestAnimationFrame(this.boundGestureTrigger),a._requiredGestures=this.requiredGestures.get(a.pointerId),this.gestureQueue.push(a)}};g.boundHandler=g.eventHandler.bind(g),g.boundGestureTrigger=g.gestureTrigger.bind(g),a.dispatcher=g,a.activateGesture=function(a,b){var c=b.toLowerCase(),d=g.dependencyMap[c];if(d){var e=g.gestures[d.index];if(a._pgListeners||(g.register(a),a._pgListeners=0),e){var f,h=e.defaultActions&&e.defaultActions[c];switch(a.nodeType){case Node.ELEMENT_NODE:f=a;break;case Node.DOCUMENT_FRAGMENT_NODE:f=a.host;break;default:f=null}h&&f&&!f.hasAttribute("touch-action")&&f.setAttribute("touch-action",h)}a._pgEvents||(a._pgEvents={}),a._pgEvents[c]=(a._pgEvents[c]||0)+1,a._pgListeners++}return Boolean(d)},a.addEventListener=function(b,c,d,e){d&&(a.activateGesture(b,c),b.addEventListener(c,d,e))},a.deactivateGesture=function(a,b){var c=b.toLowerCase(),d=g.dependencyMap[c];return d&&(a._pgListeners>0&&a._pgListeners--,0===a._pgListeners&&g.unregister(a),a._pgEvents&&(a._pgEvents[c]>0?a._pgEvents[c]--:a._pgEvents[c]=0)),Boolean(d)},a.removeEventListener=function(b,c,d,e){d&&(a.deactivateGesture(b,c),b.removeEventListener(c,d,e))}}(window.PolymerGestures),function(a){var b=a.dispatcher,c=b.pointermap,d=25,e=[0,1,4,2],f=!1;try{f=1===new MouseEvent("test",{buttons:1}).buttons}catch(g){}var h={POINTER_ID:1,POINTER_TYPE:"mouse",events:["mousedown","mousemove","mouseup"],exposes:["down","up","move"],register:function(a){b.listen(a,this.events)},unregister:function(a){a!==document&&b.unlisten(a,this.events)},lastTouches:[],isEventSimulatedFromTouch:function(a){for(var b,c=this.lastTouches,e=a.clientX,f=a.clientY,g=0,h=c.length;h>g&&(b=c[g]);g++){var i=Math.abs(e-b.x),j=Math.abs(f-b.y);if(d>=i&&d>=j)return!0}},prepareEvent:function(a){var c=b.cloneEvent(a);return c.pointerId=this.POINTER_ID,c.isPrimary=!0,c.pointerType=this.POINTER_TYPE,c._source="mouse",f||(c.buttons=e[c.which]||0),c},mousedown:function(d){if(!this.isEventSimulatedFromTouch(d)){var e=c.has(this.POINTER_ID);e&&this.mouseup(d);var f=this.prepareEvent(d);f.target=a.findTarget(d),c.set(this.POINTER_ID,f.target),b.down(f)}},mousemove:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.get(this.POINTER_ID);if(d){var e=this.prepareEvent(a);e.target=d,0===e.buttons?(b.cancel(e),this.cleanupMouse()):b.move(e)}}},mouseup:function(d){if(!this.isEventSimulatedFromTouch(d)){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(this.POINTER_ID),b.up(e),this.cleanupMouse()}},cleanupMouse:function(){c["delete"](this.POINTER_ID)}};a.mouseEvents=h}(window.PolymerGestures),function(a){var b=a.dispatcher,c=(a.targetFinding.allShadows.bind(a.targetFinding),b.pointermap),d=(Array.prototype.map.call.bind(Array.prototype.map),2500),e=200,f=20,g=!1,h={IS_IOS:!1,events:["touchstart","touchmove","touchend","touchcancel"],exposes:["down","up","move"],register:function(a,c){(this.IS_IOS?c:!c)&&b.listen(a,this.events)},unregister:function(a){this.IS_IOS||b.unlisten(a,this.events)},scrollTypes:{EMITTER:"none",XSCROLLER:"pan-x",YSCROLLER:"pan-y"},touchActionToScrollType:function(a){var b=a,c=this.scrollTypes;return b===c.EMITTER?"none":b===c.XSCROLLER?"X":b===c.YSCROLLER?"Y":"XY"},POINTER_TYPE:"touch",firstTouch:null,isPrimaryTouch:function(a){return this.firstTouch===a.identifier},setPrimaryTouch:function(a){(0===c.pointers()||1===c.pointers()&&c.has(1))&&(this.firstTouch=a.identifier,this.firstXY={X:a.clientX,Y:a.clientY},this.scrolling=null,this.cancelResetClickCount())},removePrimaryPointer:function(a){a.isPrimary&&(this.firstTouch=null,this.firstXY=null,this.resetClickCount())},clickCount:0,resetId:null,resetClickCount:function(){var a=function(){this.clickCount=0,this.resetId=null}.bind(this);this.resetId=setTimeout(a,e)},cancelResetClickCount:function(){this.resetId&&clearTimeout(this.resetId)},typeToButtons:function(a){var b=0;return("touchstart"===a||"touchmove"===a)&&(b=1),b},findTarget:function(b,d){if("touchstart"===this.currentTouchEvent.type){if(this.isPrimaryTouch(b)){var e={clientX:b.clientX,clientY:b.clientY,path:this.currentTouchEvent.path,target:this.currentTouchEvent.target};return a.findTarget(e)}return a.findTarget(b)}return c.get(d)},touchToPointer:function(a){var c=this.currentTouchEvent,d=b.cloneEvent(a),e=d.pointerId=a.identifier+2;d.target=this.findTarget(a,e),d.bubbles=!0,d.cancelable=!0,d.detail=this.clickCount,d.buttons=this.typeToButtons(c.type),d.width=a.webkitRadiusX||a.radiusX||0,d.height=a.webkitRadiusY||a.radiusY||0,d.pressure=a.webkitForce||a.force||.5,d.isPrimary=this.isPrimaryTouch(a),d.pointerType=this.POINTER_TYPE,d._source="touch";var f=this;return d.preventDefault=function(){f.scrolling=!1,f.firstXY=null,c.preventDefault()},d},processTouches:function(a,b){var d=a.changedTouches;this.currentTouchEvent=a;for(var e,f,g=0;g<d.length;g++)e=d[g],f=this.touchToPointer(e),"touchstart"===a.type&&c.set(f.pointerId,f.target),c.has(f.pointerId)&&b.call(this,f),("touchend"===a.type||a._cancel)&&this.cleanUpPointer(f)},shouldScroll:function(b){if(this.firstXY){var c,d=a.targetFinding.findTouchAction(b),e=this.touchActionToScrollType(d);if("none"===e)c=!1;else if("XY"===e)c=!0;else{var f=b.changedTouches[0],g=e,h="Y"===e?"X":"Y",i=Math.abs(f["client"+g]-this.firstXY[g]),j=Math.abs(f["client"+h]-this.firstXY[h]);c=i>=j}return c}},findTouch:function(a,b){for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)if(c.identifier===b)return!0},vacuumTouches:function(a){var b=a.touches;if(c.pointers()>=b.length){var d=[];c.forEach(function(a,c){if(1!==c&&!this.findTouch(b,c-2)){var e=a;d.push(e)}},this),d.forEach(function(a){this.cancel(a),c.delete(a.pointerId)})}},touchstart:function(a){this.vacuumTouches(a),this.setPrimaryTouch(a.changedTouches[0]),this.dedupSynthMouse(a),this.scrolling||(this.clickCount++,this.processTouches(a,this.down))},down:function(a){b.down(a)},touchmove:function(a){if(g)a.cancelable&&this.processTouches(a,this.move);else if(this.scrolling){if(this.firstXY){var b=a.changedTouches[0],c=b.clientX-this.firstXY.X,d=b.clientY-this.firstXY.Y,e=Math.sqrt(c*c+d*d);e>=f&&(this.touchcancel(a),this.scrolling=!0,this.firstXY=null)}}else null===this.scrolling&&this.shouldScroll(a)?this.scrolling=!0:(this.scrolling=!1,a.preventDefault(),this.processTouches(a,this.move))},move:function(a){b.move(a)},touchend:function(a){this.dedupSynthMouse(a),this.processTouches(a,this.up)},up:function(c){c.relatedTarget=a.findTarget(c),b.up(c)},cancel:function(a){b.cancel(a)},touchcancel:function(a){a._cancel=!0,this.processTouches(a,this.cancel)},cleanUpPointer:function(a){c["delete"](a.pointerId),this.removePrimaryPointer(a)},dedupSynthMouse:function(b){var c=a.mouseEvents.lastTouches,e=b.changedTouches[0];if(this.isPrimaryTouch(e)){var f={x:e.clientX,y:e.clientY};c.push(f);var g=function(a,b){var c=a.indexOf(b);c>-1&&a.splice(c,1)}.bind(null,c,f);setTimeout(g,d)}}};a.touchEvents=h}(window.PolymerGestures),function(a){var b=a.dispatcher,c=b.pointermap,d=window.MSPointerEvent&&"number"==typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,e={events:["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerCancel"],register:function(a){b.listen(a,this.events)},unregister:function(a){a!==document&&b.unlisten(a,this.events)},POINTER_TYPES:["","unavailable","touch","pen","mouse"],prepareEvent:function(a){var c=a;return c=b.cloneEvent(a),d&&(c.pointerType=this.POINTER_TYPES[a.pointerType]),c._source="ms",c},cleanup:function(a){c["delete"](a)},MSPointerDown:function(d){var e=this.prepareEvent(d);e.target=a.findTarget(d),c.set(d.pointerId,e.target),b.down(e)},MSPointerMove:function(a){var d=c.get(a.pointerId);if(d){var e=this.prepareEvent(a);e.target=d,b.move(e)}},MSPointerUp:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.up(e),this.cleanup(d.pointerId)},MSPointerCancel:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.cancel(e),this.cleanup(d.pointerId)}};a.msEvents=e}(window.PolymerGestures),function(a){var b=a.dispatcher,c=b.pointermap,d={events:["pointerdown","pointermove","pointerup","pointercancel"],prepareEvent:function(a){var c=b.cloneEvent(a);return c._source="pointer",c},register:function(a){b.listen(a,this.events)},unregister:function(a){a!==document&&b.unlisten(a,this.events)},cleanup:function(a){c["delete"](a)},pointerdown:function(d){var e=this.prepareEvent(d);e.target=a.findTarget(d),c.set(e.pointerId,e.target),b.down(e)},pointermove:function(a){var d=c.get(a.pointerId);if(d){var e=this.prepareEvent(a);e.target=d,b.move(e)}},pointerup:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.up(e),this.cleanup(d.pointerId)},pointercancel:function(d){var e=this.prepareEvent(d);e.relatedTarget=a.findTarget(d),e.target=c.get(e.pointerId),b.cancel(e),this.cleanup(d.pointerId)}};a.pointerEvents=d}(window.PolymerGestures),function(a){var b=a.dispatcher,c=window.navigator;window.PointerEvent?b.registerSource("pointer",a.pointerEvents):c.msPointerEnabled?b.registerSource("ms",a.msEvents):(b.registerSource("mouse",a.mouseEvents),void 0!==window.ontouchstart&&b.registerSource("touch",a.touchEvents));var d=navigator.userAgent,e=d.match(/iPad|iPhone|iPod/)&&"ontouchstart"in window;b.IS_IOS=e,a.touchEvents.IS_IOS=e,b.register(document,!0)}(window.PolymerGestures),function(a){var b=a.dispatcher,c=a.eventFactory,d=new a.PointerMap,e={events:["down","move","up"],exposes:["trackstart","track","trackx","tracky","trackend"],defaultActions:{track:"none",trackx:"pan-y",tracky:"pan-x"},WIGGLE_THRESHOLD:4,clampDir:function(a){return a>0?1:-1},calcPositionDelta:function(a,b){var c=0,d=0;return a&&b&&(c=b.pageX-a.pageX,d=b.pageY-a.pageY),{x:c,y:d}},fireTrack:function(a,b,d){var e=d,f=this.calcPositionDelta(e.downEvent,b),g=this.calcPositionDelta(e.lastMoveEvent,b);if(g.x)e.xDirection=this.clampDir(g.x);else if("trackx"===a)return;if(g.y)e.yDirection=this.clampDir(g.y);else if("tracky"===a)return;var h={bubbles:!0,cancelable:!0,trackInfo:e.trackInfo,relatedTarget:b.relatedTarget,pointerType:b.pointerType,pointerId:b.pointerId,_source:"track"};"tracky"!==a&&(h.x=b.x,h.dx=f.x,h.ddx=g.x,h.clientX=b.clientX,h.pageX=b.pageX,h.screenX=b.screenX,h.xDirection=e.xDirection),"trackx"!==a&&(h.dy=f.y,h.ddy=g.y,h.y=b.y,h.clientY=b.clientY,h.pageY=b.pageY,h.screenY=b.screenY,h.yDirection=e.yDirection);var i=c.makeGestureEvent(a,h);e.downTarget.dispatchEvent(i)},down:function(a){if(a.isPrimary&&("mouse"===a.pointerType?1===a.buttons:!0)){var b={downEvent:a,downTarget:a.target,trackInfo:{},lastMoveEvent:null,xDirection:0,yDirection:0,tracking:!1};d.set(a.pointerId,b)}},move:function(a){var b=d.get(a.pointerId);if(b){if(!b.tracking){var c=this.calcPositionDelta(b.downEvent,a),e=c.x*c.x+c.y*c.y;e>this.WIGGLE_THRESHOLD&&(b.tracking=!0,b.lastMoveEvent=b.downEvent,this.fireTrack("trackstart",a,b))}b.tracking&&(this.fireTrack("track",a,b),this.fireTrack("trackx",a,b),this.fireTrack("tracky",a,b)),b.lastMoveEvent=a}},up:function(a){var b=d.get(a.pointerId);b&&(b.tracking&&this.fireTrack("trackend",a,b),d.delete(a.pointerId))}};b.registerGesture("track",e)}(window.PolymerGestures),function(a){var b=a.dispatcher,c=a.eventFactory,d={HOLD_DELAY:200,WIGGLE_THRESHOLD:16,events:["down","move","up"],exposes:["hold","holdpulse","release"],heldPointer:null,holdJob:null,pulse:function(){var a=Date.now()-this.heldPointer.timeStamp,b=this.held?"holdpulse":"hold";this.fireHold(b,a),this.held=!0},cancel:function(){clearInterval(this.holdJob),this.held&&this.fireHold("release"),this.held=!1,this.heldPointer=null,this.target=null,this.holdJob=null},down:function(a){a.isPrimary&&!this.heldPointer&&(this.heldPointer=a,this.target=a.target,this.holdJob=setInterval(this.pulse.bind(this),this.HOLD_DELAY))},up:function(a){this.heldPointer&&this.heldPointer.pointerId===a.pointerId&&this.cancel()},move:function(a){if(this.heldPointer&&this.heldPointer.pointerId===a.pointerId){var b=a.clientX-this.heldPointer.clientX,c=a.clientY-this.heldPointer.clientY;b*b+c*c>this.WIGGLE_THRESHOLD&&this.cancel()}},fireHold:function(a,b){var d={bubbles:!0,cancelable:!0,pointerType:this.heldPointer.pointerType,pointerId:this.heldPointer.pointerId,x:this.heldPointer.clientX,y:this.heldPointer.clientY,_source:"hold"};b&&(d.holdTime=b);var e=c.makeGestureEvent(a,d);this.target.dispatchEvent(e)}};b.registerGesture("hold",d)}(window.PolymerGestures),function(a){var b=a.dispatcher,c=a.eventFactory,d=new a.PointerMap,e={events:["down","up"],exposes:["tap"],down:function(a){a.isPrimary&&!a.tapPrevented&&d.set(a.pointerId,{target:a.target,buttons:a.buttons,x:a.clientX,y:a.clientY})},shouldTap:function(a,b){return"mouse"===a.pointerType?1===b.buttons:!a.tapPrevented},up:function(b){var e=d.get(b.pointerId);if(e&&this.shouldTap(b,e)){var f=a.targetFinding.LCA(e.target,b.relatedTarget);if(f){var g=c.makeGestureEvent("tap",{bubbles:!0,cancelable:!0,x:b.clientX,y:b.clientY,detail:b.detail,pointerType:b.pointerType,pointerId:b.pointerId,altKey:b.altKey,ctrlKey:b.ctrlKey,metaKey:b.metaKey,shiftKey:b.shiftKey,_source:"tap"});f.dispatchEvent(g)}}d.delete(b.pointerId)}};c.preventTap=function(a){return function(){a.tapPrevented=!0,d.delete(a.pointerId)}},b.registerGesture("tap",e)}(window.PolymerGestures),function(a){"use strict";function b(a,b){if(!a)throw new Error("ASSERT: "+b)}function c(a){return a>=48&&57>=a}function d(a){return 32===a||9===a||11===a||12===a||160===a||a>=5760&&"\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff".indexOf(String.fromCharCode(a))>0}function e(a){return 10===a||13===a||8232===a||8233===a}function f(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a}function g(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a||a>=48&&57>=a}function h(a){return"this"===a}function i(){for(;Y>X&&d(W.charCodeAt(X));)++X}function j(){var a,b;for(a=X++;Y>X&&(b=W.charCodeAt(X),g(b));)++X;return W.slice(a,X)}function k(){var a,b,c;return a=X,b=j(),c=1===b.length?S.Identifier:h(b)?S.Keyword:"null"===b?S.NullLiteral:"true"===b||"false"===b?S.BooleanLiteral:S.Identifier,{type:c,value:b,range:[a,X]}}function l(){var a,b,c=X,d=W.charCodeAt(X),e=W[X];switch(d){case 46:case 40:case 41:case 59:case 44:case 123:case 125:case 91:case 93:case 58:case 63:return++X,{type:S.Punctuator,value:String.fromCharCode(d),range:[c,X]};default:if(a=W.charCodeAt(X+1),61===a)switch(d){case 37:case 38:case 42:case 43:case 45:case 47:case 60:case 62:case 124:return X+=2,{type:S.Punctuator,value:String.fromCharCode(d)+String.fromCharCode(a),range:[c,X]};case 33:case 61:return X+=2,61===W.charCodeAt(X)&&++X,{type:S.Punctuator,value:W.slice(c,X),range:[c,X]}}}return b=W[X+1],e===b&&"&|".indexOf(e)>=0?(X+=2,{type:S.Punctuator,value:e+b,range:[c,X]}):"<>=!+-*%&|^/".indexOf(e)>=0?(++X,{type:S.Punctuator,value:e,range:[c,X]}):void s({},V.UnexpectedToken,"ILLEGAL")}function m(){var a,d,e;if(e=W[X],b(c(e.charCodeAt(0))||"."===e,"Numeric literal must start with a decimal digit or a decimal point"),d=X,a="","."!==e){for(a=W[X++],e=W[X],"0"===a&&e&&c(e.charCodeAt(0))&&s({},V.UnexpectedToken,"ILLEGAL");c(W.charCodeAt(X));)a+=W[X++];e=W[X]}if("."===e){for(a+=W[X++];c(W.charCodeAt(X));)a+=W[X++];e=W[X]}if("e"===e||"E"===e)if(a+=W[X++],e=W[X],("+"===e||"-"===e)&&(a+=W[X++]),c(W.charCodeAt(X)))for(;c(W.charCodeAt(X));)a+=W[X++];else s({},V.UnexpectedToken,"ILLEGAL");return f(W.charCodeAt(X))&&s({},V.UnexpectedToken,"ILLEGAL"),{type:S.NumericLiteral,value:parseFloat(a),range:[d,X]}}function n(){var a,c,d,f="",g=!1;for(a=W[X],b("'"===a||'"'===a,"String literal must starts with a quote"),c=X,++X;Y>X;){if(d=W[X++],d===a){a="";break}if("\\"===d)if(d=W[X++],d&&e(d.charCodeAt(0)))"\r"===d&&"\n"===W[X]&&++X;else switch(d){case"n":f+="\n";break;case"r":f+="\r";break;case"t":f+=" ";break;case"b":f+="\b";break;case"f":f+="\f";break;case"v":f+="";break;default:f+=d}else{if(e(d.charCodeAt(0)))break;f+=d}}return""!==a&&s({},V.UnexpectedToken,"ILLEGAL"),{type:S.StringLiteral,value:f,octal:g,range:[c,X]}}function o(a){return a.type===S.Identifier||a.type===S.Keyword||a.type===S.BooleanLiteral||a.type===S.NullLiteral}function p(){var a;return i(),X>=Y?{type:S.EOF,range:[X,X]}:(a=W.charCodeAt(X),40===a||41===a||58===a?l():39===a||34===a?n():f(a)?k():46===a?c(W.charCodeAt(X+1))?m():l():c(a)?m():l())}function q(){var a;return a=$,X=a.range[1],$=p(),X=a.range[1],a}function r(){var a;a=X,$=p(),X=a}function s(a,c){var d,e=Array.prototype.slice.call(arguments,2),f=c.replace(/%(\d)/g,function(a,c){return b(c<e.length,"Message reference must be in range"),e[c]});throw d=new Error(f),d.index=X,d.description=f,d}function t(a){s(a,V.UnexpectedToken,a.value)}function u(a){var b=q();(b.type!==S.Punctuator||b.value!==a)&&t(b)}function v(a){return $.type===S.Punctuator&&$.value===a}function w(a){return $.type===S.Keyword&&$.value===a}function x(){var a=[];for(u("[");!v("]");)v(",")?(q(),a.push(null)):(a.push(bb()),v("]")||u(","));return u("]"),Z.createArrayExpression(a)}function y(){var a;return i(),a=q(),a.type===S.StringLiteral||a.type===S.NumericLiteral?Z.createLiteral(a):Z.createIdentifier(a.value)}function z(){var a,b;return a=$,i(),(a.type===S.EOF||a.type===S.Punctuator)&&t(a),b=y(),u(":"),Z.createProperty("init",b,bb())}function A(){var a=[];for(u("{");!v("}");)a.push(z()),v("}")||u(",");return u("}"),Z.createObjectExpression(a)}function B(){var a;return u("("),a=bb(),u(")"),a}function C(){var a,b,c;return v("(")?B():(a=$.type,a===S.Identifier?c=Z.createIdentifier(q().value):a===S.StringLiteral||a===S.NumericLiteral?c=Z.createLiteral(q()):a===S.Keyword?w("this")&&(q(),c=Z.createThisExpression()):a===S.BooleanLiteral?(b=q(),b.value="true"===b.value,c=Z.createLiteral(b)):a===S.NullLiteral?(b=q(),b.value=null,c=Z.createLiteral(b)):v("[")?c=x():v("{")&&(c=A()),c?c:void t(q()))}function D(){var a=[];if(u("("),!v(")"))for(;Y>X&&(a.push(bb()),!v(")"));)u(",");return u(")"),a}function E(){var a;return a=q(),o(a)||t(a),Z.createIdentifier(a.value)}function F(){return u("."),E()}function G(){var a;return u("["),a=bb(),u("]"),a}function H(){var a,b,c;for(a=C();;)if(v("["))c=G(),a=Z.createMemberExpression("[",a,c);else if(v("."))c=F(),a=Z.createMemberExpression(".",a,c);else{if(!v("("))break;b=D(),a=Z.createCallExpression(a,b)}return a}function I(){var a,b;return $.type!==S.Punctuator&&$.type!==S.Keyword?b=ab():v("+")||v("-")||v("!")?(a=q(),b=I(),b=Z.createUnaryExpression(a.value,b)):w("delete")||w("void")||w("typeof")?s({},V.UnexpectedToken):b=ab(),b}function J(a){var b=0;if(a.type!==S.Punctuator&&a.type!==S.Keyword)return 0;switch(a.value){case"||":b=1;break;case"&&":b=2;break;case"==":case"!=":case"===":case"!==":b=6;break;case"<":case">":case"<=":case">=":case"instanceof":b=7;break;case"in":b=7;break;case"+":case"-":b=9;break;case"*":case"/":case"%":b=11}return b}function K(){var a,b,c,d,e,f,g,h;if(g=I(),b=$,c=J(b),0===c)return g;for(b.prec=c,q(),e=I(),d=[g,b,e];(c=J($))>0;){for(;d.length>2&&c<=d[d.length-2].prec;)e=d.pop(),f=d.pop().value,g=d.pop(),a=Z.createBinaryExpression(f,g,e),d.push(a);b=q(),b.prec=c,d.push(b),a=I(),d.push(a)}for(h=d.length-1,a=d[h];h>1;)a=Z.createBinaryExpression(d[h-1].value,d[h-2],a),h-=2;return a}function L(){var a,b,c;return a=K(),v("?")&&(q(),b=L(),u(":"),c=L(),a=Z.createConditionalExpression(a,b,c)),a}function M(){var a,b;return a=q(),a.type!==S.Identifier&&t(a),b=v("(")?D():[],Z.createFilter(a.value,b)}function N(){for(;v("|");)q(),M()}function O(){i(),r();var a=bb();a&&(","===$.value||"in"==$.value&&a.type===U.Identifier?Q(a):(N(),"as"===$.value?P(a):Z.createTopLevel(a))),$.type!==S.EOF&&t($)}function P(a){q();var b=q().value;Z.createAsExpression(a,b)}function Q(a){var b;","===$.value&&(q(),$.type!==S.Identifier&&t($),b=q().value),q();var c=bb();N(),Z.createInExpression(a.name,b,c)}function R(a,b){return Z=b,W=a,X=0,Y=W.length,$=null,_={labelSet:{}},O()}var S,T,U,V,W,X,Y,Z,$,_;S={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},T={},T[S.BooleanLiteral]="Boolean",T[S.EOF]="<end>",T[S.Identifier]="Identifier",T[S.Keyword]="Keyword",T[S.NullLiteral]="Null",T[S.NumericLiteral]="Numeric",T[S.Punctuator]="Punctuator",T[S.StringLiteral]="String",U={ArrayExpression:"ArrayExpression",BinaryExpression:"BinaryExpression",CallExpression:"CallExpression",ConditionalExpression:"ConditionalExpression",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",Identifier:"Identifier",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ThisExpression:"ThisExpression",UnaryExpression:"UnaryExpression"},V={UnexpectedToken:"Unexpected token %0",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared"};var ab=H,bb=L;a.esprima={parse:R}}(this),function(a){"use strict";function b(a,b,d,e){var f;try{if(f=c(a),f.scopeIdent&&(d.nodeType!==Node.ELEMENT_NODE||"TEMPLATE"!==d.tagName||"bind"!==b&&"repeat"!==b))throw Error("as and in can only be used within <template bind/repeat>")}catch(g){return void console.error("Invalid expression syntax: "+a,g)}return function(a,b,c){var d=f.getBinding(a,e,c);return f.scopeIdent&&d&&(b.polymerExpressionScopeIdent_=f.scopeIdent,f.indexIdent&&(b.polymerExpressionIndexIdent_=f.indexIdent)),d}}function c(a){var b=q[a];if(!b){var c=new j;esprima.parse(a,c),b=new l(c),q[a]=b}return b}function d(a){this.value=a,this.valueFn_=void 0}function e(a){this.name=a,this.path=Path.get(a)}function f(a,b,c){this.computed="["==c,this.dynamicDeps="function"==typeof a||a.dynamicDeps||this.computed&&!(b instanceof d),this.simplePath=!this.dynamicDeps&&(b instanceof e||b instanceof d)&&(a instanceof f||a instanceof e),this.object=this.simplePath?a:i(a),this.property=!this.computed||this.simplePath?b:i(b)}function g(a,b){this.name=a,this.args=[];for(var c=0;c<b.length;c++)this.args[c]=i(b[c])}function h(){throw Error("Not Implemented")}function i(a){return"function"==typeof a?a:a.valueFn()}function j(){this.expression=null,this.filters=[],this.deps={},this.currentPath=void 0,this.scopeIdent=void 0,this.indexIdent=void 0,this.dynamicDeps=!1}function k(a){this.value_=a}function l(a){if(this.scopeIdent=a.scopeIdent,this.indexIdent=a.indexIdent,!a.expression)throw Error("No expression found.");this.expression=a.expression,i(this.expression),this.filters=a.filters,this.dynamicDeps=a.dynamicDeps}function m(a){return String(a).replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()})}function n(a,b){for(;a[t]&&!Object.prototype.hasOwnProperty.call(a,b);)a=a[t];return a}function o(a){switch(a){case"":return!1;case"false":case"null":case"true":return!0}return isNaN(Number(a))?!1:!0}function p(){}var q=Object.create(null);d.prototype={valueFn:function(){if(!this.valueFn_){var a=this.value;this.valueFn_=function(){return a}}return this.valueFn_}},e.prototype={valueFn:function(){if(!this.valueFn_){var a=(this.name,this.path);this.valueFn_=function(b,c){return c&&c.addPath(b,a),a.getValueFrom(b)}}return this.valueFn_},setValue:function(a,b){return 1==this.path.length,a=n(a,this.path[0]),this.path.setValueFrom(a,b)}},f.prototype={get fullPath(){if(!this.fullPath_){var a=this.object instanceof f?this.object.fullPath.slice():[this.object.name];
|
||
a.push(this.property instanceof e?this.property.name:this.property.value),this.fullPath_=Path.get(a)}return this.fullPath_},valueFn:function(){if(!this.valueFn_){var a=this.object;if(this.simplePath){var b=this.fullPath;this.valueFn_=function(a,c){return c&&c.addPath(a,b),b.getValueFrom(a)}}else if(this.computed){var c=this.property;this.valueFn_=function(b,d,e){var f=a(b,d,e),g=c(b,d,e);return d&&d.addPath(f,[g]),f?f[g]:void 0}}else{var b=Path.get(this.property.name);this.valueFn_=function(c,d,e){var f=a(c,d,e);return d&&d.addPath(f,b),b.getValueFrom(f)}}}return this.valueFn_},setValue:function(a,b){if(this.simplePath)return this.fullPath.setValueFrom(a,b),b;var c=this.object(a),d=this.property instanceof e?this.property.name:this.property(a);return c[d]=b}},g.prototype={transform:function(a,b,c,d,e){var f=c[this.name],g=a;if(f)g=void 0;else if(f=g[this.name],!f)return void console.error("Cannot find function or filter: "+this.name);if(d?f=f.toModel:"function"==typeof f.toDOM&&(f=f.toDOM),"function"!=typeof f)return void console.error("Cannot find function or filter: "+this.name);for(var h=e||[],j=0;j<this.args.length;j++)h.push(i(this.args[j])(a,b,c));return f.apply(g,h)}};var r={"+":function(a){return+a},"-":function(a){return-a},"!":function(a){return!a}},s={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"*":function(a,b){return a*b},"/":function(a,b){return a/b},"%":function(a,b){return a%b},"<":function(a,b){return b>a},">":function(a,b){return a>b},"<=":function(a,b){return b>=a},">=":function(a,b){return a>=b},"==":function(a,b){return a==b},"!=":function(a,b){return a!=b},"===":function(a,b){return a===b},"!==":function(a,b){return a!==b},"&&":function(a,b){return a&&b},"||":function(a,b){return a||b}};j.prototype={createUnaryExpression:function(a,b){if(!r[a])throw Error("Disallowed operator: "+a);return b=i(b),function(c,d,e){return r[a](b(c,d,e))}},createBinaryExpression:function(a,b,c){if(!s[a])throw Error("Disallowed operator: "+a);switch(b=i(b),c=i(c),a){case"||":return this.dynamicDeps=!0,function(a,d,e){return b(a,d,e)||c(a,d,e)};case"&&":return this.dynamicDeps=!0,function(a,d,e){return b(a,d,e)&&c(a,d,e)}}return function(d,e,f){return s[a](b(d,e,f),c(d,e,f))}},createConditionalExpression:function(a,b,c){return a=i(a),b=i(b),c=i(c),this.dynamicDeps=!0,function(d,e,f){return a(d,e,f)?b(d,e,f):c(d,e,f)}},createIdentifier:function(a){var b=new e(a);return b.type="Identifier",b},createMemberExpression:function(a,b,c){var d=new f(b,c,a);return d.dynamicDeps&&(this.dynamicDeps=!0),d},createCallExpression:function(a,b){if(!(a instanceof e))throw Error("Only identifier function invocations are allowed");var c=new g(a.name,b);return function(a,b,d){return c.transform(a,b,d,!1)}},createLiteral:function(a){return new d(a.value)},createArrayExpression:function(a){for(var b=0;b<a.length;b++)a[b]=i(a[b]);return function(b,c,d){for(var e=[],f=0;f<a.length;f++)e.push(a[f](b,c,d));return e}},createProperty:function(a,b,c){return{key:b instanceof e?b.name:b.value,value:c}},createObjectExpression:function(a){for(var b=0;b<a.length;b++)a[b].value=i(a[b].value);return function(b,c,d){for(var e={},f=0;f<a.length;f++)e[a[f].key]=a[f].value(b,c,d);return e}},createFilter:function(a,b){this.filters.push(new g(a,b))},createAsExpression:function(a,b){this.expression=a,this.scopeIdent=b},createInExpression:function(a,b,c){this.expression=c,this.scopeIdent=a,this.indexIdent=b},createTopLevel:function(a){this.expression=a},createThisExpression:h},k.prototype={open:function(){return this.value_},discardChanges:function(){return this.value_},deliver:function(){},close:function(){}},l.prototype={getBinding:function(a,b,c){function d(){if(h)return h=!1,g;i.dynamicDeps&&f.startReset();var c=i.getValue(a,i.dynamicDeps?f:void 0,b);return i.dynamicDeps&&f.finishReset(),c}function e(c){return i.setValue(a,c,b),c}if(c)return this.getValue(a,void 0,b);var f=new CompoundObserver,g=this.getValue(a,f,b),h=!0,i=this;return new ObserverTransform(f,d,e,!0)},getValue:function(a,b,c){for(var d=i(this.expression)(a,b,c),e=0;e<this.filters.length;e++)d=this.filters[e].transform(a,b,c,!1,[d]);return d},setValue:function(a,b,c){for(var d=this.filters?this.filters.length:0;d-->0;)b=this.filters[d].transform(a,void 0,c,!0,[b]);return this.expression.setValue?this.expression.setValue(a,b):void 0}};var t="@"+Math.random().toString(36).slice(2);p.prototype={styleObject:function(a){var b=[];for(var c in a)b.push(m(c)+": "+a[c]);return b.join("; ")},tokenList:function(a){var b=[];for(var c in a)a[c]&&b.push(c);return b.join(" ")},prepareInstancePositionChanged:function(a){var b=a.polymerExpressionIndexIdent_;if(b)return function(a,c){a.model[b]=c}},prepareBinding:function(a,c,d){var e=Path.get(a);{if(o(a)||!e.valid)return b(a,c,d,this);if(1==e.length)return function(a,b,c){if(c)return e.getValueFrom(a);var d=n(a,e[0]);return new PathObserver(d,e)}}},prepareInstanceModel:function(a){var b=a.polymerExpressionScopeIdent_;if(b){var c=a.templateInstance?a.templateInstance.model:a.model,d=a.polymerExpressionIndexIdent_;return function(a){return u(c,a,b,d)}}}};var u="__proto__"in{}?function(a,b,c,d){var e={};return e[c]=b,e[d]=void 0,e[t]=a,e.__proto__=a,e}:function(a,b,c,d){var e=Object.create(a);return Object.defineProperty(e,c,{value:b,configurable:!0,writable:!0}),Object.defineProperty(e,d,{value:void 0,configurable:!0,writable:!0}),Object.defineProperty(e,t,{value:a,configurable:!0,writable:!0}),e};a.PolymerExpressions=p,p.getExpression=c}(this),Polymer={version:"0.4.2"},"function"==typeof window.Polymer&&(Polymer={}),window.Platform||(logFlags=window.logFlags||{},Platform={flush:function(){}},CustomElements={useNative:!0,ready:!0,takeRecords:function(){},"instanceof":function(a,b){return a instanceof b}},HTMLImports={useNative:!0},addEventListener("HTMLImportsLoaded",function(){document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))}),ShadowDOMPolyfill=null,wrap=unwrap=function(a){return a}),function(a){function b(a,b){b=b||q,d(function(){f(a,b)},b)}function c(a){return"complete"===a.readyState||a.readyState===s}function d(a,b){if(c(b))a&&a();else{var e=function(){("complete"===b.readyState||b.readyState===s)&&(b.removeEventListener(t,e),d(a,b))};b.addEventListener(t,e)}}function e(a){a.target.__loaded=!0}function f(a,b){function c(){h==i&&a&&a()}function d(a){e(a),h++,c()}var f=b.querySelectorAll("link[rel=import]"),h=0,i=f.length;if(i)for(var j,k=0;i>k&&(j=f[k]);k++)g(j)?d.call(j,{target:j}):(j.addEventListener("load",d),j.addEventListener("error",d));else c()}function g(a){return m?a.__loaded||a.import&&"loading"!==a.import.readyState:a.__importParsed}function h(a){for(var b,c=0,d=a.length;d>c&&(b=a[c]);c++)i(b)&&j(b)}function i(a){return"link"===a.localName&&"import"===a.rel}function j(a){var b=a.import;b?e({target:a}):(a.addEventListener("load",e),a.addEventListener("error",e))}var k="import",l=k in document.createElement("link"),m=l,n=/Trident/.test(navigator.userAgent),o=Boolean(window.ShadowDOMPolyfill),p=function(a){return o?ShadowDOMPolyfill.wrapIfNeeded(a):a},q=p(document),r={get:function(){var a=HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return p(a)},configurable:!0};Object.defineProperty(document,"_currentScript",r),Object.defineProperty(q,"_currentScript",r);var s=n?"complete":"interactive",t="readystatechange";m&&(new MutationObserver(function(a){for(var b,c=0,d=a.length;d>c&&(b=a[c]);c++)b.addedNodes&&h(b.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var a,b=document.querySelectorAll("link[rel=import]"),c=0,d=b.length;d>c&&(a=b[c]);c++)j(a)}()),b(function(){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime(),q.dispatchEvent(new CustomEvent("HTMLImportsLoaded",{bubbles:!0}))}),a.useNative=m,a.isImportLoaded=g,a.whenReady=b,a.rootDocument=q,a.IMPORT_LINK_TYPE=k,a.isIE=n}(window.HTMLImports),function(a){function b(a,b){return b=b||[],b.map||(b=[b]),a.apply(this,b.map(d))}function c(a,c,d){var e;switch(arguments.length){case 0:return;case 1:e=null;break;case 2:e=c.apply(this);break;default:e=b(d,c)}f[a]=e}function d(a){return f[a]}function e(a,c){HTMLImports.whenImportsReady(function(){b(c,a)})}var f={};a.marshal=d,a.modularize=c,a.using=e}(window),function(){var a=document.createElement("style");a.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; } \n";var b=document.querySelector("head");b.insertBefore(a,b.firstChild)}(Platform),function(a){"use strict";function b(){function a(a){b=a}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=[],c={},d=[];return Object.observe(c,a),Array.observe(d,a),c.id=1,c.id=2,delete c.id,d.push(1,2),d.length=0,Object.deliverChangeRecords(a),5!==b.length?!1:"add"!=b[0].type||"update"!=b[1].type||"delete"!=b[2].type||"splice"!=b[3].type||"splice"!=b[4].type?!1:(Object.unobserve(c,a),Array.unobserve(d,a),!0)}function c(){if("undefined"!=typeof chrome&&chrome.app&&chrome.app.runtime)return!1;if("undefined"!=typeof navigator&&navigator.getDeviceStorage)return!1;try{var a=new Function("","return true;");return a()}catch(b){return!1}}function d(a){return+a===a>>>0&&""!==a}function e(a){return+a}function f(a){return a===Object(a)}function g(a,b){return a===b?0!==a||1/a===1/b:R(a)&&R(b)?!0:a!==a&&b!==b}function h(a){if(void 0===a)return"eof";var b=a.charCodeAt(0);switch(b){case 91:case 93:case 46:case 34:case 39:case 48:return a;case 95:case 36:return"ident";case 32:case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return"ws"}return b>=97&&122>=b||b>=65&&90>=b?"ident":b>=49&&57>=b?"number":"else"}function i(){}function j(a){function b(){if(!(m>=a.length)){var b=a[m+1];return"inSingleQuote"==n&&"'"==b||"inDoubleQuote"==n&&'"'==b?(m++,d=b,o.append(),!0):void 0}}for(var c,d,e,f,g,j,k,l=[],m=-1,n="beforePath",o={push:function(){void 0!==e&&(l.push(e),e=void 0)},append:function(){void 0===e?e=d:e+=d}};n;)if(m++,c=a[m],"\\"!=c||!b(n)){if(f=h(c),k=W[n],g=k[f]||k["else"]||"error","error"==g)return;if(n=g[0],j=o[g[1]]||i,d=void 0===g[2]?c:g[2],j(),"afterPath"===n)return l}}function k(a){return V.test(a)}function l(a,b){if(b!==X)throw Error("Use Path.get to retrieve path objects");for(var c=0;c<a.length;c++)this.push(String(a[c]));Q&&this.length&&(this.getValueFrom=this.compiledGetValueFromFn())}function m(a){if(a instanceof l)return a;if((null==a||0==a.length)&&(a=""),"string"!=typeof a){if(d(a.length))return new l(a,X);a=String(a)}var b=Y[a];if(b)return b;var c=j(a);if(!c)return Z;var b=new l(c,X);return Y[a]=b,b}function n(a){return d(a)?"["+a+"]":'["'+a.replace(/"/g,'\\"')+'"]'}function o(b){for(var c=0;_>c&&b.check_();)c++;return O&&(a.dirtyCheckCycleCount=c),c>0}function p(a){for(var b in a)return!1;return!0}function q(a){return p(a.added)&&p(a.removed)&&p(a.changed)}function r(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function s(){if(!ab.length)return!1;for(var a=0;a<ab.length;a++)ab[a]();return ab.length=0,!0}function t(){function a(a){b&&b.state_===fb&&!d&&b.check_(a)}var b,c,d=!1,e=!0;return{open:function(c){if(b)throw Error("ObservedObject in use");e||Object.deliverChangeRecords(a),b=c,e=!1},observe:function(b,d){c=b,d?Array.observe(c,a):Object.observe(c,a)},deliver:function(b){d=b,Object.deliverChangeRecords(a),d=!1},close:function(){b=void 0,Object.unobserve(c,a),cb.push(this)}}}function u(a,b,c){var d=cb.pop()||t();return d.open(a),d.observe(b,c),d}function v(){function a(b,f){b&&(b===d&&(e[f]=!0),h.indexOf(b)<0&&(h.push(b),Object.observe(b,c)),a(Object.getPrototypeOf(b),f))}function b(a){for(var b=0;b<a.length;b++){var c=a[b];if(c.object!==d||e[c.name]||"setPrototype"===c.type)return!1}return!0}function c(c){if(!b(c)){for(var d,e=0;e<g.length;e++)d=g[e],d.state_==fb&&d.iterateObjects_(a);for(var e=0;e<g.length;e++)d=g[e],d.state_==fb&&d.check_()}}var d,e,f=0,g=[],h=[],i={object:void 0,objects:h,open:function(b,c){d||(d=c,e={}),g.push(b),f++,b.iterateObjects_(a)},close:function(){if(f--,!(f>0)){for(var a=0;a<h.length;a++)Object.unobserve(h[a],c),x.unobservedCount++;g.length=0,h.length=0,d=void 0,e=void 0,db.push(this)}}};return i}function w(a,b){return $&&$.object===b||($=db.pop()||v(),$.object=b),$.open(a,b),$}function x(){this.state_=eb,this.callback_=void 0,this.target_=void 0,this.directObserver_=void 0,this.value_=void 0,this.id_=ib++}function y(a){x._allObserversCount++,kb&&jb.push(a)}function z(){x._allObserversCount--}function A(a){x.call(this),this.value_=a,this.oldObject_=void 0}function B(a){if(!Array.isArray(a))throw Error("Provided object is not an Array");A.call(this,a)}function C(a,b){x.call(this),this.object_=a,this.path_=m(b),this.directObserver_=void 0}function D(a){x.call(this),this.reportChangesOnOpen_=a,this.value_=[],this.directObserver_=void 0,this.observed_=[]}function E(a){return a}function F(a,b,c,d){this.callback_=void 0,this.target_=void 0,this.value_=void 0,this.observable_=a,this.getValueFn_=b||E,this.setValueFn_=c||E,this.dontPassThroughSet_=d}function G(a,b,c){for(var d={},e={},f=0;f<b.length;f++){var g=b[f];nb[g.type]?(g.name in c||(c[g.name]=g.oldValue),"update"!=g.type&&("add"!=g.type?g.name in d?(delete d[g.name],delete c[g.name]):e[g.name]=!0:g.name in e?delete e[g.name]:d[g.name]=!0)):(console.error("Unknown changeRecord type: "+g.type),console.error(g))}for(var h in d)d[h]=a[h];for(var h in e)e[h]=void 0;var i={};for(var h in c)if(!(h in d||h in e)){var j=a[h];c[h]!==j&&(i[h]=j)}return{added:d,removed:e,changed:i}}function H(a,b,c){return{index:a,removed:b,addedCount:c}}function I(){}function J(a,b,c,d,e,f){return sb.calcSplices(a,b,c,d,e,f)}function K(a,b,c,d){return c>b||a>d?-1:b==c||d==a?0:c>a?d>b?b-c:d-c:b>d?d-a:b-a}function L(a,b,c,d){for(var e=H(b,c,d),f=!1,g=0,h=0;h<a.length;h++){var i=a[h];if(i.index+=g,!f){var j=K(e.index,e.index+e.removed.length,i.index,i.index+i.addedCount);if(j>=0){a.splice(h,1),h--,g-=i.addedCount-i.removed.length,e.addedCount+=i.addedCount-j;var k=e.removed.length+i.removed.length-j;if(e.addedCount||k){var c=i.removed;if(e.index<i.index){var l=e.removed.slice(0,i.index-e.index);Array.prototype.push.apply(l,c),c=l}if(e.index+e.removed.length>i.index+i.addedCount){var m=e.removed.slice(i.index+i.addedCount-e.index);Array.prototype.push.apply(c,m)}e.removed=c,i.index<e.index&&(e.index=i.index)}else f=!0}else if(e.index<i.index){f=!0,a.splice(h,0,e),h++;var n=e.addedCount-e.removed.length;i.index+=n,g+=n}}}f||a.push(e)}function M(a,b){for(var c=[],f=0;f<b.length;f++){var g=b[f];switch(g.type){case"splice":L(c,g.index,g.removed.slice(),g.addedCount);break;case"add":case"update":case"delete":if(!d(g.name))continue;var h=e(g.name);if(0>h)continue;L(c,h,[g.oldValue],1);break;default:console.error("Unexpected record type: "+JSON.stringify(g))}}return c}function N(a,b){var c=[];return M(a,b).forEach(function(b){return 1==b.addedCount&&1==b.removed.length?void(b.removed[0]!==a[b.index]&&c.push(b)):void(c=c.concat(J(a,b.index,b.index+b.addedCount,b.removed,0,b.removed.length)))}),c}var O=a.testingExposeCycleCount,P=b(),Q=c(),R=a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},S="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c},T="[$_a-zA-Z]",U="[$_a-zA-Z0-9]",V=new RegExp("^"+T+"+"+U+"*$"),W={beforePath:{ws:["beforePath"],ident:["inIdent","append"],"[":["beforeElement"],eof:["afterPath"]},inPath:{ws:["inPath"],".":["beforeIdent"],"[":["beforeElement"],eof:["afterPath"]},beforeIdent:{ws:["beforeIdent"],ident:["inIdent","append"]},inIdent:{ident:["inIdent","append"],0:["inIdent","append"],number:["inIdent","append"],ws:["inPath","push"],".":["beforeIdent","push"],"[":["beforeElement","push"],eof:["afterPath","push"]},beforeElement:{ws:["beforeElement"],0:["afterZero","append"],number:["inIndex","append"],"'":["inSingleQuote","append",""],'"':["inDoubleQuote","append",""]},afterZero:{ws:["afterElement","push"],"]":["inPath","push"]},inIndex:{0:["inIndex","append"],number:["inIndex","append"],ws:["afterElement"],"]":["inPath","push"]},inSingleQuote:{"'":["afterElement"],eof:["error"],"else":["inSingleQuote","append"]},inDoubleQuote:{'"':["afterElement"],eof:["error"],"else":["inDoubleQuote","append"]},afterElement:{ws:["afterElement"],"]":["inPath","push"]}},X={},Y={};l.get=m,l.prototype=S({__proto__:[],valid:!0,toString:function(){for(var a="",b=0;b<this.length;b++){var c=this[b];a+=k(c)?b?"."+c:c:n(c)}return a},getValueFrom:function(a){for(var b=0;b<this.length;b++){if(null==a)return;a=a[this[b]]}return a},iterateObjects:function(a,b){for(var c=0;c<this.length;c++){if(c&&(a=a[this[c-1]]),!f(a))return;b(a,this[0])}},compiledGetValueFromFn:function(){var a="",b="obj";a+="if (obj != null";for(var c,d=0;d<this.length-1;d++)c=this[d],b+=k(c)?"."+c:n(c),a+=" &&\n "+b+" != null";a+=")\n";var c=this[d];return b+=k(c)?"."+c:n(c),a+=" return "+b+";\nelse\n return undefined;",new Function("obj",a)},setValueFrom:function(a,b){if(!this.length)return!1;for(var c=0;c<this.length-1;c++){if(!f(a))return!1;a=a[this[c]]}return f(a)?(a[this[c]]=b,!0):!1}});var Z=new l("",X);Z.valid=!1,Z.getValueFrom=Z.setValueFrom=function(){};var $,_=1e3,ab=[],bb=P?function(){var a={pingPong:!0},b=!1;return Object.observe(a,function(){s(),b=!1}),function(c){ab.push(c),b||(b=!0,a.pingPong=!a.pingPong)}}():function(){return function(a){ab.push(a)}}(),cb=[],db=[],eb=0,fb=1,gb=2,hb=3,ib=1;x.prototype={open:function(a,b){if(this.state_!=eb)throw Error("Observer has already been opened.");return y(this),this.callback_=a,this.target_=b,this.connect_(),this.state_=fb,this.value_},close:function(){this.state_==fb&&(z(this),this.disconnect_(),this.value_=void 0,this.callback_=void 0,this.target_=void 0,this.state_=gb)},deliver:function(){this.state_==fb&&o(this)},report_:function(a){try{this.callback_.apply(this.target_,a)}catch(b){x._errorThrownDuringCallback=!0,console.error("Exception caught during observer callback: "+(b.stack||b))}},discardChanges:function(){return this.check_(void 0,!0),this.value_}};var jb,kb=!P;x._allObserversCount=0,kb&&(jb=[]);var lb=!1;a.Platform=a.Platform||{},a.Platform.performMicrotaskCheckpoint=function(){if(!lb&&kb){lb=!0;var b,c,d=0;do{d++,c=jb,jb=[],b=!1;for(var e=0;e<c.length;e++){var f=c[e];f.state_==fb&&(f.check_()&&(b=!0),jb.push(f))}s()&&(b=!0)}while(_>d&&b);O&&(a.dirtyCheckCycleCount=d),lb=!1}},kb&&(a.Platform.clearObservers=function(){jb=[]}),A.prototype=S({__proto__:x.prototype,arrayObserve:!1,connect_:function(){P?this.directObserver_=u(this,this.value_,this.arrayObserve):this.oldObject_=this.copyObject(this.value_)},copyObject:function(a){var b=Array.isArray(a)?[]:{};for(var c in a)b[c]=a[c];return Array.isArray(a)&&(b.length=a.length),b},check_:function(a){var b,c;if(P){if(!a)return!1;c={},b=G(this.value_,a,c)}else c=this.oldObject_,b=r(this.value_,this.oldObject_);return q(b)?!1:(P||(this.oldObject_=this.copyObject(this.value_)),this.report_([b.added||{},b.removed||{},b.changed||{},function(a){return c[a]}]),!0)},disconnect_:function(){P?(this.directObserver_.close(),this.directObserver_=void 0):this.oldObject_=void 0},deliver:function(){this.state_==fb&&(P?this.directObserver_.deliver(!1):o(this))},discardChanges:function(){return this.directObserver_?this.directObserver_.deliver(!0):this.oldObject_=this.copyObject(this.value_),this.value_}}),B.prototype=S({__proto__:A.prototype,arrayObserve:!0,copyObject:function(a){return a.slice()},check_:function(a){var b;if(P){if(!a)return!1;b=N(this.value_,a)}else b=J(this.value_,0,this.value_.length,this.oldObject_,0,this.oldObject_.length);return b&&b.length?(P||(this.oldObject_=this.copyObject(this.value_)),this.report_([b]),!0):!1}}),B.applySplices=function(a,b,c){c.forEach(function(c){for(var d=[c.index,c.removed.length],e=c.index;e<c.index+c.addedCount;)d.push(b[e]),e++;Array.prototype.splice.apply(a,d)})},C.prototype=S({__proto__:x.prototype,get path(){return this.path_},connect_:function(){P&&(this.directObserver_=w(this,this.object_)),this.check_(void 0,!0)},disconnect_:function(){this.value_=void 0,this.directObserver_&&(this.directObserver_.close(this),this.directObserver_=void 0)},iterateObjects_:function(a){this.path_.iterateObjects(this.object_,a)},check_:function(a,b){var c=this.value_;return this.value_=this.path_.getValueFrom(this.object_),b||g(this.value_,c)?!1:(this.report_([this.value_,c,this]),!0)},setValue:function(a){this.path_&&this.path_.setValueFrom(this.object_,a)}});var mb={};D.prototype=S({__proto__:x.prototype,connect_:function(){if(P){for(var a,b=!1,c=0;c<this.observed_.length;c+=2)if(a=this.observed_[c],a!==mb){b=!0;break}b&&(this.directObserver_=w(this,a))}this.check_(void 0,!this.reportChangesOnOpen_)},disconnect_:function(){for(var a=0;a<this.observed_.length;a+=2)this.observed_[a]===mb&&this.observed_[a+1].close();this.observed_.length=0,this.value_.length=0,this.directObserver_&&(this.directObserver_.close(this),this.directObserver_=void 0)},addPath:function(a,b){if(this.state_!=eb&&this.state_!=hb)throw Error("Cannot add paths once started.");var b=m(b);if(this.observed_.push(a,b),this.reportChangesOnOpen_){var c=this.observed_.length/2-1;this.value_[c]=b.getValueFrom(a)}},addObserver:function(a){if(this.state_!=eb&&this.state_!=hb)throw Error("Cannot add observers once started.");if(this.observed_.push(mb,a),this.reportChangesOnOpen_){var b=this.observed_.length/2-1;this.value_[b]=a.open(this.deliver,this)}},startReset:function(){if(this.state_!=fb)throw Error("Can only reset while open");this.state_=hb,this.disconnect_()},finishReset:function(){if(this.state_!=hb)throw Error("Can only finishReset after startReset");return this.state_=fb,this.connect_(),this.value_},iterateObjects_:function(a){for(var b,c=0;c<this.observed_.length;c+=2)b=this.observed_[c],b!==mb&&this.observed_[c+1].iterateObjects(b,a)},check_:function(a,b){for(var c,d=0;d<this.observed_.length;d+=2){var e,f=this.observed_[d],h=this.observed_[d+1];if(f===mb){var i=h;e=this.state_===eb?i.open(this.deliver,this):i.discardChanges()}else e=h.getValueFrom(f);b?this.value_[d/2]=e:g(e,this.value_[d/2])||(c=c||[],c[d/2]=this.value_[d/2],this.value_[d/2]=e)}return c?(this.report_([this.value_,c,this.observed_]),!0):!1}}),F.prototype={open:function(a,b){return this.callback_=a,this.target_=b,this.value_=this.getValueFn_(this.observable_.open(this.observedCallback_,this)),this.value_},observedCallback_:function(a){if(a=this.getValueFn_(a),!g(a,this.value_)){var b=this.value_;this.value_=a,this.callback_.call(this.target_,this.value_,b)}},discardChanges:function(){return this.value_=this.getValueFn_(this.observable_.discardChanges()),this.value_},deliver:function(){return this.observable_.deliver()},setValue:function(a){return a=this.setValueFn_(a),!this.dontPassThroughSet_&&this.observable_.setValue?this.observable_.setValue(a):void 0},close:function(){this.observable_&&this.observable_.close(),this.callback_=void 0,this.target_=void 0,this.observable_=void 0,this.value_=void 0,this.getValueFn_=void 0,this.setValueFn_=void 0}};var nb={add:!0,update:!0,"delete":!0},ob=0,pb=1,qb=2,rb=3;I.prototype={calcEditDistances:function(a,b,c,d,e,f){for(var g=f-e+1,h=c-b+1,i=new Array(g),j=0;g>j;j++)i[j]=new Array(h),i[j][0]=j;for(var k=0;h>k;k++)i[0][k]=k;for(var j=1;g>j;j++)for(var k=1;h>k;k++)if(this.equals(a[b+k-1],d[e+j-1]))i[j][k]=i[j-1][k-1];else{var l=i[j-1][k]+1,m=i[j][k-1]+1;i[j][k]=m>l?l:m}return i},spliceOperationsFromEditDistances:function(a){for(var b=a.length-1,c=a[0].length-1,d=a[b][c],e=[];b>0||c>0;)if(0!=b)if(0!=c){var f,g=a[b-1][c-1],h=a[b-1][c],i=a[b][c-1];f=i>h?g>h?h:g:g>i?i:g,f==g?(g==d?e.push(ob):(e.push(pb),d=g),b--,c--):f==h?(e.push(rb),b--,d=h):(e.push(qb),c--,d=i)}else e.push(rb),b--;else e.push(qb),c--;return e.reverse(),e},calcSplices:function(a,b,c,d,e,f){var g=0,h=0,i=Math.min(c-b,f-e);if(0==b&&0==e&&(g=this.sharedPrefix(a,d,i)),c==a.length&&f==d.length&&(h=this.sharedSuffix(a,d,i-g)),b+=g,e+=g,c-=h,f-=h,c-b==0&&f-e==0)return[];if(b==c){for(var j=H(b,[],0);f>e;)j.removed.push(d[e++]);return[j]}if(e==f)return[H(b,[],c-b)];for(var k=this.spliceOperationsFromEditDistances(this.calcEditDistances(a,b,c,d,e,f)),j=void 0,l=[],m=b,n=e,o=0;o<k.length;o++)switch(k[o]){case ob:j&&(l.push(j),j=void 0),m++,n++;break;case pb:j||(j=H(m,[],0)),j.addedCount++,m++,j.removed.push(d[n]),n++;break;case qb:j||(j=H(m,[],0)),j.addedCount++,m++;break;case rb:j||(j=H(m,[],0)),j.removed.push(d[n]),n++}return j&&l.push(j),l},sharedPrefix:function(a,b,c){for(var d=0;c>d;d++)if(!this.equals(a[d],b[d]))return d;return c},sharedSuffix:function(a,b,c){for(var d=a.length,e=b.length,f=0;c>f&&this.equals(a[--d],b[--e]);)f++;return f},calculateSplices:function(a,b){return this.calcSplices(a,0,a.length,b,0,b.length)},equals:function(a,b){return a===b}};var sb=new I;a.Observer=x,a.Observer.runEOM_=bb,a.Observer.observerSentinel_=mb,a.Observer.hasObjectObserve=P,a.ArrayObserver=B,a.ArrayObserver.calculateSplices=function(a,b){return sb.calculateSplices(a,b)},a.ArraySplice=I,a.ObjectObserver=A,a.PathObserver=C,a.CompoundObserver=D,a.Path=l,a.ObserverTransform=F}("undefined"!=typeof global&&global&&"undefined"!=typeof module&&module?global:this||window),function(){"use strict";function a(a){for(;a.parentNode;)a=a.parentNode;return"function"==typeof a.getElementById?a:null}function b(a,b,c){var d=a.bindings_;return d||(d=a.bindings_={}),d[b]&&c[b].close(),d[b]=c}function c(a,b,c){return c}function d(a){return null==a?"":a}function e(a,b){a.data=d(b)}function f(a){return function(b){return e(a,b)}}function g(a,b,c,e){return c?void(e?a.setAttribute(b,""):a.removeAttribute(b)):void a.setAttribute(b,d(e))}function h(a,b,c){return function(d){g(a,b,c,d)}}function i(a){switch(a.type){case"checkbox":return u;case"radio":case"select-multiple":case"select-one":return"change";case"range":if(/Trident|MSIE/.test(navigator.userAgent))return"change";default:return"input"}}function j(a,b,c,e){a[b]=(e||d)(c)}function k(a,b,c){return function(d){return j(a,b,d,c)}}function l(){}function m(a,b,c,d){function e(){c.setValue(a[b]),c.discardChanges(),(d||l)(a),Platform.performMicrotaskCheckpoint()}var f=i(a);return a.addEventListener(f,e),{close:function(){a.removeEventListener(f,e),c.close()},observable_:c}}function n(a){return Boolean(a)}function o(b){if(b.form)return s(b.form.elements,function(a){return a!=b&&"INPUT"==a.tagName&&"radio"==a.type&&a.name==b.name});var c=a(b);if(!c)return[];var d=c.querySelectorAll('input[type="radio"][name="'+b.name+'"]');return s(d,function(a){return a!=b&&!a.form})}function p(a){"INPUT"===a.tagName&&"radio"===a.type&&o(a).forEach(function(a){var b=a.bindings_.checked;b&&b.observable_.setValue(!1)})}function q(a,b){var c,e,f,g=a.parentNode;g instanceof HTMLSelectElement&&g.bindings_&&g.bindings_.value&&(c=g,e=c.bindings_.value,f=c.value),a.value=d(b),c&&c.value!=f&&(e.observable_.setValue(c.value),e.observable_.discardChanges(),Platform.performMicrotaskCheckpoint())}function r(a){return function(b){q(a,b)}}var s=Array.prototype.filter.call.bind(Array.prototype.filter);Node.prototype.bind=function(a,b){console.error("Unhandled binding to Node: ",this,a,b)},Node.prototype.bindFinished=function(){};var t=c;Object.defineProperty(Platform,"enableBindingsReflection",{get:function(){return t===b},set:function(a){return t=a?b:c,a},configurable:!0}),Text.prototype.bind=function(a,b,c){if("textContent"!==a)return Node.prototype.bind.call(this,a,b,c);if(c)return e(this,b);var d=b;return e(this,d.open(f(this))),t(this,a,d)},Element.prototype.bind=function(a,b,c){var d="?"==a[a.length-1];if(d&&(this.removeAttribute(a),a=a.slice(0,-1)),c)return g(this,a,d,b);var e=b;return g(this,a,d,e.open(h(this,a,d))),t(this,a,e)};var u;!function(){var a=document.createElement("div"),b=a.appendChild(document.createElement("input"));b.setAttribute("type","checkbox");var c,d=0;b.addEventListener("click",function(){d++,c=c||"click"}),b.addEventListener("change",function(){d++,c=c||"change"});var e=document.createEvent("MouseEvent");e.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),b.dispatchEvent(e),u=1==d?"change":c}(),HTMLInputElement.prototype.bind=function(a,c,e){if("value"!==a&&"checked"!==a)return HTMLElement.prototype.bind.call(this,a,c,e);this.removeAttribute(a);var f="checked"==a?n:d,g="checked"==a?p:l;if(e)return j(this,a,c,f);var h=c,i=m(this,a,h,g);return j(this,a,h.open(k(this,a,f)),f),b(this,a,i)},HTMLTextAreaElement.prototype.bind=function(a,b,c){if("value"!==a)return HTMLElement.prototype.bind.call(this,a,b,c);if(this.removeAttribute("value"),c)return j(this,"value",b);var e=b,f=m(this,"value",e);return j(this,"value",e.open(k(this,"value",d))),t(this,a,f)},HTMLOptionElement.prototype.bind=function(a,b,c){if("value"!==a)return HTMLElement.prototype.bind.call(this,a,b,c);if(this.removeAttribute("value"),c)return q(this,b);var d=b,e=m(this,"value",d);return q(this,d.open(r(this))),t(this,a,e)},HTMLSelectElement.prototype.bind=function(a,c,d){if("selectedindex"===a&&(a="selectedIndex"),"selectedIndex"!==a&&"value"!==a)return HTMLElement.prototype.bind.call(this,a,c,d);if(this.removeAttribute(a),d)return j(this,a,c);var e=c,f=m(this,a,e);return j(this,a,e.open(k(this,a))),b(this,a,f)}}(this),function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a){for(var b;b=a.parentNode;)a=b;return a}function d(a,b){if(b){for(var d,e="#"+b;!d&&(a=c(a),a.protoContent_?d=a.protoContent_.querySelector(e):a.getElementById&&(d=a.getElementById(b)),!d&&a.templateCreator_);)a=a.templateCreator_;return d}}function e(a){return"template"==a.tagName&&"http://www.w3.org/2000/svg"==a.namespaceURI}function f(a){return"TEMPLATE"==a.tagName&&"http://www.w3.org/1999/xhtml"==a.namespaceURI}function g(a){return Boolean(L[a.tagName]&&a.hasAttribute("template"))}function h(a){return void 0===a.isTemplate_&&(a.isTemplate_="TEMPLATE"==a.tagName||g(a)),a.isTemplate_}function i(a,b){var c=a.querySelectorAll(N);h(a)&&b(a),G(c,b)}function j(a){function b(a){HTMLTemplateElement.decorate(a)||j(a.content)}i(a,b)}function k(a,b){Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))})}function l(a){var b=a.ownerDocument;if(!b.defaultView)return b;var c=b.templateContentsOwner_;if(!c){for(c=b.implementation.createHTMLDocument("");c.lastChild;)c.removeChild(c.lastChild);b.templateContentsOwner_=c}return c}function m(a){if(!a.stagingDocument_){var b=a.ownerDocument;if(!b.stagingDocument_){b.stagingDocument_=b.implementation.createHTMLDocument(""),b.stagingDocument_.isStagingDocument=!0;var c=b.stagingDocument_.createElement("base");c.href=document.baseURI,b.stagingDocument_.head.appendChild(c),b.stagingDocument_.stagingDocument_=b.stagingDocument_}a.stagingDocument_=b.stagingDocument_}return a.stagingDocument_}function n(a){var b=a.ownerDocument.createElement("template");a.parentNode.insertBefore(b,a);for(var c=a.attributes,d=c.length;d-->0;){var e=c[d];K[e.name]&&("template"!==e.name&&b.setAttribute(e.name,e.value),a.removeAttribute(e.name))}return b}function o(a){var b=a.ownerDocument.createElement("template");a.parentNode.insertBefore(b,a);for(var c=a.attributes,d=c.length;d-->0;){var e=c[d];b.setAttribute(e.name,e.value),a.removeAttribute(e.name)}return a.parentNode.removeChild(a),b}function p(a,b,c){var d=a.content;if(c)return void d.appendChild(b);for(var e;e=b.firstChild;)d.appendChild(e)}function q(a){P?a.__proto__=HTMLTemplateElement.prototype:k(a,HTMLTemplateElement.prototype)}function r(a){a.setModelFn_||(a.setModelFn_=function(){a.setModelFnScheduled_=!1;
|
||
var b=z(a,a.delegate_&&a.delegate_.prepareBinding);w(a,b,a.model_)}),a.setModelFnScheduled_||(a.setModelFnScheduled_=!0,Observer.runEOM_(a.setModelFn_))}function s(a,b,c,d){if(a&&a.length){for(var e,f=a.length,g=0,h=0,i=0,j=!0;f>h;){var g=a.indexOf("{{",h),k=a.indexOf("[[",h),l=!1,m="}}";if(k>=0&&(0>g||g>k)&&(g=k,l=!0,m="]]"),i=0>g?-1:a.indexOf(m,g+2),0>i){if(!e)return;e.push(a.slice(h));break}e=e||[],e.push(a.slice(h,g));var n=a.slice(g+2,i).trim();e.push(l),j=j&&l;var o=d&&d(n,b,c);e.push(null==o?Path.get(n):null),e.push(o),h=i+2}return h===f&&e.push(""),e.hasOnePath=5===e.length,e.isSimplePath=e.hasOnePath&&""==e[0]&&""==e[4],e.onlyOneTime=j,e.combinator=function(a){for(var b=e[0],c=1;c<e.length;c+=4){var d=e.hasOnePath?a:a[(c-1)/4];void 0!==d&&(b+=d),b+=e[c+3]}return b},e}}function t(a,b,c,d){if(b.hasOnePath){var e=b[3],f=e?e(d,c,!0):b[2].getValueFrom(d);return b.isSimplePath?f:b.combinator(f)}for(var g=[],h=1;h<b.length;h+=4){var e=b[h+2];g[(h-1)/4]=e?e(d,c):b[h+1].getValueFrom(d)}return b.combinator(g)}function u(a,b,c,d){var e=b[3],f=e?e(d,c,!1):new PathObserver(d,b[2]);return b.isSimplePath?f:new ObserverTransform(f,b.combinator)}function v(a,b,c,d){if(b.onlyOneTime)return t(a,b,c,d);if(b.hasOnePath)return u(a,b,c,d);for(var e=new CompoundObserver,f=1;f<b.length;f+=4){var g=b[f],h=b[f+2];if(h){var i=h(d,c,g);g?e.addPath(i):e.addObserver(i)}else{var j=b[f+1];g?e.addPath(j.getValueFrom(d)):e.addPath(d,j)}}return new ObserverTransform(e,b.combinator)}function w(a,b,c,d){for(var e=0;e<b.length;e+=2){var f=b[e],g=b[e+1],h=v(f,g,a,c),i=a.bind(f,h,g.onlyOneTime);i&&d&&d.push(i)}if(a.bindFinished(),b.isTemplate){a.model_=c;var j=a.processBindingDirectives_(b);d&&j&&d.push(j)}}function x(a,b,c){var d=a.getAttribute(b);return s(""==d?"{{}}":d,b,a,c)}function y(a,c){b(a);for(var d=[],e=0;e<a.attributes.length;e++){for(var f=a.attributes[e],g=f.name,i=f.value;"_"===g[0];)g=g.substring(1);if(!h(a)||g!==J&&g!==H&&g!==I){var j=s(i,g,a,c);j&&d.push(g,j)}}return h(a)&&(d.isTemplate=!0,d.if=x(a,J,c),d.bind=x(a,H,c),d.repeat=x(a,I,c),!d.if||d.bind||d.repeat||(d.bind=s("{{}}",H,a,c))),d}function z(a,b){if(a.nodeType===Node.ELEMENT_NODE)return y(a,b);if(a.nodeType===Node.TEXT_NODE){var c=s(a.data,"textContent",a,b);if(c)return["textContent",c]}return[]}function A(a,b,c,d,e,f,g){for(var h=b.appendChild(c.importNode(a,!1)),i=0,j=a.firstChild;j;j=j.nextSibling)A(j,h,c,d.children[i++],e,f,g);return d.isTemplate&&(HTMLTemplateElement.decorate(h,a),f&&h.setDelegate_(f)),w(h,d,e,g),h}function B(a,b){var c=z(a,b);c.children={};for(var d=0,e=a.firstChild;e;e=e.nextSibling)c.children[d++]=B(e,b);return c}function C(a){var b=a.id_;return b||(b=a.id_=S++),b}function D(a,b){var c=C(a);if(b){var d=b.bindingMaps[c];return d||(d=b.bindingMaps[c]=B(a,b.prepareBinding)||[]),d}var d=a.bindingMap_;return d||(d=a.bindingMap_=B(a,void 0)||[]),d}function E(a){this.closed=!1,this.templateElement_=a,this.instances=[],this.deps=void 0,this.iteratedValue=[],this.presentValue=void 0,this.arrayObserver=void 0}var F,G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.Map&&"function"==typeof a.Map.prototype.forEach?F=a.Map:(F=function(){this.keys=[],this.values=[]},F.prototype={set:function(a,b){var c=this.keys.indexOf(a);0>c?(this.keys.push(a),this.values.push(b)):this.values[c]=b},get:function(a){var b=this.keys.indexOf(a);if(!(0>b))return this.values[b]},"delete":function(a){var b=this.keys.indexOf(a);return 0>b?!1:(this.keys.splice(b,1),this.values.splice(b,1),!0)},forEach:function(a,b){for(var c=0;c<this.keys.length;c++)a.call(b||this,this.values[c],this.keys[c],this)}});"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)});var H="bind",I="repeat",J="if",K={template:!0,repeat:!0,bind:!0,ref:!0},L={THEAD:!0,TBODY:!0,TFOOT:!0,TH:!0,TR:!0,TD:!0,COLGROUP:!0,COL:!0,CAPTION:!0,OPTION:!0,OPTGROUP:!0},M="undefined"!=typeof HTMLTemplateElement;M&&!function(){var a=document.createElement("template"),b=a.content.ownerDocument,c=b.appendChild(b.createElement("html")),d=c.appendChild(b.createElement("head")),e=b.createElement("base");e.href=document.baseURI,d.appendChild(e)}();var N="template, "+Object.keys(L).map(function(a){return a.toLowerCase()+"[template]"}).join(", ");document.addEventListener("DOMContentLoaded",function(){j(document),Platform.performMicrotaskCheckpoint()},!1),M||(a.HTMLTemplateElement=function(){throw TypeError("Illegal constructor")});var O,P="__proto__"in{};"function"==typeof MutationObserver&&(O=new MutationObserver(function(a){for(var b=0;b<a.length;b++)a[b].target.refChanged_()})),HTMLTemplateElement.decorate=function(a,c){if(a.templateIsDecorated_)return!1;var d=a;d.templateIsDecorated_=!0;var h=f(d)&&M,i=h,k=!h,m=!1;if(h||(g(d)?(b(!c),d=n(a),d.templateIsDecorated_=!0,h=M,m=!0):e(d)&&(d=o(a),d.templateIsDecorated_=!0,h=M)),!h){q(d);var r=l(d);d.content_=r.createDocumentFragment()}return c?d.instanceRef_=c:k?p(d,a,m):i&&j(d.content),!0},HTMLTemplateElement.bootstrap=j;var Q=a.HTMLUnknownElement||HTMLElement,R={get:function(){return this.content_},enumerable:!0,configurable:!0};M||(HTMLTemplateElement.prototype=Object.create(Q.prototype),Object.defineProperty(HTMLTemplateElement.prototype,"content",R)),k(HTMLTemplateElement.prototype,{bind:function(a,b,c){if("ref"!=a)return Element.prototype.bind.call(this,a,b,c);var d=this,e=c?b:b.open(function(a){d.setAttribute("ref",a),d.refChanged_()});return this.setAttribute("ref",e),this.refChanged_(),c?void 0:(this.bindings_?this.bindings_.ref=b:this.bindings_={ref:b},b)},processBindingDirectives_:function(a){return this.iterator_&&this.iterator_.closeDeps(),a.if||a.bind||a.repeat?(this.iterator_||(this.iterator_=new E(this)),this.iterator_.updateDependencies(a,this.model_),O&&O.observe(this,{attributes:!0,attributeFilter:["ref"]}),this.iterator_):void(this.iterator_&&(this.iterator_.close(),this.iterator_=void 0))},createInstance:function(a,b,c){b?c=this.newDelegate_(b):c||(c=this.delegate_),this.refContent_||(this.refContent_=this.ref_.content);var d=this.refContent_;if(null===d.firstChild)return T;var e=D(d,c),f=m(this),g=f.createDocumentFragment();g.templateCreator_=this,g.protoContent_=d,g.bindings_=[],g.terminator_=null;for(var h=g.templateInstance_={firstNode:null,lastNode:null,model:a},i=0,j=!1,k=d.firstChild;k;k=k.nextSibling){null===k.nextSibling&&(j=!0);var l=A(k,g,f,e.children[i++],a,c,g.bindings_);l.templateInstance_=h,j&&(g.terminator_=l)}return h.firstNode=g.firstChild,h.lastNode=g.lastChild,g.templateCreator_=void 0,g.protoContent_=void 0,g},get model(){return this.model_},set model(a){this.model_=a,r(this)},get bindingDelegate(){return this.delegate_&&this.delegate_.raw},refChanged_:function(){this.iterator_&&this.refContent_!==this.ref_.content&&(this.refContent_=void 0,this.iterator_.valueChanged(),this.iterator_.updateIteratedValue(this.iterator_.getUpdatedValue()))},clear:function(){this.model_=void 0,this.delegate_=void 0,this.bindings_&&this.bindings_.ref&&this.bindings_.ref.close(),this.refContent_=void 0,this.iterator_&&(this.iterator_.valueChanged(),this.iterator_.close(),this.iterator_=void 0)},setDelegate_:function(a){this.delegate_=a,this.bindingMap_=void 0,this.iterator_&&(this.iterator_.instancePositionChangedFn_=void 0,this.iterator_.instanceModelFn_=void 0)},newDelegate_:function(a){function b(b){var c=a&&a[b];if("function"==typeof c)return function(){return c.apply(a,arguments)}}if(a)return{bindingMaps:{},raw:a,prepareBinding:b("prepareBinding"),prepareInstanceModel:b("prepareInstanceModel"),prepareInstancePositionChanged:b("prepareInstancePositionChanged")}},set bindingDelegate(a){if(this.delegate_)throw Error("Template must be cleared before a new bindingDelegate can be assigned");this.setDelegate_(this.newDelegate_(a))},get ref_(){var a=d(this,this.getAttribute("ref"));if(a||(a=this.instanceRef_),!a)return this;var b=a.ref_;return b?b:a}});var S=1;Object.defineProperty(Node.prototype,"templateInstance",{get:function(){var a=this.templateInstance_;return a?a:this.parentNode?this.parentNode.templateInstance:void 0}});var T=document.createDocumentFragment();T.bindings_=[],T.terminator_=null,E.prototype={closeDeps:function(){var a=this.deps;a&&(a.ifOneTime===!1&&a.ifValue.close(),a.oneTime===!1&&a.value.close())},updateDependencies:function(a,b){this.closeDeps();var c=this.deps={},d=this.templateElement_,e=!0;if(a.if){if(c.hasIf=!0,c.ifOneTime=a.if.onlyOneTime,c.ifValue=v(J,a.if,d,b),e=c.ifValue,c.ifOneTime&&!e)return void this.valueChanged();c.ifOneTime||(e=e.open(this.updateIfValue,this))}a.repeat?(c.repeat=!0,c.oneTime=a.repeat.onlyOneTime,c.value=v(I,a.repeat,d,b)):(c.repeat=!1,c.oneTime=a.bind.onlyOneTime,c.value=v(H,a.bind,d,b));var f=c.value;return c.oneTime||(f=f.open(this.updateIteratedValue,this)),e?void this.updateValue(f):void this.valueChanged()},getUpdatedValue:function(){var a=this.deps.value;return this.deps.oneTime||(a=a.discardChanges()),a},updateIfValue:function(a){return a?void this.updateValue(this.getUpdatedValue()):void this.valueChanged()},updateIteratedValue:function(a){if(this.deps.hasIf){var b=this.deps.ifValue;if(this.deps.ifOneTime||(b=b.discardChanges()),!b)return void this.valueChanged()}this.updateValue(a)},updateValue:function(a){this.deps.repeat||(a=[a]);var b=this.deps.repeat&&!this.deps.oneTime&&Array.isArray(a);this.valueChanged(a,b)},valueChanged:function(a,b){Array.isArray(a)||(a=[]),a!==this.iteratedValue&&(this.unobserve(),this.presentValue=a,b&&(this.arrayObserver=new ArrayObserver(this.presentValue),this.arrayObserver.open(this.handleSplices,this)),this.handleSplices(ArrayObserver.calculateSplices(this.presentValue,this.iteratedValue)))},getLastInstanceNode:function(a){if(-1==a)return this.templateElement_;var b=this.instances[a],c=b.terminator_;if(!c)return this.getLastInstanceNode(a-1);if(c.nodeType!==Node.ELEMENT_NODE||this.templateElement_===c)return c;var d=c.iterator_;return d?d.getLastTemplateNode():c},getLastTemplateNode:function(){return this.getLastInstanceNode(this.instances.length-1)},insertInstanceAt:function(a,b){var c=this.getLastInstanceNode(a-1),d=this.templateElement_.parentNode;this.instances.splice(a,0,b),d.insertBefore(b,c.nextSibling)},extractInstanceAt:function(a){for(var b=this.getLastInstanceNode(a-1),c=this.getLastInstanceNode(a),d=this.templateElement_.parentNode,e=this.instances.splice(a,1)[0];c!==b;){var f=b.nextSibling;f==c&&(c=b),e.appendChild(d.removeChild(f))}return e},getDelegateFn:function(a){return a=a&&a(this.templateElement_),"function"==typeof a?a:null},handleSplices:function(a){if(!this.closed&&a.length){var b=this.templateElement_;if(!b.parentNode)return void this.close();ArrayObserver.applySplices(this.iteratedValue,this.presentValue,a);var c=b.delegate_;void 0===this.instanceModelFn_&&(this.instanceModelFn_=this.getDelegateFn(c&&c.prepareInstanceModel)),void 0===this.instancePositionChangedFn_&&(this.instancePositionChangedFn_=this.getDelegateFn(c&&c.prepareInstancePositionChanged));for(var d=new F,e=0,f=0;f<a.length;f++){for(var g=a[f],h=g.removed,i=0;i<h.length;i++){var j=h[i],k=this.extractInstanceAt(g.index+e);k!==T&&d.set(j,k)}e-=g.addedCount}for(var f=0;f<a.length;f++)for(var g=a[f],l=g.index;l<g.index+g.addedCount;l++){var j=this.iteratedValue[l],k=d.get(j);k?d.delete(j):(this.instanceModelFn_&&(j=this.instanceModelFn_(j)),k=void 0===j?T:b.createInstance(j,void 0,c)),this.insertInstanceAt(l,k)}d.forEach(function(a){this.closeInstanceBindings(a)},this),this.instancePositionChangedFn_&&this.reportInstancesMoved(a)}},reportInstanceMoved:function(a){var b=this.instances[a];b!==T&&this.instancePositionChangedFn_(b.templateInstance_,a)},reportInstancesMoved:function(a){for(var b=0,c=0,d=0;d<a.length;d++){var e=a[d];if(0!=c)for(;b<e.index;)this.reportInstanceMoved(b),b++;else b=e.index;for(;b<e.index+e.addedCount;)this.reportInstanceMoved(b),b++;c+=e.addedCount-e.removed.length}if(0!=c)for(var f=this.instances.length;f>b;)this.reportInstanceMoved(b),b++},closeInstanceBindings:function(a){for(var b=a.bindings_,c=0;c<b.length;c++)b[c].close()},unobserve:function(){this.arrayObserver&&(this.arrayObserver.close(),this.arrayObserver=void 0)},close:function(){if(!this.closed){this.unobserve();for(var a=0;a<this.instances.length;a++)this.closeInstanceBindings(this.instances[a]);this.instances.length=0,this.closeDeps(),this.templateElement_.iterator_=void 0,this.closed=!0}}},HTMLTemplateElement.forAllTemplatesFrom_=i}(this),function(a){function b(a){f.textContent=d++,e.push(a)}function c(){for(;e.length;)e.shift()()}var d=0,e=[],f=document.createTextNode("");new(window.MutationObserver||JsMutationObserver)(c).observe(f,{characterData:!0}),a.endOfMicrotask=b}(Platform),function(a){function b(){e||(e=!0,a.endOfMicrotask(function(){e=!1,logFlags.data&&console.group("Platform.flush()"),a.performMicrotaskCheckpoint(),logFlags.data&&console.groupEnd()}))}var c=document.createElement("style");c.textContent="template {display: none !important;} /* injected by platform.js */";var d=document.querySelector("head");d.insertBefore(c,d.firstChild);var e;if(Observer.hasObjectObserve)b=function(){};else{var f=125;window.addEventListener("WebComponentsReady",function(){b(),a.flushPoll=setInterval(b,f)})}if(window.CustomElements&&!CustomElements.useNative){var g=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=g.call(this,a,b);return CustomElements.upgradeAll(c),c}}a.flush=b}(window.Platform),function(a){function b(a,b,d,e){return a.replace(e,function(a,e,f,g){var h=f.replace(/["']/g,"");return h=c(b,h,d),e+"'"+h+"'"+g})}function c(a,b,c){if(b&&"/"===b[0])return b;var e=new URL(b,a);return c?e.href:d(e.href)}function d(a){var b=new URL(document.baseURI),c=new URL(a,b);return c.host===b.host&&c.port===b.port&&c.protocol===b.protocol?e(b,c):a}function e(a,b){for(var c=a.pathname,d=b.pathname,e=c.split("/"),f=d.split("/");e.length&&e[0]===f[0];)e.shift(),f.shift();for(var g=0,h=e.length-1;h>g;g++)f.unshift("..");return f.join("/")+b.search+b.hash}var f={resolveDom:function(a,b){b=b||a.ownerDocument.baseURI,this.resolveAttributes(a,b),this.resolveStyles(a,b);var c=a.querySelectorAll("template");if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)d.content&&this.resolveDom(d.content,b)},resolveTemplate:function(a){this.resolveDom(a.content,a.ownerDocument.baseURI)},resolveStyles:function(a,b){var c=a.querySelectorAll("style");if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)this.resolveStyle(d,b)},resolveStyle:function(a,b){b=b||a.ownerDocument.baseURI,a.textContent=this.resolveCssText(a.textContent,b)},resolveCssText:function(a,c,d){return a=b(a,c,d,g),b(a,c,d,h)},resolveAttributes:function(a,b){a.hasAttributes&&a.hasAttributes()&&this.resolveElementAttributes(a,b);var c=a&&a.querySelectorAll(j);if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)this.resolveElementAttributes(d,b)},resolveElementAttributes:function(a,d){d=d||a.ownerDocument.baseURI,i.forEach(function(e){var f,h=a.attributes[e],i=h&&h.value;i&&i.search(k)<0&&(f="style"===e?b(i,d,!1,g):c(d,i),h.value=f)})}},g=/(url\()([^)]*)(\))/g,h=/(@import[\s]+(?!url\())([^;]*)(;)/g,i=["href","src","action","style","url"],j="["+i.join("],[")+"]",k="{{.*}}";a.urlResolver=f}(Polymer),function(a){function b(a){this.cache=Object.create(null),this.map=Object.create(null),this.requests=0,this.regex=a}var c=Platform.endOfMicrotask;b.prototype={extractUrls:function(a,b){for(var c,d,e=[];c=this.regex.exec(a);)d=new URL(c[1],b),e.push({matched:c[0],url:d.href});return e},process:function(a,b,c){var d=this.extractUrls(a,b),e=c.bind(null,this.map);this.fetch(d,e)},fetch:function(a,b){var c=a.length;if(!c)return b();for(var d,e,f,g=function(){0===--c&&b()},h=0;c>h;h++)d=a[h],f=d.url,e=this.cache[f],e||(e=this.xhr(f),e.match=d,this.cache[f]=e),e.wait(g)},handleXhr:function(a){var b=a.match,c=b.url,d=a.response||a.responseText||"";this.map[c]=d,this.fetch(this.extractUrls(d,c),a.resolve)},xhr:function(a){this.requests++;var b=new XMLHttpRequest;return b.open("GET",a,!0),b.send(),b.onerror=b.onload=this.handleXhr.bind(this,b),b.pending=[],b.resolve=function(){for(var a=b.pending,c=0;c<a.length;c++)a[c]();b.pending=null},b.wait=function(a){b.pending?b.pending.push(a):c(a)},b}},a.Loader=b}(Polymer),function(a){function b(){this.loader=new d(this.regex)}var c=a.urlResolver,d=a.Loader;b.prototype={regex:/@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,resolve:function(a,b,c){var d=function(d){c(this.flatten(a,b,d))}.bind(this);this.loader.process(a,b,d)},resolveNode:function(a,b,c){var d=a.textContent,e=function(b){a.textContent=b,c(a)};this.resolve(d,b,e)},flatten:function(a,b,d){for(var e,f,g,h=this.loader.extractUrls(a,b),i=0;i<h.length;i++)e=h[i],f=e.url,g=c.resolveCssText(d[f],f,!0),g=this.flatten(g,b,d),a=a.replace(e.matched,g);return a},loadStyles:function(a,b,c){function d(){f++,f===g&&c&&c()}for(var e,f=0,g=a.length,h=0;g>h&&(e=a[h]);h++)this.resolveNode(e,b,d)}};var e=new b;a.styleResolver=e}(Polymer),function(a){function b(a,b){return a&&b&&Object.getOwnPropertyNames(b).forEach(function(c){var d=Object.getOwnPropertyDescriptor(b,c);d&&(Object.defineProperty(a,c,d),"function"==typeof d.value&&(d.value.nom=c))}),a}function c(a){for(var b=a||{},c=1;c<arguments.length;c++){var e=arguments[c];try{for(var f in e)d(f,e,b)}catch(g){}}return b}function d(a,b,c){var d=e(b,a);Object.defineProperty(c,a,d)}function e(a,b){if(a){var c=Object.getOwnPropertyDescriptor(a,b);return c||e(Object.getPrototypeOf(a),b)}}a.extend=b,a.mixin=c,Platform.mixin=c}(Polymer),function(a){function b(a,b,d){return a?a.stop():a=new c(this),a.go(b,d),a}var c=function(a){this.context=a,this.boundComplete=this.complete.bind(this)};c.prototype={go:function(a,b){this.callback=a;var c;b?(c=setTimeout(this.boundComplete,b),this.handle=function(){clearTimeout(c)}):(c=requestAnimationFrame(this.boundComplete),this.handle=function(){cancelAnimationFrame(c)})},stop:function(){this.handle&&(this.handle(),this.handle=null)},complete:function(){this.handle&&(this.stop(),this.callback.call(this.context))}},a.job=b}(Polymer),function(a){function b(a,b,c){var d="string"==typeof a?document.createElement(a):a.cloneNode(!0);if(d.innerHTML=b,c)for(var e in c)d.setAttribute(e,c[e]);return d}var c={};HTMLElement.register=function(a,b){c[a]=b},HTMLElement.getPrototypeForTag=function(a){var b=a?c[a]:HTMLElement.prototype;return b||Object.getPrototypeOf(document.createElement(a))};var d=Event.prototype.stopPropagation;Event.prototype.stopPropagation=function(){this.cancelBubble=!0,d.apply(this,arguments)};var e=DOMTokenList.prototype.add,f=DOMTokenList.prototype.remove;DOMTokenList.prototype.add=function(){for(var a=0;a<arguments.length;a++)e.call(this,arguments[a])},DOMTokenList.prototype.remove=function(){for(var a=0;a<arguments.length;a++)f.call(this,arguments[a])},DOMTokenList.prototype.toggle=function(a,b){1==arguments.length&&(b=!this.contains(a)),b?this.add(a):this.remove(a)},DOMTokenList.prototype.switch=function(a,b){a&&this.remove(a),b&&this.add(b)};var g=function(){return Array.prototype.slice.call(this)},h=window.NamedNodeMap||window.MozNamedAttrMap||{};NodeList.prototype.array=g,h.prototype.array=g,HTMLCollection.prototype.array=g,a.createDOM=b}(Polymer),function(a){function b(a){var e=b.caller,g=e.nom,h=e._super;h||(g||(g=e.nom=c.call(this,e)),g||console.warn("called super() on a method not installed declaratively (has no .nom property)"),h=d(e,g,f(this)));var i=h[g];return i?(i._super||d(i,g,h),i.apply(this,a||[])):void 0}function c(a){for(var b=this.__proto__;b&&b!==HTMLElement.prototype;){for(var c,d=Object.getOwnPropertyNames(b),e=0,f=d.length;f>e&&(c=d[e]);e++){var g=Object.getOwnPropertyDescriptor(b,c);if("function"==typeof g.value&&g.value===a)return c}b=b.__proto__}}function d(a,b,c){var d=e(c,b,a);return d[b]&&(d[b].nom=b),a._super=d}function e(a,b,c){for(;a;){if(a[b]!==c&&a[b])return a;a=f(a)}return Object}function f(a){return a.__proto__}a.super=b}(Polymer),function(a){function b(a){return a}function c(a,b){var c=typeof b;return b instanceof Date&&(c="date"),d[c](a,b)}var d={string:b,undefined:b,date:function(a){return new Date(Date.parse(a)||Date.now())},"boolean":function(a){return""===a?!0:"false"===a?!1:!!a},number:function(a){var b=parseFloat(a);return 0===b&&(b=parseInt(a)),isNaN(b)?a:b},object:function(a,b){if(null===b)return a;try{return JSON.parse(a.replace(/'/g,'"'))}catch(c){return a}},"function":function(a,b){return b}};a.deserializeValue=c}(Polymer),function(a){var b=a.extend,c={};c.declaration={},c.instance={},c.publish=function(a,c){for(var d in a)b(c,a[d])},a.api=c}(Polymer),function(a){var b={async:function(a,b,c){Platform.flush(),b=b&&b.length?b:[b];var d=function(){(this[a]||a).apply(this,b)}.bind(this),e=c?setTimeout(d,c):requestAnimationFrame(d);return c?e:~e},cancelAsync:function(a){0>a?cancelAnimationFrame(~a):clearTimeout(a)},fire:function(a,b,c,d,e){var f=c||this,b=null===b||void 0===b?{}:b,g=new CustomEvent(a,{bubbles:void 0!==d?d:!0,cancelable:void 0!==e?e:!0,detail:b});return f.dispatchEvent(g),g},asyncFire:function(){this.async("fire",arguments)},classFollows:function(a,b,c){b&&b.classList.remove(c),a&&a.classList.add(c)},injectBoundHTML:function(a,b){var c=document.createElement("template");c.innerHTML=a;var d=this.instanceTemplate(c);return b&&(b.textContent="",b.appendChild(d)),d}},c=function(){},d={};b.asyncMethod=b.async,a.api.instance.utils=b,a.nop=c,a.nob=d}(Polymer),function(a){var b=window.logFlags||{},c="on-",d={EVENT_PREFIX:c,addHostListeners:function(){var a=this.eventDelegates;b.events&&Object.keys(a).length>0&&console.log("[%s] addHostListeners:",this.localName,a);for(var c in a){var d=a[c];PolymerGestures.addEventListener(this,c,this.element.getEventHandler(this,this,d))}},dispatchMethod:function(a,c,d){if(a){b.events&&console.group("[%s] dispatch [%s]",a.localName,c);var e="function"==typeof c?c:a[c];e&&e[d?"apply":"call"](a,d),b.events&&console.groupEnd(),Platform.flush()}}};a.api.instance.events=d,a.addEventListener=function(a,b,c,d){PolymerGestures.addEventListener(wrap(a),b,c,d)},a.removeEventListener=function(a,b,c,d){PolymerGestures.removeEventListener(wrap(a),b,c,d)}}(Polymer),function(a){var b={copyInstanceAttributes:function(){var a=this._instanceAttributes;for(var b in a)this.hasAttribute(b)||this.setAttribute(b,a[b])},takeAttributes:function(){if(this._publishLC)for(var a,b=0,c=this.attributes,d=c.length;(a=c[b])&&d>b;b++)this.attributeToProperty(a.name,a.value)},attributeToProperty:function(b,c){var b=this.propertyForAttribute(b);if(b){if(c&&c.search(a.bindPattern)>=0)return;var d=this[b],c=this.deserializeValue(c,d);c!==d&&(this[b]=c)}},propertyForAttribute:function(a){var b=this._publishLC&&this._publishLC[a];return b},deserializeValue:function(b,c){return a.deserializeValue(b,c)},serializeValue:function(a,b){return"boolean"===b?a?"":void 0:"object"!==b&&"function"!==b&&void 0!==a?a:void 0},reflectPropertyToAttribute:function(a){var b=typeof this[a],c=this.serializeValue(this[a],b);void 0!==c?this.setAttribute(a,c):"boolean"===b&&this.removeAttribute(a)}};a.api.instance.attributes=b}(Polymer),function(a){function b(a,b){return a===b?0!==a||1/a===1/b:f(a)&&f(b)?!0:a!==a&&b!==b}function c(a,b){return void 0===b&&null===a?b:null===b||void 0===b?a:b}var d=window.logFlags||{},e={object:void 0,type:"update",name:void 0,oldValue:void 0},f=Number.isNaN||function(a){return"number"==typeof a&&isNaN(a)},g={createPropertyObserver:function(){var a=this._observeNames;if(a&&a.length){var b=this._propertyObserver=new CompoundObserver(!0);this.registerObserver(b);for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)b.addPath(this,c),this.observeArrayValue(c,this[c],null)}},openPropertyObserver:function(){this._propertyObserver&&this._propertyObserver.open(this.notifyPropertyChanges,this)},notifyPropertyChanges:function(a,b,c){var d,e,f={};for(var g in b)if(d=c[2*g+1],e=this.observe[d]){var h=b[g],i=a[g];this.observeArrayValue(d,i,h),f[e]||(void 0!==h&&null!==h||void 0!==i&&null!==i)&&(f[e]=!0,this.invokeMethod(e,[h,i,arguments]))}},deliverChanges:function(){this._propertyObserver&&this._propertyObserver.deliver()},propertyChanged_:function(a){this.reflect[a]&&this.reflectPropertyToAttribute(a)},observeArrayValue:function(a,b,c){var e=this.observe[a];if(e&&(Array.isArray(c)&&(d.observe&&console.log("[%s] observeArrayValue: unregister observer [%s]",this.localName,a),this.closeNamedObserver(a+"__array")),Array.isArray(b))){d.observe&&console.log("[%s] observeArrayValue: register observer [%s]",this.localName,a,b);var f=new ArrayObserver(b);f.open(function(a){this.invokeMethod(e,[a])},this),this.registerNamedObserver(a+"__array",f)}},emitPropertyChangeRecord:function(a,c,d){if(!b(c,d)&&(this.propertyChanged_(a,c,d),Observer.hasObjectObserve)){var f=this.notifier_;f||(f=this.notifier_=Object.getNotifier(this)),e.object=this,e.name=a,e.oldValue=d,f.notify(e)}},bindToAccessor:function(a,c,d){function e(b,c){j[f]=b;var d=j[h];d&&"function"==typeof d.setValue&&d.setValue(b),j.emitPropertyChangeRecord(a,b,c)}var f=a+"_",g=a+"Observable_",h=a+"ComputedBoundObservable_";this[g]=c;var i=this[f],j=this,k=c.open(e);if(d&&!b(i,k)){var l=d(i,k);b(k,l)||(k=l,c.setValue&&c.setValue(k))}e(k,i);var m={close:function(){c.close(),j[g]=void 0,j[h]=void 0}};return this.registerObserver(m),m},createComputedProperties:function(){if(this._computedNames)for(var a=0;a<this._computedNames.length;a++){var b=this._computedNames[a],c=this.computed[b];try{var d=PolymerExpressions.getExpression(c),e=d.getBinding(this,this.element.syntax);this.bindToAccessor(b,e)}catch(f){console.error("Failed to create computed property",f)}}},bindProperty:function(a,b,d){if(d)return void(this[a]=b);var e=this.element.prototype.computed;if(e&&e[a]){var f=a+"ComputedBoundObservable_";return void(this[f]=b)}return this.bindToAccessor(a,b,c)},invokeMethod:function(a,b){var c=this[a]||a;"function"==typeof c&&c.apply(this,b)},registerObserver:function(a){return this._observers?void this._observers.push(a):void(this._observers=[a])},closeObservers:function(){if(this._observers){for(var a=this._observers,b=0;b<a.length;b++){var c=a[b];c&&"function"==typeof c.close&&c.close()}this._observers=[]}},registerNamedObserver:function(a,b){var c=this._namedObservers||(this._namedObservers={});c[a]=b},closeNamedObserver:function(a){var b=this._namedObservers;return b&&b[a]?(b[a].close(),b[a]=null,!0):void 0},closeNamedObservers:function(){if(this._namedObservers){for(var a in this._namedObservers)this.closeNamedObserver(a);this._namedObservers={}}}};a.api.instance.properties=g}(Polymer),function(a){var b=window.logFlags||0,c={instanceTemplate:function(a){HTMLTemplateElement.decorate(a);for(var b=this.syntax||!a.bindingDelegate&&this.element.syntax,c=a.createInstance(this,b),d=c.bindings_,e=0;e<d.length;e++)this.registerObserver(d[e]);return c},bind:function(a,b,c){var d=this.propertyForAttribute(a);if(d){var e=this.bindProperty(d,b,c);return Platform.enableBindingsReflection&&e&&(e.path=b.path_,this._recordBinding(d,e)),this.reflect[d]&&this.reflectPropertyToAttribute(d),e}return this.mixinSuper(arguments)},bindFinished:function(){this.makeElementReady()},_recordBinding:function(a,b){this.bindings_=this.bindings_||{},this.bindings_[a]=b},asyncUnbindAll:function(){this._unbound||(b.unbind&&console.log("[%s] asyncUnbindAll",this.localName),this._unbindAllJob=this.job(this._unbindAllJob,this.unbindAll,0))},unbindAll:function(){this._unbound||(this.closeObservers(),this.closeNamedObservers(),this._unbound=!0)},cancelUnbindAll:function(){return this._unbound?void(b.unbind&&console.warn("[%s] already unbound, cannot cancel unbindAll",this.localName)):(b.unbind&&console.log("[%s] cancelUnbindAll",this.localName),void(this._unbindAllJob&&(this._unbindAllJob=this._unbindAllJob.stop())))}},d=/\{\{([^{}]*)}}/;a.bindPattern=d,a.api.instance.mdv=c}(Polymer),function(a){function b(a){return a.hasOwnProperty("PolymerBase")}function c(){}var d={PolymerBase:!0,job:function(a,b,c){if("string"!=typeof a)return Polymer.job.call(this,a,b,c);var d="___"+a;this[d]=Polymer.job.call(this,this[d],b,c)},"super":Polymer.super,created:function(){},ready:function(){},createdCallback:function(){this.templateInstance&&this.templateInstance.model&&console.warn("Attributes on "+this.localName+" were data bound prior to Polymer upgrading the element. This may result in incorrect binding types."),this.created(),this.prepareElement(),this.ownerDocument.isStagingDocument||this.makeElementReady()},prepareElement:function(){return this._elementPrepared?void console.warn("Element already prepared",this.localName):(this._elementPrepared=!0,this.shadowRoots={},this.createPropertyObserver(),this.openPropertyObserver(),this.copyInstanceAttributes(),this.takeAttributes(),void this.addHostListeners())},makeElementReady:function(){this._readied||(this._readied=!0,this.createComputedProperties(),this.parseDeclarations(this.__proto__),this.removeAttribute("unresolved"),this.ready())},attachedCallback:function(){this.cancelUnbindAll(),this.attached&&this.attached(),this.enteredView&&this.enteredView(),this.hasBeenAttached||(this.hasBeenAttached=!0,this.domReady&&this.async("domReady"))},detachedCallback:function(){this.preventDispose||this.asyncUnbindAll(),this.detached&&this.detached(),this.leftView&&this.leftView()},enteredViewCallback:function(){this.attachedCallback()},leftViewCallback:function(){this.detachedCallback()},enteredDocumentCallback:function(){this.attachedCallback()},leftDocumentCallback:function(){this.detachedCallback()},parseDeclarations:function(a){a&&a.element&&(this.parseDeclarations(a.__proto__),a.parseDeclaration.call(this,a.element))},parseDeclaration:function(a){var b=this.fetchTemplate(a);if(b){var c=this.shadowFromTemplate(b);this.shadowRoots[a.name]=c}},fetchTemplate:function(a){return a.querySelector("template")},shadowFromTemplate:function(a){if(a){var b=this.createShadowRoot(),c=this.instanceTemplate(a);return b.appendChild(c),this.shadowRootReady(b,a),b}},lightFromTemplate:function(a,b){if(a){this.eventController=this;var c=this.instanceTemplate(a);return b?this.insertBefore(c,b):this.appendChild(c),this.shadowRootReady(this),c}},shadowRootReady:function(a){this.marshalNodeReferences(a)},marshalNodeReferences:function(a){var b=this.$=this.$||{};if(a)for(var c,d=a.querySelectorAll("[id]"),e=0,f=d.length;f>e&&(c=d[e]);e++)b[c.id]=c},attributeChangedCallback:function(a){"class"!==a&&"style"!==a&&this.attributeToProperty(a,this.getAttribute(a)),this.attributeChanged&&this.attributeChanged.apply(this,arguments)},onMutation:function(a,b){var c=new MutationObserver(function(a){b.call(this,c,a),c.disconnect()}.bind(this));c.observe(a,{childList:!0,subtree:!0})}};c.prototype=d,d.constructor=c,a.Base=c,a.isBase=b,a.api.instance.base=d}(Polymer),function(a){function b(a){return a.__proto__}function c(a,b){var c="",d=!1;b&&(c=b.localName,d=b.hasAttribute("is"));var e=Platform.ShadowCSS.makeScopeSelector(c,d);return Platform.ShadowCSS.shimCssText(a,e)}var d=(window.logFlags||{},window.ShadowDOMPolyfill),e="element",f="controller",g={STYLE_SCOPE_ATTRIBUTE:e,installControllerStyles:function(){var a=this.findStyleScope();if(a&&!this.scopeHasNamedStyle(a,this.localName)){for(var c=b(this),d="";c&&c.element;)d+=c.element.cssTextForScope(f),c=b(c);d&&this.installScopeCssText(d,a)}},installScopeStyle:function(a,b,c){var c=c||this.findStyleScope(),b=b||"";if(c&&!this.scopeHasNamedStyle(c,this.localName+b)){var d="";if(a instanceof Array)for(var e,f=0,g=a.length;g>f&&(e=a[f]);f++)d+=e.textContent+"\n\n";else d=a.textContent;this.installScopeCssText(d,c,b)}},installScopeCssText:function(a,b,e){if(b=b||this.findStyleScope(),e=e||"",b){d&&(a=c(a,b.host));var g=this.element.cssTextToScopeStyle(a,f);Polymer.applyStyleToScope(g,b),this.styleCacheForScope(b)[this.localName+e]=!0}},findStyleScope:function(a){for(var b=a||this;b.parentNode;)b=b.parentNode;return b},scopeHasNamedStyle:function(a,b){var c=this.styleCacheForScope(a);
|
||
return c[b]},styleCacheForScope:function(a){if(d){var b=a.host?a.host.localName:a.localName;return h[b]||(h[b]={})}return a._scopeStyles=a._scopeStyles||{}}},h={};a.api.instance.styles=g}(Polymer),function(a){function b(a,b){if("string"!=typeof a){var c=b||document._currentScript;if(b=a,a=c&&c.parentNode&&c.parentNode.getAttribute?c.parentNode.getAttribute("name"):"",!a)throw"Element name could not be inferred."}if(f(a))throw"Already registered (Polymer) prototype for element "+a;e(a,b),d(a)}function c(a,b){i[a]=b}function d(a){i[a]&&(i[a].registerWhenReady(),delete i[a])}function e(a,b){return j[a]=b||{}}function f(a){return j[a]}function g(a,b){if("string"!=typeof b)return!1;var c=HTMLElement.getPrototypeForTag(b),d=c&&c.constructor;return d?CustomElements.instanceof?CustomElements.instanceof(a,d):a instanceof d:!1}var h=a.extend,i=(a.api,{}),j={};a.getRegisteredPrototype=f,a.waitingForPrototype=c,a.instanceOfType=g,window.Polymer=b,h(Polymer,a),Platform.consumeDeclarations&&Platform.consumeDeclarations(function(a){if(a)for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)b.apply(null,c)})}(Polymer),function(a){var b={resolveElementPaths:function(a){Polymer.urlResolver.resolveDom(a)},addResolvePathApi:function(){var a=this.getAttribute("assetpath")||"",b=new URL(a,this.ownerDocument.baseURI);this.prototype.resolvePath=function(a,c){var d=new URL(a,c||b);return d.href}}};a.api.declaration.path=b}(Polymer),function(a){function b(a,b){var c=new URL(a.getAttribute("href"),b).href;return"@import '"+c+"';"}function c(a,b){if(a){b===document&&(b=document.head),i&&(b=document.head);var c=d(a.textContent),e=a.getAttribute(h);e&&c.setAttribute(h,e);var f=b.firstElementChild;if(b===document.head){var g="style["+h+"]",j=document.head.querySelectorAll(g);j.length&&(f=j[j.length-1].nextElementSibling)}b.insertBefore(c,f)}}function d(a,b){b=b||document,b=b.createElement?b:b.ownerDocument;var c=b.createElement("style");return c.textContent=a,c}function e(a){return a&&a.__resource||""}function f(a,b){return q?q.call(a,b):void 0}var g=(window.logFlags||{},a.api.instance.styles),h=g.STYLE_SCOPE_ATTRIBUTE,i=window.ShadowDOMPolyfill,j="style",k="@import",l="link[rel=stylesheet]",m="global",n="polymer-scope",o={loadStyles:function(a){var b=this.fetchTemplate(),c=b&&this.templateContent();if(c){this.convertSheetsToStyles(c);var d=this.findLoadableStyles(c);if(d.length){var e=b.ownerDocument.baseURI;return Polymer.styleResolver.loadStyles(d,e,a)}}a&&a()},convertSheetsToStyles:function(a){for(var c,e,f=a.querySelectorAll(l),g=0,h=f.length;h>g&&(c=f[g]);g++)e=d(b(c,this.ownerDocument.baseURI),this.ownerDocument),this.copySheetAttributes(e,c),c.parentNode.replaceChild(e,c)},copySheetAttributes:function(a,b){for(var c,d=0,e=b.attributes,f=e.length;(c=e[d])&&f>d;d++)"rel"!==c.name&&"href"!==c.name&&a.setAttribute(c.name,c.value)},findLoadableStyles:function(a){var b=[];if(a)for(var c,d=a.querySelectorAll(j),e=0,f=d.length;f>e&&(c=d[e]);e++)c.textContent.match(k)&&b.push(c);return b},installSheets:function(){this.cacheSheets(),this.cacheStyles(),this.installLocalSheets(),this.installGlobalStyles()},cacheSheets:function(){this.sheets=this.findNodes(l),this.sheets.forEach(function(a){a.parentNode&&a.parentNode.removeChild(a)})},cacheStyles:function(){this.styles=this.findNodes(j+"["+n+"]"),this.styles.forEach(function(a){a.parentNode&&a.parentNode.removeChild(a)})},installLocalSheets:function(){var a=this.sheets.filter(function(a){return!a.hasAttribute(n)}),b=this.templateContent();if(b){var c="";if(a.forEach(function(a){c+=e(a)+"\n"}),c){var f=d(c,this.ownerDocument);b.insertBefore(f,b.firstChild)}}},findNodes:function(a,b){var c=this.querySelectorAll(a).array(),d=this.templateContent();if(d){var e=d.querySelectorAll(a).array();c=c.concat(e)}return b?c.filter(b):c},installGlobalStyles:function(){var a=this.styleForScope(m);c(a,document.head)},cssTextForScope:function(a){var b="",c="["+n+"="+a+"]",d=function(a){return f(a,c)},g=this.sheets.filter(d);g.forEach(function(a){b+=e(a)+"\n\n"});var h=this.styles.filter(d);return h.forEach(function(a){b+=a.textContent+"\n\n"}),b},styleForScope:function(a){var b=this.cssTextForScope(a);return this.cssTextToScopeStyle(b,a)},cssTextToScopeStyle:function(a,b){if(a){var c=d(a);return c.setAttribute(h,this.getAttribute("name")+"-"+b),c}}},p=HTMLElement.prototype,q=p.matches||p.matchesSelector||p.webkitMatchesSelector||p.mozMatchesSelector;a.api.declaration.styles=o,a.applyStyleToScope=c}(Polymer),function(a){var b=(window.logFlags||{},a.api.instance.events),c=b.EVENT_PREFIX,d={};["webkitAnimationStart","webkitAnimationEnd","webkitTransitionEnd","DOMFocusOut","DOMFocusIn","DOMMouseScroll"].forEach(function(a){d[a.toLowerCase()]=a});var e={parseHostEvents:function(){var a=this.prototype.eventDelegates;this.addAttributeDelegates(a)},addAttributeDelegates:function(a){for(var b,c=0;b=this.attributes[c];c++)this.hasEventPrefix(b.name)&&(a[this.removeEventPrefix(b.name)]=b.value.replace("{{","").replace("}}","").trim())},hasEventPrefix:function(a){return a&&"o"===a[0]&&"n"===a[1]&&"-"===a[2]},removeEventPrefix:function(a){return a.slice(f)},findController:function(a){for(;a.parentNode;){if(a.eventController)return a.eventController;a=a.parentNode}return a.host},getEventHandler:function(a,b,c){var d=this;return function(e){a&&a.PolymerBase||(a=d.findController(b));var f=[e,e.detail,e.currentTarget];a.dispatchMethod(a,c,f)}},prepareEventBinding:function(a,b){if(this.hasEventPrefix(b)){var c=this.removeEventPrefix(b);c=d[c]||c;var e=this;return function(b,d,f){function g(){return"{{ "+a+" }}"}var h=e.getEventHandler(void 0,d,a);return PolymerGestures.addEventListener(d,c,h),f?void 0:{open:g,discardChanges:g,close:function(){PolymerGestures.removeEventListener(d,c,h)}}}}}},f=c.length;a.api.declaration.events=e}(Polymer),function(a){var b={inferObservers:function(a){var b,c=a.observe;for(var d in a)"Changed"===d.slice(-7)&&(c||(c=a.observe={}),b=d.slice(0,-7),c[b]=c[b]||d)},explodeObservers:function(a){var b=a.observe;if(b){var c={};for(var d in b)for(var e,f=d.split(" "),g=0;e=f[g];g++)c[e]=b[d];a.observe=c}},optimizePropertyMaps:function(a){if(a.observe){var b=a._observeNames=[];for(var c in a.observe)for(var d,e=c.split(" "),f=0;d=e[f];f++)b.push(d)}if(a.publish){var b=a._publishNames=[];for(var c in a.publish)b.push(c)}if(a.computed){var b=a._computedNames=[];for(var c in a.computed)b.push(c)}},publishProperties:function(a,b){var c=a.publish;c&&(this.requireProperties(c,a,b),a._publishLC=this.lowerCaseMap(c))},requireProperties:function(a,b){b.reflect=b.reflect||{};for(var c in a){var d=a[c];d&&void 0!==d.reflect&&(b.reflect[c]=Boolean(d.reflect),d=d.value),void 0!==d&&(b[c]=d)}},lowerCaseMap:function(a){var b={};for(var c in a)b[c.toLowerCase()]=c;return b},createPropertyAccessor:function(a,b){var c=this.prototype,d=a+"_",e=a+"Observable_";c[d]=c[a],Object.defineProperty(c,a,{get:function(){var a=this[e];return a&&a.deliver(),this[d]},set:function(c){if(b)return this[d];var f=this[e];if(f)return void f.setValue(c);var g=this[d];return this[d]=c,this.emitPropertyChangeRecord(a,c,g),c},configurable:!0})},createPropertyAccessors:function(a){var b=a._computedNames;if(b&&b.length)for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)this.createPropertyAccessor(c,!0);var b=a._publishNames;if(b&&b.length)for(var c,d=0,e=b.length;e>d&&(c=b[d]);d++)a.computed&&a.computed[c]||this.createPropertyAccessor(c)}};a.api.declaration.properties=b}(Polymer),function(a){var b="attributes",c=/\s|,/,d={inheritAttributesObjects:function(a){this.inheritObject(a,"publishLC"),this.inheritObject(a,"_instanceAttributes")},publishAttributes:function(a){var d=this.getAttribute(b);if(d)for(var e,f=a.publish||(a.publish={}),g=d.split(c),h=0,i=g.length;i>h;h++)e=g[h].trim(),e&&void 0===f[e]&&(f[e]=void 0)},accumulateInstanceAttributes:function(){for(var a,b=this.prototype._instanceAttributes,c=this.attributes,d=0,e=c.length;e>d&&(a=c[d]);d++)this.isInstanceAttribute(a.name)&&(b[a.name]=a.value)},isInstanceAttribute:function(a){return!this.blackList[a]&&"on-"!==a.slice(0,3)},blackList:{name:1,"extends":1,constructor:1,noscript:1,assetpath:1,"cache-csstext":1}};d.blackList[b]=1,a.api.declaration.attributes=d}(Polymer),function(a){var b=a.api.declaration.events,c=new PolymerExpressions,d=c.prepareBinding;c.prepareBinding=function(a,e,f){return b.prepareEventBinding(a,e,f)||d.call(c,a,e,f)};var e={syntax:c,fetchTemplate:function(){return this.querySelector("template")},templateContent:function(){var a=this.fetchTemplate();return a&&a.content},installBindingDelegate:function(a){a&&(a.bindingDelegate=this.syntax)}};a.api.declaration.mdv=e}(Polymer),function(a){function b(a){if(!Object.__proto__){var b=Object.getPrototypeOf(a);a.__proto__=b,d(b)&&(b.__proto__=Object.getPrototypeOf(b))}}var c=a.api,d=a.isBase,e=a.extend,f=window.ShadowDOMPolyfill,g={register:function(a,b){this.buildPrototype(a,b),this.registerPrototype(a,b),this.publishConstructor()},buildPrototype:function(b,c){var d=a.getRegisteredPrototype(b),e=this.generateBasePrototype(c);this.desugarBeforeChaining(d,e),this.prototype=this.chainPrototypes(d,e),this.desugarAfterChaining(b,c)},desugarBeforeChaining:function(a,b){a.element=this,this.publishAttributes(a,b),this.publishProperties(a,b),this.inferObservers(a),this.explodeObservers(a)},chainPrototypes:function(a,c){this.inheritMetaData(a,c);var d=this.chainObject(a,c);return b(d),d},inheritMetaData:function(a,b){this.inheritObject("observe",a,b),this.inheritObject("publish",a,b),this.inheritObject("reflect",a,b),this.inheritObject("_publishLC",a,b),this.inheritObject("_instanceAttributes",a,b),this.inheritObject("eventDelegates",a,b)},desugarAfterChaining:function(a,b){this.optimizePropertyMaps(this.prototype),this.createPropertyAccessors(this.prototype),this.installBindingDelegate(this.fetchTemplate()),this.installSheets(),this.resolveElementPaths(this),this.accumulateInstanceAttributes(),this.parseHostEvents(),this.addResolvePathApi(),f&&Platform.ShadowCSS.shimStyling(this.templateContent(),a,b),this.prototype.registerCallback&&this.prototype.registerCallback(this)},publishConstructor:function(){var a=this.getAttribute("constructor");a&&(window[a]=this.ctor)},generateBasePrototype:function(a){var b=this.findBasePrototype(a);if(!b){var b=HTMLElement.getPrototypeForTag(a);b=this.ensureBaseApi(b),h[a]=b}return b},findBasePrototype:function(a){return h[a]},ensureBaseApi:function(a){if(a.PolymerBase)return a;var b=Object.create(a);return c.publish(c.instance,b),this.mixinMethod(b,a,c.instance.mdv,"bind"),b},mixinMethod:function(a,b,c,d){var e=function(a){return b[d].apply(this,a)};a[d]=function(){return this.mixinSuper=e,c[d].apply(this,arguments)}},inheritObject:function(a,b,c){var d=b[a]||{};b[a]=this.chainObject(d,c[a])},registerPrototype:function(a,b){var c={prototype:this.prototype},d=this.findTypeExtension(b);d&&(c.extends=d),HTMLElement.register(a,this.prototype),this.ctor=document.registerElement(a,c)},findTypeExtension:function(a){if(a&&a.indexOf("-")<0)return a;var b=this.findBasePrototype(a);return b.element?this.findTypeExtension(b.element.extends):void 0}},h={};g.chainObject=Object.__proto__?function(a,b){return a&&b&&a!==b&&(a.__proto__=b),a}:function(a,b){if(a&&b&&a!==b){var c=Object.create(b);a=e(c,a)}return a},c.declaration.prototype=g}(Polymer),function(a){function b(a){return document.contains(a)?j:i}function c(){return i.length?i[0]:j[0]}function d(a){f.waitToReady=!0,Platform.endOfMicrotask(function(){HTMLImports.whenReady(function(){f.addReadyCallback(a),f.waitToReady=!1,f.check()})})}function e(a){if(void 0===a)return void f.ready();var b=setTimeout(function(){f.ready()},a);Polymer.whenReady(function(){clearTimeout(b)})}var f={wait:function(a){a.__queue||(a.__queue={},g.push(a))},enqueue:function(a,c,d){var e=a.__queue&&!a.__queue.check;return e&&(b(a).push(a),a.__queue.check=c,a.__queue.go=d),0!==this.indexOf(a)},indexOf:function(a){var c=b(a).indexOf(a);return c>=0&&document.contains(a)&&(c+=HTMLImports.useNative||HTMLImports.ready?i.length:1e9),c},go:function(a){var b=this.remove(a);b&&(a.__queue.flushable=!0,this.addToFlushQueue(b),this.check())},remove:function(a){var c=this.indexOf(a);if(0===c)return b(a).shift()},check:function(){var a=this.nextElement();return a&&a.__queue.check.call(a),this.canReady()?(this.ready(),!0):void 0},nextElement:function(){return c()},canReady:function(){return!this.waitToReady&&this.isEmpty()},isEmpty:function(){for(var a,b=0,c=g.length;c>b&&(a=g[b]);b++)if(a.__queue&&!a.__queue.flushable)return;return!0},addToFlushQueue:function(a){h.push(a)},flush:function(){if(!this.flushing){this.flushing=!0;for(var a;h.length;)a=h.shift(),a.__queue.go.call(a),a.__queue=null;this.flushing=!1}},ready:function(){var a=CustomElements.ready;CustomElements.ready=!1,this.flush(),CustomElements.useNative||CustomElements.upgradeDocumentTree(document),CustomElements.ready=a,Platform.flush(),requestAnimationFrame(this.flushReadyCallbacks)},addReadyCallback:function(a){a&&k.push(a)},flushReadyCallbacks:function(){if(k)for(var a;k.length;)(a=k.shift())()},waitingFor:function(){for(var a,b=[],c=0,d=g.length;d>c&&(a=g[c]);c++)a.__queue&&!a.__queue.flushable&&b.push(a);return b},waitToReady:!0},g=[],h=[],i=[],j=[],k=[];a.elements=g,a.waitingFor=f.waitingFor.bind(f),a.forceReady=e,a.queue=f,a.whenReady=a.whenPolymerReady=d}(Polymer),function(a){function b(a){return Boolean(HTMLElement.getPrototypeForTag(a))}function c(a){return a&&a.indexOf("-")>=0}var d=a.extend,e=a.api,f=a.queue,g=a.whenReady,h=a.getRegisteredPrototype,i=a.waitingForPrototype,j=d(Object.create(HTMLElement.prototype),{createdCallback:function(){this.getAttribute("name")&&this.init()},init:function(){this.name=this.getAttribute("name"),this.extends=this.getAttribute("extends"),f.wait(this),this.loadResources(),this.registerWhenReady()},registerWhenReady:function(){this.registered||this.waitingForPrototype(this.name)||this.waitingForQueue()||this.waitingForResources()||f.go(this)},_register:function(){c(this.extends)&&!b(this.extends)&&console.warn("%s is attempting to extend %s, an unregistered element or one that was not registered with Polymer.",this.name,this.extends),this.register(this.name,this.extends),this.registered=!0},waitingForPrototype:function(a){return h(a)?void 0:(i(a,this),this.handleNoScript(a),!0)},handleNoScript:function(a){this.hasAttribute("noscript")&&!this.noscript&&(this.noscript=!0,Polymer(a))},waitingForResources:function(){return this._needsResources},waitingForQueue:function(){return f.enqueue(this,this.registerWhenReady,this._register)},loadResources:function(){this._needsResources=!0,this.loadStyles(function(){this._needsResources=!1,this.registerWhenReady()}.bind(this))}});e.publish(e.declaration,j),g(function(){document.body.removeAttribute("unresolved"),document.dispatchEvent(new CustomEvent("polymer-ready",{bubbles:!0}))}),document.registerElement("polymer-element",{prototype:j})}(Polymer),function(a){function b(a,b){a?(document.head.appendChild(a),d(b)):b&&b()}function c(a,c){if(a&&a.length){for(var d,e,f=document.createDocumentFragment(),g=0,h=a.length;h>g&&(d=a[g]);g++)e=document.createElement("link"),e.rel="import",e.href=d,f.appendChild(e);b(f,c)}else c&&c()}var d=a.whenPolymerReady;a.import=c,a.importElements=b}(Polymer),function(){var a=document.createElement("polymer-element");a.setAttribute("name","auto-binding"),a.setAttribute("extends","template"),a.init(),Polymer("auto-binding",{createdCallback:function(){this.syntax=this.bindingDelegate=this.makeSyntax(),Polymer.whenPolymerReady(function(){this.model=this,this.setAttribute("bind",""),this.async(function(){this.marshalNodeReferences(this.parentNode),this.fire("template-bound")})}.bind(this))},makeSyntax:function(){var a=Object.create(Polymer.api.declaration.events),b=this;a.findController=function(){return b.model};var c=new PolymerExpressions,d=c.prepareBinding;return c.prepareBinding=function(b,e,f){return a.prepareEventBinding(b,e,f)||d.call(c,b,e,f)},c}})}();
|
||
//# sourceMappingURL=polymer.js.map</script>
|
||
<!--<link rel="import" href="../polymer-dev/polymer.html">-->
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<!--
|
||
|
||
The `core-icon` element displays an icon. By default an icon renders as a 24px square.
|
||
|
||
Example using src:
|
||
|
||
<core-icon src="star.png"></core-icon>
|
||
|
||
Example setting size to 32px x 32px:
|
||
|
||
<core-icon class="big" src="big_star.png"></core-icon>
|
||
|
||
<style>
|
||
.big {
|
||
height: 32px;
|
||
width: 32px;
|
||
}
|
||
</style>
|
||
|
||
The core elements include several sets of icons.
|
||
To use the default set of icons, import `core-icons.html` and use the `icon` attribute to specify an icon:
|
||
|
||
<!-- import default iconset and core-icon -->
|
||
<link rel="import" href="/components/core-icons/core-icons.html">
|
||
|
||
<core-icon icon="menu"></core-icon>
|
||
|
||
To use a different built-in set of icons, import `core-icons/<iconset>-icons.html`, and
|
||
specify the icon as `<iconset>:<icon>`. For example:
|
||
|
||
<!-- import communication iconset and core-icon -->
|
||
<link rel="import" href="/components/core-icons/communication-icons.html">
|
||
|
||
<core-icon icon="communication:email"></core-icon>
|
||
|
||
You can also create custom icon sets of bitmap or SVG icons.
|
||
|
||
Example of using an icon named `cherry` from a custom iconset with the ID `fruit`:
|
||
|
||
<core-icon icon="fruit:cherry"></core-icon>
|
||
|
||
See [core-iconset](#core-iconset) and [core-iconset-svg](#core-iconset-svg) for more information about
|
||
how to create a custom iconset.
|
||
|
||
See [core-icons](http://www.polymer-project.org/components/core-icons/demo.html) for the default set of icons.
|
||
|
||
@group Polymer Core Elements
|
||
@element core-icon
|
||
@homepage polymer.github.io
|
||
-->
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
/**
|
||
* @group Polymer Core Elements
|
||
*
|
||
* The `core-iconset` element allows users to define their own icon sets.
|
||
* The `src` property specifies the url of the icon image. Multiple icons may
|
||
* be included in this image and they may be organized into rows.
|
||
* The `icons` property is a space separated list of names corresponding to the
|
||
* icons. The names must be ordered as the icons are ordered in the icon image.
|
||
* Icons are expected to be square and are the size specified by the `iconSize`
|
||
* property. The `width` property corresponds to the width of the icon image
|
||
* and must be specified if icons are arranged into multiple rows in the image.
|
||
*
|
||
* All `core-iconset` elements are available for use by other `core-iconset`
|
||
* elements via a database keyed by id. Typically, an element author that wants
|
||
* to support a set of custom icons uses a `core-iconset` to retrieve
|
||
* and use another, user-defined iconset.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-iconset id="my-icons" src="my-icons.png" width="96" iconSize="24"
|
||
* icons="location place starta stopb bus car train walk">
|
||
* </core-iconset>
|
||
*
|
||
* This will automatically register the icon set "my-icons" to the iconset
|
||
* database. To use these icons from within another element, make a
|
||
* `core-iconset` element and call the `byId` method to retrieve a
|
||
* given iconset. To apply a particular icon to an element, use the
|
||
* `applyIcon` method. For example:
|
||
*
|
||
* iconset.applyIcon(iconNode, 'car');
|
||
*
|
||
* Themed icon sets are also supported. The `core-iconset` can contain child
|
||
* `property` elements that specify a theme with an offsetX and offsetY of the
|
||
* theme within the icon resource. For example.
|
||
*
|
||
* <core-iconset id="my-icons" src="my-icons.png" width="96" iconSize="24"
|
||
* icons="location place starta stopb bus car train walk">
|
||
* <property theme="special" offsetX="256" offsetY="24"></property>
|
||
* </core-iconset>
|
||
*
|
||
* Then a themed icon can be applied like this:
|
||
*
|
||
* iconset.applyIcon(iconNode, 'car', 'special');
|
||
*
|
||
* @element core-iconset
|
||
* @extends core-meta
|
||
* @homepage github.io
|
||
*/
|
||
-->
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`core-meta` provides a method of constructing a self-organizing database.
|
||
It is useful to collate element meta-data for things like catalogs and for
|
||
designer.
|
||
|
||
Example, an element folder has a `metadata.html` file in it, that contains a
|
||
`core-meta`, something like this:
|
||
|
||
<core-meta id="my-element" label="My Element">
|
||
<property name="color" value="blue"></property>
|
||
</core-meta>
|
||
|
||
An application can import as many of these files as it wants, and then use
|
||
`core-meta` again to access the collected data.
|
||
|
||
<script>
|
||
var meta = document.createElement('core-meta');
|
||
console.log(meta.list); // dump a list of all meta-data elements that have been created
|
||
</script>
|
||
|
||
Use `byId(id)` to retrive a specific core-meta.
|
||
|
||
<script>
|
||
var meta = document.createElement('core-meta');
|
||
console.log(meta.byId('my-element'));
|
||
</script>
|
||
|
||
By default all meta-data are stored in a single databse. If your meta-data
|
||
have different types and want them to be stored separately, use `type` to
|
||
differentiate them.
|
||
|
||
Example:
|
||
|
||
<core-meta id="x-foo" type="xElt"></core-meta>
|
||
<core-meta id="x-bar" type="xElt"></core-meta>
|
||
<core-meta id="y-bar" type="yElt"></core-meta>
|
||
|
||
<script>
|
||
var meta = document.createElement('core-meta');
|
||
meta.type = 'xElt';
|
||
console.log(meta.list);
|
||
</script>
|
||
|
||
@group Polymer Core Elements
|
||
@element core-meta
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-meta" attributes="label type" hidden assetpath="polymer/bower_components/core-meta/">
|
||
<script>
|
||
|
||
(function() {
|
||
|
||
var SKIP_ID = 'meta';
|
||
var metaData = {}, metaArray = {};
|
||
|
||
Polymer('core-meta', {
|
||
|
||
/**
|
||
* The type of meta-data. All meta-data with the same type with be
|
||
* stored together.
|
||
*
|
||
* @attribute type
|
||
* @type string
|
||
* @default 'default'
|
||
*/
|
||
type: 'default',
|
||
|
||
alwaysPrepare: true,
|
||
|
||
ready: function() {
|
||
this.register(this.id);
|
||
},
|
||
|
||
get metaArray() {
|
||
var t = this.type;
|
||
if (!metaArray[t]) {
|
||
metaArray[t] = [];
|
||
}
|
||
return metaArray[t];
|
||
},
|
||
|
||
get metaData() {
|
||
var t = this.type;
|
||
if (!metaData[t]) {
|
||
metaData[t] = {};
|
||
}
|
||
return metaData[t];
|
||
},
|
||
|
||
register: function(id, old) {
|
||
if (id && id !== SKIP_ID) {
|
||
this.unregister(this, old);
|
||
this.metaData[id] = this;
|
||
this.metaArray.push(this);
|
||
}
|
||
},
|
||
|
||
unregister: function(meta, id) {
|
||
delete this.metaData[id || meta.id];
|
||
var i = this.metaArray.indexOf(meta);
|
||
if (i >= 0) {
|
||
this.metaArray.splice(i, 1);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Returns a list of all meta-data elements with the same type.
|
||
*
|
||
* @property list
|
||
* @type array
|
||
* @default []
|
||
*/
|
||
get list() {
|
||
return this.metaArray;
|
||
},
|
||
|
||
/**
|
||
* Retrieves meta-data by ID.
|
||
*
|
||
* @method byId
|
||
* @param {String} id The ID of the meta-data to be returned.
|
||
* @returns Returns meta-data.
|
||
*/
|
||
byId: function(id) {
|
||
return this.metaData[id];
|
||
}
|
||
|
||
});
|
||
|
||
})();
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="core-iconset" extends="core-meta" attributes="src width icons iconSize" assetpath="polymer/bower_components/core-iconset/">
|
||
|
||
<script>
|
||
|
||
Polymer('core-iconset', {
|
||
|
||
/**
|
||
* The URL of the iconset image.
|
||
*
|
||
* @attribute src
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
src: '',
|
||
|
||
/**
|
||
* The width of the iconset image. This must only be specified if the
|
||
* icons are arranged into separate rows inside the image.
|
||
*
|
||
* @attribute width
|
||
* @type number
|
||
* @default 0
|
||
*/
|
||
width: 0,
|
||
|
||
/**
|
||
* A space separated list of names corresponding to icons in the iconset
|
||
* image file. This list must be ordered the same as the icon images
|
||
* in the image file.
|
||
*
|
||
* @attribute icons
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
icons: '',
|
||
|
||
/**
|
||
* The size of an individual icon. Note that icons must be square.
|
||
*
|
||
* @attribute iconSize
|
||
* @type number
|
||
* @default 24
|
||
*/
|
||
iconSize: 24,
|
||
|
||
/**
|
||
* The horizontal offset of the icon images in the inconset src image.
|
||
* This is typically used if the image resource contains additional images
|
||
* beside those intended for the iconset.
|
||
*
|
||
* @attribute offsetX
|
||
* @type number
|
||
* @default 0
|
||
*/
|
||
offsetX: 0,
|
||
/**
|
||
* The vertical offset of the icon images in the inconset src image.
|
||
* This is typically used if the image resource contains additional images
|
||
* beside those intended for the iconset.
|
||
*
|
||
* @attribute offsetY
|
||
* @type number
|
||
* @default 0
|
||
*/
|
||
offsetY: 0,
|
||
type: 'iconset',
|
||
|
||
created: function() {
|
||
this.iconMap = {};
|
||
this.iconNames = [];
|
||
this.themes = {};
|
||
},
|
||
|
||
ready: function() {
|
||
// TODO(sorvell): ensure iconset's src is always relative to the main
|
||
// document
|
||
if (this.src && (this.ownerDocument !== document)) {
|
||
this.src = this.resolvePath(this.src, this.ownerDocument.baseURI);
|
||
}
|
||
this.super();
|
||
this.updateThemes();
|
||
},
|
||
|
||
iconsChanged: function() {
|
||
var ox = this.offsetX;
|
||
var oy = this.offsetY;
|
||
this.icons && this.icons.split(/\s+/g).forEach(function(name, i) {
|
||
this.iconNames.push(name);
|
||
this.iconMap[name] = {
|
||
offsetX: ox,
|
||
offsetY: oy
|
||
}
|
||
if (ox + this.iconSize < this.width) {
|
||
ox += this.iconSize;
|
||
} else {
|
||
ox = this.offsetX;
|
||
oy += this.iconSize;
|
||
}
|
||
}, this);
|
||
},
|
||
|
||
updateThemes: function() {
|
||
var ts = this.querySelectorAll('property[theme]');
|
||
ts && ts.array().forEach(function(t) {
|
||
this.themes[t.getAttribute('theme')] = {
|
||
offsetX: parseInt(t.getAttribute('offsetX')) || 0,
|
||
offsetY: parseInt(t.getAttribute('offsetY')) || 0
|
||
};
|
||
}, this);
|
||
},
|
||
|
||
// TODO(ffu): support retrived by index e.g. getOffset(10);
|
||
/**
|
||
* Returns an object containing `offsetX` and `offsetY` properties which
|
||
* specify the pixel locaion in the iconset's src file for the given
|
||
* `icon` and `theme`. It's uncommon to call this method. It is useful,
|
||
* for example, to manually position a css backgroundImage to the proper
|
||
* offset. It's more common to use the `applyIcon` method.
|
||
*
|
||
* @method getOffset
|
||
* @param {String|Number} icon The name of the icon or the index of the
|
||
* icon within in the icon image.
|
||
* @param {String} theme The name of the theme.
|
||
* @returns {Object} An object specifying the offset of the given icon
|
||
* within the icon resource file; `offsetX` is the horizontal offset and
|
||
* `offsetY` is the vertical offset. Both values are in pixel units.
|
||
*/
|
||
getOffset: function(icon, theme) {
|
||
var i = this.iconMap[icon];
|
||
if (!i) {
|
||
var n = this.iconNames[Number(icon)];
|
||
i = this.iconMap[n];
|
||
}
|
||
var t = this.themes[theme];
|
||
if (i && t) {
|
||
return {
|
||
offsetX: i.offsetX + t.offsetX,
|
||
offsetY: i.offsetY + t.offsetY
|
||
}
|
||
}
|
||
return i;
|
||
},
|
||
|
||
/**
|
||
* Applies an icon to the given element as a css background image. This
|
||
* method does not size the element, and it's often necessary to set
|
||
* the element's height and width so that the background image is visible.
|
||
*
|
||
* @method applyIcon
|
||
* @param {Element} element The element to which the background is
|
||
* applied.
|
||
* @param {String|Number} icon The name or index of the icon to apply.
|
||
* @param {Number} scale (optional, defaults to 1) A scaling factor
|
||
* with which the icon can be magnified.
|
||
* @return {Element} The icon element.
|
||
*/
|
||
applyIcon: function(element, icon, scale) {
|
||
var offset = this.getOffset(icon);
|
||
scale = scale || 1;
|
||
if (element && offset) {
|
||
var icon = element._icon || document.createElement('div');
|
||
var style = icon.style;
|
||
style.backgroundImage = 'url(' + this.src + ')';
|
||
style.backgroundPosition = (-offset.offsetX * scale + 'px') +
|
||
' ' + (-offset.offsetY * scale + 'px');
|
||
style.backgroundSize = scale === 1 ? 'auto' :
|
||
this.width * scale + 'px';
|
||
if (icon.parentNode !== element) {
|
||
element.appendChild(icon);
|
||
}
|
||
return icon;
|
||
}
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
|
||
</polymer-element>
|
||
|
||
|
||
<style shim-shadowdom="">/* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */
|
||
|
||
html /deep/ core-icon {
|
||
display: inline-block;
|
||
vertical-align: middle;
|
||
background-repeat: no-repeat;
|
||
fill: currentcolor;
|
||
position: relative;
|
||
height: 24px;
|
||
width: 24px;
|
||
}</style>
|
||
|
||
<polymer-element name="core-icon" attributes="src icon alt" assetpath="polymer/bower_components/core-icon/">
|
||
<script>
|
||
(function() {
|
||
|
||
// mono-state
|
||
var meta;
|
||
|
||
Polymer('core-icon', {
|
||
|
||
/**
|
||
* The URL of an image for the icon. If the src property is specified,
|
||
* the icon property should not be.
|
||
*
|
||
* @attribute src
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
src: '',
|
||
|
||
/**
|
||
* Specifies the icon name or index in the set of icons available in
|
||
* the icon's icon set. If the icon property is specified,
|
||
* the src property should not be.
|
||
*
|
||
* @attribute icon
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
icon: '',
|
||
|
||
/**
|
||
* Alternative text content for accessibility support.
|
||
* If alt is present and not empty, it will set the element's role to img and add an aria-label whose content matches alt.
|
||
* If alt is present and is an empty string, '', it will hide the element from the accessibility layer
|
||
* If alt is not present, it will set the element's role to img and the element will fallback to using the icon attribute for its aria-label.
|
||
*
|
||
* @attribute alt
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
alt: null,
|
||
|
||
observe: {
|
||
'icon': 'updateIcon',
|
||
'alt': 'updateAlt'
|
||
},
|
||
|
||
defaultIconset: 'icons',
|
||
|
||
ready: function() {
|
||
if (!meta) {
|
||
meta = document.createElement('core-iconset');
|
||
}
|
||
|
||
// Allow user-provided `aria-label` in preference to any other text alternative.
|
||
if (this.hasAttribute('aria-label')) {
|
||
// Set `role` if it has not been overridden.
|
||
if (!this.hasAttribute('role')) {
|
||
this.setAttribute('role', 'img');
|
||
}
|
||
return;
|
||
}
|
||
this.updateAlt();
|
||
},
|
||
|
||
srcChanged: function() {
|
||
var icon = this._icon || document.createElement('div');
|
||
icon.textContent = '';
|
||
icon.setAttribute('fit', '');
|
||
icon.style.backgroundImage = 'url(' + this.src + ')';
|
||
icon.style.backgroundPosition = 'center';
|
||
icon.style.backgroundSize = '100%';
|
||
if (!icon.parentNode) {
|
||
this.appendChild(icon);
|
||
}
|
||
this._icon = icon;
|
||
},
|
||
|
||
getIconset: function(name) {
|
||
return meta.byId(name || this.defaultIconset);
|
||
},
|
||
|
||
updateIcon: function(oldVal, newVal) {
|
||
if (!this.icon) {
|
||
this.updateAlt();
|
||
return;
|
||
}
|
||
var parts = String(this.icon).split(':');
|
||
var icon = parts.pop();
|
||
if (icon) {
|
||
var set = this.getIconset(parts.pop());
|
||
if (set) {
|
||
this._icon = set.applyIcon(this, icon);
|
||
if (this._icon) {
|
||
this._icon.setAttribute('fit', '');
|
||
}
|
||
}
|
||
}
|
||
// Check to see if we're using the old icon's name for our a11y fallback
|
||
if (oldVal) {
|
||
if (oldVal.split(':').pop() == this.getAttribute('aria-label')) {
|
||
this.updateAlt();
|
||
}
|
||
}
|
||
},
|
||
|
||
updateAlt: function() {
|
||
// Respect the user's decision to remove this element from
|
||
// the a11y tree
|
||
if (this.getAttribute('aria-hidden')) {
|
||
return;
|
||
}
|
||
|
||
// Remove element from a11y tree if `alt` is empty, otherwise
|
||
// use `alt` as `aria-label`.
|
||
if (this.alt === '') {
|
||
this.setAttribute('aria-hidden', 'true');
|
||
if (this.hasAttribute('role')) {
|
||
this.removeAttribute('role');
|
||
}
|
||
if (this.hasAttribute('aria-label')) {
|
||
this.removeAttribute('aria-label');
|
||
}
|
||
} else {
|
||
this.setAttribute('aria-label', this.alt ||
|
||
this.icon.split(':').pop());
|
||
if (!this.hasAttribute('role')) {
|
||
this.setAttribute('role', 'img');
|
||
}
|
||
if (this.hasAttribute('aria-hidden')) {
|
||
this.removeAttribute('aria-hidden');
|
||
}
|
||
}
|
||
}
|
||
|
||
});
|
||
|
||
})();
|
||
</script>
|
||
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`paper-ripple` provides a visual effect that other paper elements can
|
||
use to simulate a rippling effect emanating from the point of contact. The
|
||
effect can be visualized as a concentric circle with motion.
|
||
|
||
Example:
|
||
|
||
<paper-ripple></paper-ripple>
|
||
|
||
`paper-ripple` listens to "down" and "up" events so it would display ripple
|
||
effect when touches on it. You can also defeat the default behavior and
|
||
manually route the down and up actions to the ripple element. Note that it is
|
||
important if you call downAction() you will have to make sure to call upAction()
|
||
so that `paper-ripple` would end the animation loop.
|
||
|
||
Example:
|
||
|
||
<paper-ripple id="ripple" style="pointer-events: none;"></paper-ripple>
|
||
...
|
||
downAction: function(e) {
|
||
this.$.ripple.downAction({x: e.x, y: e.y});
|
||
},
|
||
upAction: function(e) {
|
||
this.$.ripple.upAction();
|
||
}
|
||
|
||
Styling ripple effect:
|
||
|
||
Use CSS color property to style the ripple:
|
||
|
||
paper-ripple {
|
||
color: #4285f4;
|
||
}
|
||
|
||
Note that CSS color property is inherited so it is not required to set it on
|
||
the `paper-ripple` element directly.
|
||
|
||
Apply `recenteringTouch` class to make the recentering rippling effect.
|
||
|
||
<paper-ripple class="recenteringTouch"></paper-ripple>
|
||
|
||
Apply `circle` class to make the rippling effect within a circle.
|
||
|
||
<paper-ripple class="circle"></paper-ripple>
|
||
|
||
@group Paper Elements
|
||
@element paper-ripple
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="paper-ripple" attributes="initialOpacity opacityDecayVelocity" assetpath="polymer/bower_components/paper-ripple/">
|
||
<template>
|
||
|
||
<style>
|
||
|
||
:host {
|
||
display: block;
|
||
position: relative;
|
||
border-radius: inherit;
|
||
overflow: hidden;
|
||
}
|
||
|
||
:host-context([noink]) {
|
||
pointer-events: none;
|
||
}
|
||
|
||
#bg, #waves, .wave-container, .wave {
|
||
pointer-events: none;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
#bg, .wave {
|
||
opacity: 0;
|
||
}
|
||
|
||
#waves, .wave {
|
||
overflow: hidden;
|
||
}
|
||
|
||
.wave-container, .wave {
|
||
border-radius: 50%;
|
||
}
|
||
|
||
:host(.circle) #bg,
|
||
:host(.circle) #waves {
|
||
border-radius: 50%;
|
||
}
|
||
|
||
:host(.circle) .wave-container {
|
||
overflow: hidden;
|
||
}
|
||
|
||
</style>
|
||
|
||
<div id="bg"></div>
|
||
<div id="waves">
|
||
</div>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
(function() {
|
||
|
||
var waveMaxRadius = 150;
|
||
//
|
||
// INK EQUATIONS
|
||
//
|
||
function waveRadiusFn(touchDownMs, touchUpMs, anim) {
|
||
// Convert from ms to s.
|
||
var touchDown = touchDownMs / 1000;
|
||
var touchUp = touchUpMs / 1000;
|
||
var totalElapsed = touchDown + touchUp;
|
||
var ww = anim.width, hh = anim.height;
|
||
// use diagonal size of container to avoid floating point math sadness
|
||
var waveRadius = Math.min(Math.sqrt(ww * ww + hh * hh), waveMaxRadius) * 1.1 + 5;
|
||
var duration = 1.1 - .2 * (waveRadius / waveMaxRadius);
|
||
var tt = (totalElapsed / duration);
|
||
|
||
var size = waveRadius * (1 - Math.pow(80, -tt));
|
||
return Math.abs(size);
|
||
}
|
||
|
||
function waveOpacityFn(td, tu, anim) {
|
||
// Convert from ms to s.
|
||
var touchDown = td / 1000;
|
||
var touchUp = tu / 1000;
|
||
var totalElapsed = touchDown + touchUp;
|
||
|
||
if (tu <= 0) { // before touch up
|
||
return anim.initialOpacity;
|
||
}
|
||
return Math.max(0, anim.initialOpacity - touchUp * anim.opacityDecayVelocity);
|
||
}
|
||
|
||
function waveOuterOpacityFn(td, tu, anim) {
|
||
// Convert from ms to s.
|
||
var touchDown = td / 1000;
|
||
var touchUp = tu / 1000;
|
||
|
||
// Linear increase in background opacity, capped at the opacity
|
||
// of the wavefront (waveOpacity).
|
||
var outerOpacity = touchDown * 0.3;
|
||
var waveOpacity = waveOpacityFn(td, tu, anim);
|
||
return Math.max(0, Math.min(outerOpacity, waveOpacity));
|
||
}
|
||
|
||
// Determines whether the wave should be completely removed.
|
||
function waveDidFinish(wave, radius, anim) {
|
||
var waveOpacity = waveOpacityFn(wave.tDown, wave.tUp, anim);
|
||
|
||
// If the wave opacity is 0 and the radius exceeds the bounds
|
||
// of the element, then this is finished.
|
||
return waveOpacity < 0.01 && radius >= Math.min(wave.maxRadius, waveMaxRadius);
|
||
};
|
||
|
||
function waveAtMaximum(wave, radius, anim) {
|
||
var waveOpacity = waveOpacityFn(wave.tDown, wave.tUp, anim);
|
||
|
||
return waveOpacity >= anim.initialOpacity && radius >= Math.min(wave.maxRadius, waveMaxRadius);
|
||
}
|
||
|
||
//
|
||
// DRAWING
|
||
//
|
||
function drawRipple(ctx, x, y, radius, innerAlpha, outerAlpha) {
|
||
// Only animate opacity and transform
|
||
if (outerAlpha !== undefined) {
|
||
ctx.bg.style.opacity = outerAlpha;
|
||
}
|
||
ctx.wave.style.opacity = innerAlpha;
|
||
|
||
var s = radius / (ctx.containerSize / 2);
|
||
var dx = x - (ctx.containerWidth / 2);
|
||
var dy = y - (ctx.containerHeight / 2);
|
||
|
||
ctx.wc.style.webkitTransform = 'translate3d(' + dx + 'px,' + dy + 'px,0)';
|
||
ctx.wc.style.transform = 'translate3d(' + dx + 'px,' + dy + 'px,0)';
|
||
|
||
// 2d transform for safari because of border-radius and overflow:hidden clipping bug.
|
||
// https://bugs.webkit.org/show_bug.cgi?id=98538
|
||
ctx.wave.style.webkitTransform = 'scale(' + s + ',' + s + ')';
|
||
ctx.wave.style.transform = 'scale3d(' + s + ',' + s + ',1)';
|
||
}
|
||
|
||
//
|
||
// SETUP
|
||
//
|
||
function createWave(elem) {
|
||
var elementStyle = window.getComputedStyle(elem);
|
||
var fgColor = elementStyle.color;
|
||
|
||
var inner = document.createElement('div');
|
||
inner.style.backgroundColor = fgColor;
|
||
inner.classList.add('wave');
|
||
|
||
var outer = document.createElement('div');
|
||
outer.classList.add('wave-container');
|
||
outer.appendChild(inner);
|
||
|
||
var container = elem.$.waves;
|
||
container.appendChild(outer);
|
||
|
||
elem.$.bg.style.backgroundColor = fgColor;
|
||
|
||
var wave = {
|
||
bg: elem.$.bg,
|
||
wc: outer,
|
||
wave: inner,
|
||
waveColor: fgColor,
|
||
maxRadius: 0,
|
||
isMouseDown: false,
|
||
mouseDownStart: 0.0,
|
||
mouseUpStart: 0.0,
|
||
tDown: 0,
|
||
tUp: 0
|
||
};
|
||
return wave;
|
||
}
|
||
|
||
function removeWaveFromScope(scope, wave) {
|
||
if (scope.waves) {
|
||
var pos = scope.waves.indexOf(wave);
|
||
scope.waves.splice(pos, 1);
|
||
// FIXME cache nodes
|
||
wave.wc.remove();
|
||
}
|
||
};
|
||
|
||
// Shortcuts.
|
||
var pow = Math.pow;
|
||
var now = Date.now;
|
||
if (window.performance && performance.now) {
|
||
now = performance.now.bind(performance);
|
||
}
|
||
|
||
function cssColorWithAlpha(cssColor, alpha) {
|
||
var parts = cssColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
||
if (typeof alpha == 'undefined') {
|
||
alpha = 1;
|
||
}
|
||
if (!parts) {
|
||
return 'rgba(255, 255, 255, ' + alpha + ')';
|
||
}
|
||
return 'rgba(' + parts[1] + ', ' + parts[2] + ', ' + parts[3] + ', ' + alpha + ')';
|
||
}
|
||
|
||
function dist(p1, p2) {
|
||
return Math.sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
|
||
}
|
||
|
||
function distanceFromPointToFurthestCorner(point, size) {
|
||
var tl_d = dist(point, {x: 0, y: 0});
|
||
var tr_d = dist(point, {x: size.w, y: 0});
|
||
var bl_d = dist(point, {x: 0, y: size.h});
|
||
var br_d = dist(point, {x: size.w, y: size.h});
|
||
return Math.max(tl_d, tr_d, bl_d, br_d);
|
||
}
|
||
|
||
Polymer('paper-ripple', {
|
||
|
||
/**
|
||
* The initial opacity set on the wave.
|
||
*
|
||
* @attribute initialOpacity
|
||
* @type number
|
||
* @default 0.25
|
||
*/
|
||
initialOpacity: 0.25,
|
||
|
||
/**
|
||
* How fast (opacity per second) the wave fades out.
|
||
*
|
||
* @attribute opacityDecayVelocity
|
||
* @type number
|
||
* @default 0.8
|
||
*/
|
||
opacityDecayVelocity: 0.8,
|
||
|
||
backgroundFill: true,
|
||
pixelDensity: 2,
|
||
|
||
eventDelegates: {
|
||
down: 'downAction',
|
||
up: 'upAction'
|
||
},
|
||
|
||
ready: function() {
|
||
this.waves = [];
|
||
},
|
||
|
||
downAction: function(e) {
|
||
var wave = createWave(this);
|
||
|
||
this.cancelled = false;
|
||
wave.isMouseDown = true;
|
||
wave.tDown = 0.0;
|
||
wave.tUp = 0.0;
|
||
wave.mouseUpStart = 0.0;
|
||
wave.mouseDownStart = now();
|
||
|
||
var rect = this.getBoundingClientRect();
|
||
var width = rect.width;
|
||
var height = rect.height;
|
||
var touchX = e.x - rect.left;
|
||
var touchY = e.y - rect.top;
|
||
|
||
wave.startPosition = {x:touchX, y:touchY};
|
||
|
||
if (this.classList.contains("recenteringTouch")) {
|
||
wave.endPosition = {x: width / 2, y: height / 2};
|
||
wave.slideDistance = dist(wave.startPosition, wave.endPosition);
|
||
}
|
||
wave.containerSize = Math.max(width, height);
|
||
wave.containerWidth = width;
|
||
wave.containerHeight = height;
|
||
wave.maxRadius = distanceFromPointToFurthestCorner(wave.startPosition, {w: width, h: height});
|
||
|
||
// The wave is circular so constrain its container to 1:1
|
||
wave.wc.style.top = (wave.containerHeight - wave.containerSize) / 2 + 'px';
|
||
wave.wc.style.left = (wave.containerWidth - wave.containerSize) / 2 + 'px';
|
||
wave.wc.style.width = wave.containerSize + 'px';
|
||
wave.wc.style.height = wave.containerSize + 'px';
|
||
|
||
this.waves.push(wave);
|
||
|
||
if (!this._loop) {
|
||
this._loop = this.animate.bind(this, {
|
||
width: width,
|
||
height: height
|
||
});
|
||
requestAnimationFrame(this._loop);
|
||
}
|
||
// else there is already a rAF
|
||
},
|
||
|
||
upAction: function() {
|
||
for (var i = 0; i < this.waves.length; i++) {
|
||
// Declare the next wave that has mouse down to be mouse'ed up.
|
||
var wave = this.waves[i];
|
||
if (wave.isMouseDown) {
|
||
wave.isMouseDown = false
|
||
wave.mouseUpStart = now();
|
||
wave.mouseDownStart = 0;
|
||
wave.tUp = 0.0;
|
||
break;
|
||
}
|
||
}
|
||
this._loop && requestAnimationFrame(this._loop);
|
||
},
|
||
|
||
cancel: function() {
|
||
this.cancelled = true;
|
||
},
|
||
|
||
animate: function(ctx) {
|
||
var shouldRenderNextFrame = false;
|
||
|
||
var deleteTheseWaves = [];
|
||
// The oldest wave's touch down duration
|
||
var longestTouchDownDuration = 0;
|
||
var longestTouchUpDuration = 0;
|
||
// Save the last known wave color
|
||
var lastWaveColor = null;
|
||
// wave animation values
|
||
var anim = {
|
||
initialOpacity: this.initialOpacity,
|
||
opacityDecayVelocity: this.opacityDecayVelocity,
|
||
height: ctx.height,
|
||
width: ctx.width
|
||
}
|
||
|
||
for (var i = 0; i < this.waves.length; i++) {
|
||
var wave = this.waves[i];
|
||
|
||
if (wave.mouseDownStart > 0) {
|
||
wave.tDown = now() - wave.mouseDownStart;
|
||
}
|
||
if (wave.mouseUpStart > 0) {
|
||
wave.tUp = now() - wave.mouseUpStart;
|
||
}
|
||
|
||
// Determine how long the touch has been up or down.
|
||
var tUp = wave.tUp;
|
||
var tDown = wave.tDown;
|
||
longestTouchDownDuration = Math.max(longestTouchDownDuration, tDown);
|
||
longestTouchUpDuration = Math.max(longestTouchUpDuration, tUp);
|
||
|
||
// Obtain the instantenous size and alpha of the ripple.
|
||
var radius = waveRadiusFn(tDown, tUp, anim);
|
||
var waveAlpha = waveOpacityFn(tDown, tUp, anim);
|
||
var waveColor = cssColorWithAlpha(wave.waveColor, waveAlpha);
|
||
lastWaveColor = wave.waveColor;
|
||
|
||
// Position of the ripple.
|
||
var x = wave.startPosition.x;
|
||
var y = wave.startPosition.y;
|
||
|
||
// Ripple gravitational pull to the center of the canvas.
|
||
if (wave.endPosition) {
|
||
|
||
// This translates from the origin to the center of the view based on the max dimension of
|
||
var translateFraction = Math.min(1, radius / wave.containerSize * 2 / Math.sqrt(2) );
|
||
|
||
x += translateFraction * (wave.endPosition.x - wave.startPosition.x);
|
||
y += translateFraction * (wave.endPosition.y - wave.startPosition.y);
|
||
}
|
||
|
||
// If we do a background fill fade too, work out the correct color.
|
||
var bgFillColor = null;
|
||
if (this.backgroundFill) {
|
||
var bgFillAlpha = waveOuterOpacityFn(tDown, tUp, anim);
|
||
bgFillColor = cssColorWithAlpha(wave.waveColor, bgFillAlpha);
|
||
}
|
||
|
||
// Draw the ripple.
|
||
drawRipple(wave, x, y, radius, waveAlpha, bgFillAlpha);
|
||
|
||
// Determine whether there is any more rendering to be done.
|
||
var maximumWave = waveAtMaximum(wave, radius, anim);
|
||
var waveDissipated = waveDidFinish(wave, radius, anim);
|
||
var shouldKeepWave = !waveDissipated || maximumWave;
|
||
// keep rendering dissipating wave when at maximum radius on upAction
|
||
var shouldRenderWaveAgain = wave.mouseUpStart ? !waveDissipated : !maximumWave;
|
||
shouldRenderNextFrame = shouldRenderNextFrame || shouldRenderWaveAgain;
|
||
if (!shouldKeepWave || this.cancelled) {
|
||
deleteTheseWaves.push(wave);
|
||
}
|
||
}
|
||
|
||
if (shouldRenderNextFrame) {
|
||
requestAnimationFrame(this._loop);
|
||
}
|
||
|
||
for (var i = 0; i < deleteTheseWaves.length; ++i) {
|
||
var wave = deleteTheseWaves[i];
|
||
removeWaveFromScope(this, wave);
|
||
}
|
||
|
||
if (!this.waves.length && this._loop) {
|
||
// clear the background color
|
||
this.$.bg.style.backgroundColor = null;
|
||
this._loop = null;
|
||
this.fire('core-transitionend');
|
||
}
|
||
}
|
||
|
||
});
|
||
|
||
})();
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
The `paper-shadow` element is a helper to add shadows to elements.
|
||
Paper shadows are composed of two shadows on top of each other. We
|
||
mimic this effect by using two elements on top of each other, each with a
|
||
different drop shadow. You can apply the shadow to an element by assigning
|
||
it as the target. If you do not specify a target, the shadow is applied to
|
||
the `paper-shadow` element's parent element or shadow host element if its
|
||
parent is a shadow root. Alternatively, you can use the CSS classes included
|
||
by this element directly.
|
||
|
||
Example:
|
||
|
||
<div id="myCard" class="card"></div>
|
||
<paper-shadow id="myShadow" z="1"></div>
|
||
|
||
// Assign a target explicitly
|
||
myShadow.target = document.getElementById('myCard');
|
||
|
||
// Auto-assign the target.
|
||
<div class="card">
|
||
<paper-shadow z="1"></paper-shadow>
|
||
</div>
|
||
|
||
// Use the classes directly
|
||
<div class="card paper-shadow-top paper-shadow-top-z-1">
|
||
<div class="card-inner paper-shadow-bottom paper-shadow-bottom-z-1"></div>
|
||
</div>
|
||
|
||
If you assign a target to a `paper-shadow` element, it creates two nodes and inserts
|
||
them as the first children of the target, or the first children of the target's shadow
|
||
root if there is one. This implies:
|
||
|
||
1. If the primary node that drops the shadow has styling that affects its shape,
|
||
the same styling must be applied to elements with class `paper-shadow`.
|
||
`border-radius` is a very common property and is inherited automatically.
|
||
|
||
2. The target's overflow property will be set to `overflow: visible` because the
|
||
shadow is rendered beyond the bounds of its container. Position the shadow as a
|
||
separate layer and use a different child element for clipping if needed.
|
||
|
||
@group Paper Elements
|
||
@class paper-shadow
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="paper-shadow" assetpath="polymer/bower_components/paper-shadow/">
|
||
|
||
<template>
|
||
|
||
<style no-shim="">/*
|
||
* @license
|
||
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
* Code distributed by Google as part of the polymer project is also
|
||
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
.paper-shadow {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
bottom: 0;
|
||
right: 0;
|
||
border-radius: inherit;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.paper-shadow-animated.paper-shadow {
|
||
transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
.paper-shadow-top-z-1 {
|
||
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.16);
|
||
}
|
||
|
||
.paper-shadow-bottom-z-1 {
|
||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
|
||
}
|
||
|
||
.paper-shadow-top-z-2 {
|
||
box-shadow: 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||
}
|
||
|
||
.paper-shadow-bottom-z-2 {
|
||
box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.paper-shadow-top-z-3 {
|
||
box-shadow: 0 17px 50px 0 rgba(0, 0, 0, 0.19);
|
||
}
|
||
|
||
.paper-shadow-bottom-z-3 {
|
||
box-shadow: 0 12px 15px 0 rgba(0, 0, 0, 0.24);
|
||
}
|
||
|
||
.paper-shadow-top-z-4 {
|
||
box-shadow: 0 25px 55px 0 rgba(0, 0, 0, 0.21);
|
||
}
|
||
|
||
.paper-shadow-bottom-z-4 {
|
||
box-shadow: 0 16px 28px 0 rgba(0, 0, 0, 0.22);
|
||
}
|
||
|
||
.paper-shadow-top-z-5 {
|
||
box-shadow: 0 40px 77px 0 rgba(0, 0, 0, 0.22);
|
||
}
|
||
|
||
.paper-shadow-bottom-z-5 {
|
||
box-shadow: 0 27px 24px 0 rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.paper-shadow-animate-z-1-z-2.paper-shadow-top {
|
||
-webkit-transition: none;
|
||
-webkit-animation: animate-shadow-top-z-1-z-2 0.7s infinite alternate;
|
||
}
|
||
|
||
.paper-shadow-animate-z-1-z-2 .paper-shadow-bottom {
|
||
-webkit-transition: none;
|
||
-webkit-animation: animate-shadow-bottom-z-1-z-2 0.7s infinite alternate;
|
||
}
|
||
|
||
@-webkit-keyframes animate-shadow-top-z-1-z-2 {
|
||
0% {
|
||
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.16);
|
||
}
|
||
100% {
|
||
box-shadow: 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||
}
|
||
}
|
||
|
||
@-webkit-keyframes animate-shadow-bottom-z-1-z-2 {
|
||
0% {
|
||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
|
||
}
|
||
100% {
|
||
box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
|
||
}
|
||
}</style>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
Polymer('paper-shadow', {
|
||
|
||
publish: {
|
||
/**
|
||
* If set, the shadow is applied to this node.
|
||
*
|
||
* @attribute target
|
||
* @type Element
|
||
* @default null
|
||
*/
|
||
target: {value: null, reflect: true},
|
||
|
||
/**
|
||
* The z-depth of this shadow, from 0-5.
|
||
*
|
||
* @attribute z
|
||
* @type number
|
||
* @default 1
|
||
*/
|
||
z: {value: 1, reflect: true},
|
||
|
||
/**
|
||
* If true, the shadow animates between z-depth changes.
|
||
*
|
||
* @attribute animated
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
animated: {value: false, reflect: true},
|
||
|
||
/**
|
||
* Workaround: getComputedStyle is wrong sometimes so `paper-shadow`
|
||
* may overwrite the `position` CSS property. Set this property to
|
||
* true to prevent this.
|
||
*
|
||
* @attribute hasPosition
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
hasPosition: false
|
||
},
|
||
|
||
// NOTE: include template so that styles are loaded, but remove
|
||
// so that we can decide dynamically what part to include
|
||
registerCallback: function(polymerElement) {
|
||
var template = polymerElement.querySelector('template');
|
||
this._style = template.content.querySelector('style');
|
||
this._style.removeAttribute('no-shim');
|
||
},
|
||
|
||
fetchTemplate: function() {
|
||
return null;
|
||
},
|
||
|
||
attached: function() {
|
||
// If no target is bound at attach, default the target to the parent
|
||
// element or shadow host.
|
||
if (!this.target) {
|
||
if (!this.parentElement && this.parentNode.host) {
|
||
this.target = this.parentNode.host;
|
||
} else if (this.parentElement && (window.ShadowDOMPolyfill ? this.parentElement !== wrap(document.body) : this.parentElement !== document.body)) {
|
||
this.target = this.parentElement;
|
||
}
|
||
}
|
||
},
|
||
|
||
targetChanged: function(old) {
|
||
if (old) {
|
||
this.removeShadow(old);
|
||
}
|
||
if (this.target) {
|
||
this.addShadow(this.target);
|
||
}
|
||
},
|
||
|
||
zChanged: function(old) {
|
||
if (this.target && this.target._paperShadow) {
|
||
var shadow = this.target._paperShadow;
|
||
['top', 'bottom'].forEach(function(s) {
|
||
shadow[s].classList.remove('paper-shadow-' + s + '-z-' + old);
|
||
shadow[s].classList.add('paper-shadow-' + s + '-z-' + this.z);
|
||
}.bind(this));
|
||
}
|
||
},
|
||
|
||
animatedChanged: function() {
|
||
if (this.target && this.target._paperShadow) {
|
||
var shadow = this.target._paperShadow;
|
||
['top', 'bottom'].forEach(function(s) {
|
||
if (this.animated) {
|
||
shadow[s].classList.add('paper-shadow-animated');
|
||
} else {
|
||
shadow[s].classList.remove('paper-shadow-animated');
|
||
}
|
||
}.bind(this));
|
||
}
|
||
},
|
||
|
||
addShadow: function(node) {
|
||
if (node._paperShadow) {
|
||
return;
|
||
}
|
||
|
||
if (!node._hasShadowStyle) {
|
||
if (!node.shadowRoot) {
|
||
node.createShadowRoot().innerHTML = '<content></content>';
|
||
}
|
||
this.installScopeStyle(this._style, 'shadow', node.shadowRoot);
|
||
node._hasShadowStyle = true;
|
||
}
|
||
|
||
var computed = getComputedStyle(node);
|
||
if (!this.hasPosition && computed.position === 'static') {
|
||
node.style.position = 'relative';
|
||
}
|
||
node.style.overflow = 'visible';
|
||
|
||
// Both the top and bottom shadows are children of the target, so
|
||
// it does not affect the classes and CSS properties of the target.
|
||
['top', 'bottom'].forEach(function(s) {
|
||
var inner = (node._paperShadow && node._paperShadow[s]) || document.createElement('div');
|
||
inner.classList.add('paper-shadow');
|
||
inner.classList.add('paper-shadow-' + s + '-z-' + this.z);
|
||
if (this.animated) {
|
||
inner.classList.add('paper-shadow-animated');
|
||
}
|
||
|
||
if (node.shadowRoot) {
|
||
node.shadowRoot.insertBefore(inner, node.shadowRoot.firstChild);
|
||
} else {
|
||
node.insertBefore(inner, node.firstChild);
|
||
}
|
||
|
||
node._paperShadow = node._paperShadow || {};
|
||
node._paperShadow[s] = inner;
|
||
}.bind(this));
|
||
|
||
},
|
||
|
||
removeShadow: function(node) {
|
||
if (!node._paperShadow) {
|
||
return;
|
||
}
|
||
|
||
['top', 'bottom'].forEach(function(s) {
|
||
node._paperShadow[s].remove();
|
||
});
|
||
node._paperShadow = null;
|
||
|
||
node.style.position = null;
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
@group Paper Elements
|
||
|
||
`paper-button-base` is the base class for button-like elements with ripple and optional shadow.
|
||
|
||
@element paper-button-base
|
||
@extends paper-focusable
|
||
@status unstable
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
/**
|
||
* @group Paper Elements
|
||
*
|
||
* paper-focusable is a base class for paper elements that can be focused.
|
||
*
|
||
* @element paper-focusable
|
||
* @status beta
|
||
* @homepage github.io
|
||
*/
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="paper-focusable" attributes="active focused disabled isToggle" tabindex="0" on-down="{{downAction}}" on-up="{{upAction}}" on-focus="{{focusAction}}" on-blur="{{blurAction}}" on-contextmenu="{{contextMenuAction}}" assetpath="polymer/bower_components/paper-focusable/">
|
||
|
||
<template>
|
||
<style>
|
||
:host([disabled]) {
|
||
pointer-events: none;
|
||
}
|
||
</style>
|
||
<content></content>
|
||
</template>
|
||
|
||
<script>
|
||
Polymer('paper-focusable', {
|
||
|
||
publish: {
|
||
|
||
/**
|
||
* If true, the button is currently active either because the
|
||
* user is holding down the button, or the button is a toggle
|
||
* and is currently in the active state.
|
||
*
|
||
* @attribute active
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
active: {value: false, reflect: true},
|
||
|
||
/**
|
||
* If true, the element currently has focus due to keyboard
|
||
* navigation.
|
||
*
|
||
* @attribute focused
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
focused: {value: false, reflect: true},
|
||
|
||
/**
|
||
* If true, the user is currently holding down the button.
|
||
*
|
||
* @attribute pressed
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
pressed: {value: false, reflect: true},
|
||
|
||
/**
|
||
* If true, the user cannot interact with this element.
|
||
*
|
||
* @attribute disabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
disabled: {value: false, reflect: true},
|
||
|
||
/**
|
||
* If true, the button toggles the active state with each tap.
|
||
* Otherwise, the button becomes active when the user is holding
|
||
* it down.
|
||
*
|
||
* @attribute isToggle
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
isToggle: {value: false, reflect: false}
|
||
|
||
},
|
||
|
||
disabledChanged: function() {
|
||
if (this.disabled) {
|
||
this.removeAttribute('tabindex');
|
||
} else {
|
||
this.setAttribute('tabindex', 0);
|
||
}
|
||
},
|
||
|
||
downAction: function() {
|
||
this.pressed = true;
|
||
|
||
if (this.isToggle) {
|
||
this.active = !this.active;
|
||
} else {
|
||
this.active = true;
|
||
}
|
||
},
|
||
|
||
// Pulling up the context menu for an item should focus it; but we need to
|
||
// be careful about how we deal with down/up events surrounding context
|
||
// menus. The up event typically does not fire until the context menu
|
||
// closes: so we focus immediately.
|
||
//
|
||
// This fires _after_ downAction.
|
||
contextMenuAction: function(e) {
|
||
// Note that upAction may fire _again_ on the actual up event.
|
||
this.upAction(e);
|
||
this.focusAction();
|
||
},
|
||
|
||
upAction: function() {
|
||
this.pressed = false;
|
||
|
||
if (!this.isToggle) {
|
||
this.active = false;
|
||
}
|
||
},
|
||
|
||
focusAction: function() {
|
||
if (!this.pressed) {
|
||
// Only render the "focused" state if the element gains focus due to
|
||
// keyboard navigation.
|
||
this.focused = true;
|
||
}
|
||
},
|
||
|
||
blurAction: function() {
|
||
this.focused = false;
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="paper-button-base" extends="paper-focusable" assetpath="polymer/bower_components/paper-button/">
|
||
|
||
<script>
|
||
Polymer('paper-button-base',{
|
||
|
||
z: 1,
|
||
|
||
activeChanged: function() {
|
||
this.super();
|
||
|
||
if (this.active) {
|
||
// FIXME: remove when paper-ripple can have a default 'down' state.
|
||
if (!this.lastEvent) {
|
||
var rect = this.getBoundingClientRect();
|
||
this.lastEvent = {
|
||
x: rect.left + rect.width / 2,
|
||
y: rect.top + rect.height / 2
|
||
}
|
||
}
|
||
this.$.ripple.downAction(this.lastEvent);
|
||
} else {
|
||
this.$.ripple.upAction();
|
||
}
|
||
this.adjustZ();
|
||
},
|
||
|
||
disabledChanged: function() {
|
||
this.super();
|
||
if (this.disabled) {
|
||
this.setAttribute('aria-disabled', '');
|
||
} else {
|
||
this.removeAttribute('aria-disabled');
|
||
}
|
||
this.adjustZ();
|
||
},
|
||
|
||
recenteringTouchChanged: function() {
|
||
if (this.$.ripple) {
|
||
this.$.ripple.classList.toggle('recenteringTouch', this.recenteringTouch);
|
||
}
|
||
},
|
||
|
||
fillChanged: function() {
|
||
if (this.$.ripple) {
|
||
this.$.ripple.classList.toggle('fill', this.fill);
|
||
}
|
||
},
|
||
|
||
adjustZ: function() {
|
||
if (this.active) {
|
||
this.z = 2;
|
||
} else if (this.disabled) {
|
||
this.z = 0;
|
||
} else {
|
||
this.z = 1;
|
||
}
|
||
},
|
||
|
||
downAction: function(e) {
|
||
this.super(e);
|
||
this.lastEvent = e;
|
||
if (!this.$.ripple) {
|
||
var ripple = document.createElement('paper-ripple');
|
||
ripple.setAttribute('id', 'ripple');
|
||
ripple.setAttribute('fit', '');
|
||
if (this.recenteringTouch) {
|
||
ripple.classList.add('recenteringTouch');
|
||
}
|
||
if (!this.fill) {
|
||
ripple.classList.add('circle');
|
||
}
|
||
this.$.ripple = ripple;
|
||
this.shadowRoot.insertBefore(ripple, this.shadowRoot.firstChild);
|
||
// No need to forward the event to the ripple because the ripple
|
||
// is triggered in activeChanged
|
||
}
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="paper-button" extends="paper-button-base" attributes="raised recenteringTouch fill" role="button" assetpath="polymer/bower_components/paper-button/">
|
||
|
||
<template>
|
||
|
||
<style>
|
||
|
||
:host {
|
||
display: inline-block;
|
||
position: relative;
|
||
box-sizing: border-box;
|
||
min-width: 5.14em;
|
||
padding: 0.7em 0.57em;
|
||
margin: 0 0.29em;
|
||
background: transparent;
|
||
text-align: center;
|
||
font: inherit;
|
||
text-transform: uppercase;
|
||
outline: none;
|
||
border-radius: 3px;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
cursor: pointer;
|
||
z-index: 0;
|
||
}
|
||
|
||
:host([disabled]) {
|
||
background: #eaeaea !important;
|
||
color: #a8a8a8 !important;
|
||
cursor: auto;
|
||
pointer-events: none;
|
||
}
|
||
|
||
::content * {
|
||
text-transform: inherit;
|
||
}
|
||
|
||
#ripple {
|
||
pointer-events: none;
|
||
z-index: -1;
|
||
}
|
||
|
||
</style>
|
||
|
||
<template if="{{raisedButton || raised}}">
|
||
<paper-shadow id="shadow" z="{{z}}" animated=""></paper-shadow>
|
||
</template>
|
||
|
||
<!-- this div is needed to position the ripple behind text content -->
|
||
<div relative="">
|
||
<content></content>
|
||
{{label}}
|
||
</div>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
Polymer('paper-button',{
|
||
|
||
publish: {
|
||
|
||
label: '',
|
||
|
||
/**
|
||
* If true, the button will be styled with a shadow.
|
||
*
|
||
* @attribute raised
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
raised: false,
|
||
raisedButton: false,
|
||
|
||
/**
|
||
* By default the ripple emanates from where the user touched the button.
|
||
* Set this to true to always center the ripple.
|
||
*
|
||
* @attribute recenteringTouch
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
recenteringTouch: false,
|
||
|
||
/**
|
||
* By default the ripple expands to fill the button. Set this to true to
|
||
* constrain the ripple to a circle within the button.
|
||
*
|
||
* @attribute fill
|
||
* @type boolean
|
||
* @default true
|
||
*/
|
||
fill: true
|
||
|
||
},
|
||
|
||
labelChanged: function() {
|
||
if (this.label) {
|
||
console.warn('The "label" property is deprecated.');
|
||
}
|
||
},
|
||
|
||
raisedButtonChanged: function() {
|
||
if (this.raisedButton) {
|
||
console.warn('The "raisedButton" property is deprecated.');
|
||
}
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
</div>
|
||
<div hidden><!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
|
||
-->
|
||
|
||
<!--
|
||
`paper-input` is a single- or multi-line text field where user can enter input.
|
||
It can optionally have a label.
|
||
|
||
Example:
|
||
|
||
<paper-input label="Your Name"></paper-input>
|
||
<paper-input multiline label="Enter multiple lines here"></paper-input>
|
||
|
||
Theming
|
||
--------
|
||
|
||
Set `CoreStyle.g.paperInput.focusedColor` and `CoreStyle.g.paperInput.invalidColor` to theme
|
||
the focused and invalid states.
|
||
|
||
To add custom styling to only some elements, use these selectors:
|
||
|
||
html /deep/ paper-input[focused] .floated-label {
|
||
/* floating label color when the input has focus */
|
||
color: green;
|
||
}
|
||
|
||
html /deep/ paper-input .focused-underline,
|
||
html /deep/ paper-input .cursor {
|
||
/* line and cursor color when the input has focus */
|
||
background-color: green;
|
||
}
|
||
|
||
html /deep/ paper-input.invalid[focused] .floated-label,
|
||
html /deep/ paper-input[focused] .error-text,
|
||
html /deep/ paper-input[focused] .error-icon {
|
||
/* error text, icon, and floating label color when input is invalid */
|
||
color: salmon;
|
||
}
|
||
|
||
html /deep/ paper-input.invalid .focused-underline,
|
||
html /deep/ paper-input.invalid .cursor {
|
||
/* line and cursor color when the input is invalid */
|
||
background-color: salmon;
|
||
}
|
||
|
||
@group Paper Elements
|
||
@element paper-input
|
||
@extends core-input
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
/**
|
||
* @group Polymer Core Elements
|
||
*
|
||
* The `core-iconset-svg` element allows users to define their own icon sets
|
||
* that contain svg icons. The svg icon elements should be children of the
|
||
* `core-iconset-svg` element. Multiple icons should be given distinct id's.
|
||
*
|
||
* Using svg elements to create icons has a few advantages over traditional
|
||
* bitmap graphics like jpg or png. Icons that use svg are vector based so they
|
||
* are resolution independent and should look good on any device. They are
|
||
* stylable via css. Icons can be themed, colorized, and even animated.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-iconset-svg id="my-svg-icons" iconSize="24">
|
||
* <svg>
|
||
* <defs>
|
||
* <g id="shape">
|
||
* <rect x="50" y="50" width="50" height="50" />
|
||
* <circle cx="50" cy="50" r="50" />
|
||
* </g>
|
||
* </defs>
|
||
* </svg>
|
||
* </core-iconset-svg>
|
||
*
|
||
* This will automatically register the icon set "my-svg-icons" to the iconset
|
||
* database. To use these icons from within another element, make a
|
||
* `core-iconset` element and call the `byId` method
|
||
* to retrieve a given iconset. To apply a particular icon inside an
|
||
* element use the `applyIcon` method. For example:
|
||
*
|
||
* iconset.applyIcon(iconNode, 'car');
|
||
*
|
||
* @element core-iconset-svg
|
||
* @extends core-meta
|
||
* @homepage github.io
|
||
*/
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-iconset-svg" extends="core-meta" attributes="iconSize" assetpath="polymer/bower_components/core-iconset-svg/">
|
||
|
||
<script>
|
||
|
||
Polymer('core-iconset-svg', {
|
||
|
||
|
||
/**
|
||
* The size of an individual icon. Note that icons must be square.
|
||
*
|
||
* @attribute iconSize
|
||
* @type number
|
||
* @default 24
|
||
*/
|
||
iconSize: 24,
|
||
type: 'iconset',
|
||
|
||
created: function() {
|
||
this._icons = {};
|
||
},
|
||
|
||
ready: function() {
|
||
this.super();
|
||
this.updateIcons();
|
||
},
|
||
|
||
iconById: function(id) {
|
||
return this._icons[id] || (this._icons[id] = this.querySelector('#' + id));
|
||
},
|
||
|
||
cloneIcon: function(id) {
|
||
var icon = this.iconById(id);
|
||
if (icon) {
|
||
var content = icon.cloneNode(true);
|
||
content.removeAttribute('id');
|
||
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||
svg.setAttribute('viewBox', '0 0 ' + this.iconSize + ' ' +
|
||
this.iconSize);
|
||
// NOTE(dfreedm): work around https://crbug.com/370136
|
||
svg.style.pointerEvents = 'none';
|
||
svg.appendChild(content);
|
||
return svg;
|
||
}
|
||
},
|
||
|
||
get iconNames() {
|
||
if (!this._iconNames) {
|
||
this._iconNames = this.findIconNames();
|
||
}
|
||
return this._iconNames;
|
||
},
|
||
|
||
findIconNames: function() {
|
||
var icons = this.querySelectorAll('[id]').array();
|
||
if (icons.length) {
|
||
return icons.map(function(n){ return n.id });
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Applies an icon to the given element. The svg icon is added to the
|
||
* element's shadowRoot if one exists or directly to itself.
|
||
*
|
||
* @method applyIcon
|
||
* @param {Element} element The element to which the icon is
|
||
* applied.
|
||
* @param {String|Number} icon The name the icon to apply.
|
||
* @return {Element} The icon element
|
||
*/
|
||
applyIcon: function(element, icon) {
|
||
var root = element;
|
||
// remove old
|
||
var old = root.querySelector('svg');
|
||
if (old) {
|
||
old.remove();
|
||
}
|
||
// install new
|
||
var svg = this.cloneIcon(icon);
|
||
if (!svg) {
|
||
return;
|
||
}
|
||
svg.setAttribute('height', '100%');
|
||
svg.setAttribute('width', '100%');
|
||
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||
svg.style.display = 'block';
|
||
root.insertBefore(svg, root.firstElementChild);
|
||
return svg;
|
||
},
|
||
|
||
/**
|
||
* Tell users of the iconset, that the set has loaded.
|
||
* This finds all elements matching the selector argument and calls
|
||
* the method argument on them.
|
||
* @method updateIcons
|
||
* @param selector {string} css selector to identify iconset users,
|
||
* defaults to '[icon]'
|
||
* @param method {string} method to call on found elements,
|
||
* defaults to 'updateIcon'
|
||
*/
|
||
updateIcons: function(selector, method) {
|
||
selector = selector || '[icon]';
|
||
method = method || 'updateIcon';
|
||
var deep = window.ShadowDOMPolyfill ? '' : 'html /deep/ ';
|
||
var i$ = document.querySelectorAll(deep + selector);
|
||
for (var i=0, e; e=i$[i]; i++) {
|
||
if (e[method]) {
|
||
e[method].call(e);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
});
|
||
|
||
</script>
|
||
|
||
</polymer-element>
|
||
|
||
<core-iconset-svg id="icons" iconsize="24">
|
||
<svg><defs>
|
||
<g id="accessibility"><path d="M12,2c1.1,0,2,0.9,2,2s-0.9,2-2,2s-2-0.9-2-2S10.9,2,12,2z M21,9h-6v13h-2v-6h-2v6H9V9H3V7h18V9z"/></g>
|
||
<g id="account-balance"><path d="M4,10v7h3v-7H4z M10,10v7h3v-7H10z M2,22h19v-3H2V22z M16,10v7h3v-7H16z M11.5,1L2,6v2h19V6L11.5,1z"/></g>
|
||
<g id="account-box"><path d="M3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5z M15,9c0,1.7-1.3,3-3,3c-1.7,0-3-1.3-3-3c0-1.7,1.3-3,3-3C13.7,6,15,7.3,15,9z M6,17c0-2,4-3.1,6-3.1s6,1.1,6,3.1v1H6V17z"/></g>
|
||
<g id="account-child"><path d="M16.5,12c1.4,0,2.5-1.1,2.5-2.5C19,8.1,17.9,7,16.5,7C15.1,7,14,8.1,14,9.5C14,10.9,15.1,12,16.5,12z M9,11c1.7,0,3-1.3,3-3s-1.3-3-3-3C7.3,5,6,6.3,6,8S7.3,11,9,11z M16.5,14c-1.8,0-5.5,0.9-5.5,2.7V19h11v-2.2C22,14.9,18.3,14,16.5,14z M9,13c-2.3,0-7,1.2-7,3.5V19h7v-2.2c0-0.8,0.3-2.3,2.4-3.5C10.5,13.1,9.7,13,9,13z"/></g>
|
||
<g id="account-circle"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,5c1.7,0,3,1.3,3,3c0,1.7-1.3,3-3,3c-1.7,0-3-1.3-3-3C9,6.3,10.3,5,12,5z M12,19.2c-2.5,0-4.7-1.3-6-3.2c0-2,4-3.1,6-3.1c2,0,6,1.1,6,3.1C16.7,17.9,14.5,19.2,12,19.2z"/></g>
|
||
<g id="add"><path d="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6V13z"/></g>
|
||
<g id="add-box"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M17,13h-4v4h-2v-4H7v-2h4V7h2v4h4V13z"/></g>
|
||
<g id="add-circle"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M17,13h-4v4h-2v-4H7v-2h4V7h2v4h4V13z"/></g>
|
||
<g id="add-circle-outline"><path d="M13,7h-2v4H7v2h4v4h2v-4h4v-2h-4V7z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="add-shopping-cart"><polygon points="18.3,6 18.3,6 15.6,11 "/></g>
|
||
<g id="alarm"><path d="M22,5.7l-4.6-3.9l-1.3,1.5l4.6,3.9L22,5.7z M7.9,3.4L6.6,1.9L2,5.7l1.3,1.5L7.9,3.4z M12.5,8H11v6l4.7,2.9l0.8-1.2l-4-2.4V8z M12,4c-5,0-9,4-9,9c0,5,4,9,9,9c5,0,9-4,9-9C21,8,17,4,12,4z M12,20c-3.9,0-7-3.1-7-7c0-3.9,3.1-7,7-7c3.9,0,7,3.1,7,7C19,16.9,15.9,20,12,20z"/></g>
|
||
<g id="alarm-add"><path d="M7.9,3.4L6.6,1.9L2,5.7l1.3,1.5L7.9,3.4z M22,5.7l-4.6-3.9l-1.3,1.5l4.6,3.9L22,5.7z M12,4c-5,0-9,4-9,9c0,5,4,9,9,9c5,0,9-4,9-9C21,8,17,4,12,4z M12,20c-3.9,0-7-3.1-7-7c0-3.9,3.1-7,7-7c3.9,0,7,3.1,7,7C19,16.9,15.9,20,12,20z M13,9h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"/></g>
|
||
<g id="alarm-off"><path d="M12,6c3.9,0,7,3.1,7,7c0,0.8-0.2,1.6-0.4,2.4l1.5,1.5c0.6-1.2,0.9-2.5,0.9-3.9c0-5-4-9-9-9c-1.4,0-2.7,0.3-3.9,0.9l1.5,1.5C10.4,6.2,11.2,6,12,6z M22,5.7l-4.6-3.9l-1.3,1.5l4.6,3.9L22,5.7z M2.9,2.3L1.6,3.6L3,4.9L1.9,5.8l1.4,1.4l1.1-0.9l0.8,0.8C3.8,8.7,3,10.7,3,13c0,5,4,9,9,9c2.3,0,4.3-0.8,5.9-2.2l2.2,2.2l1.3-1.3L3.9,3.3L2.9,2.3z M16.5,18.4c-1.2,1-2.8,1.6-4.5,1.6c-3.9,0-7-3.1-7-7c0-1.7,0.6-3.3,1.6-4.5L16.5,18.4z M8,3.3L6.6,1.9L5.7,2.6L7.2,4L8,3.3z"/></g>
|
||
<g id="alarm-on"><path d="M22,5.7l-4.6-3.9l-1.3,1.5l4.6,3.9L22,5.7z M7.9,3.4L6.6,1.9L2,5.7l1.3,1.5L7.9,3.4z M12,4c-5,0-9,4-9,9c0,5,4,9,9,9c5,0,9-4,9-9C21,8,17,4,12,4z M12,20c-3.9,0-7-3.1-7-7c0-3.9,3.1-7,7-7s7,3.1,7,7C19,16.9,15.9,20,12,20z M10.5,14.5l-2.1-2.1l-1.1,1.1l3.2,3.2l6-6l-1.1-1.1L10.5,14.5z"/></g>
|
||
<g id="android"><path d="M6,18c0,0.6,0.4,1,1,1h1v3.5C8,23.3,8.7,24,9.5,24c0.8,0,1.5-0.7,1.5-1.5V19h2v3.5c0,0.8,0.7,1.5,1.5,1.5c0.8,0,1.5-0.7,1.5-1.5V19h1c0.6,0,1-0.4,1-1V8H6V18z M3.5,8C2.7,8,2,8.7,2,9.5v7C2,17.3,2.7,18,3.5,18C4.3,18,5,17.3,5,16.5v-7C5,8.7,4.3,8,3.5,8z M20.5,8C19.7,8,19,8.7,19,9.5v7c0,0.8,0.7,1.5,1.5,1.5c0.8,0,1.5-0.7,1.5-1.5v-7C22,8.7,21.3,8,20.5,8z M15.5,2.2l1.3-1.3c0.2-0.2,0.2-0.5,0-0.7c-0.2-0.2-0.5-0.2-0.7,0l-1.5,1.5C13.9,1.2,13,1,12,1c-1,0-1.9,0.2-2.7,0.6L7.9,0.1C7.7,0,7.3,0,7.1,0.1C7,0.3,7,0.7,7.1,0.9l1.3,1.3C7,3.3,6,5,6,7h12C18,5,17,3.2,15.5,2.2z M10,5H9V4h1V5z M15,5h-1V4h1V5z"/></g>
|
||
<g id="announcement"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,18l4-4h14c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M13,11h-2V5h2V11z M13,15h-2v-2h2V15z"/></g>
|
||
<g id="apps"><path d="M4,8h4V4H4V8z M10,20h4v-4h-4V20z M4,20h4v-4H4V20z M4,14h4v-4H4V14z M10,14h4v-4h-4V14z M16,4v4h4V4H16z M10,8h4V4h-4V8z M16,14h4v-4h-4V14z M16,20h4v-4h-4V20z"/></g>
|
||
<g id="archive"><path d="M20.5,5.2l-1.4-1.7C18.9,3.2,18.5,3,18,3H6C5.5,3,5.1,3.2,4.8,3.5L3.5,5.2C3.2,5.6,3,6,3,6.5V19c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V6.5C21,6,20.8,5.6,20.5,5.2z M12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5z M5.1,5l0.8-1h12l0.9,1H5.1z"/></g>
|
||
<g id="arrow-back"><path d="M20,11H7.8l5.6-5.6L12,4l-8,8l8,8l1.4-1.4L7.8,13H20V11z"/></g>
|
||
<g id="arrow-drop-down"><polygon points="7,10 12,15 17,10 "/></g>
|
||
<g id="arrow-drop-down-circle"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,14l-4-4h8L12,14z"/></g>
|
||
<g id="arrow-drop-up"><polygon points="7,14 12,9 17,14 "/></g>
|
||
<g id="arrow-forward"><polygon points="12,4 10.6,5.4 16.2,11 4,11 4,13 16.2,13 10.6,18.6 12,20 20,12 "/></g>
|
||
<g id="aspect-ratio"><path d="M19,12h-2v3h-3v2h5V12z M7,9h3V7H5v5h2V9z M21,3H3C1.9,3,1,3.9,1,5v14c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z M21,19H3V5h18V19z"/></g>
|
||
<g id="assessment"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M9,17H7v-7h2V17z M13,17h-2V7h2V17z M17,17h-2v-4h2V17z"/></g>
|
||
<g id="assignment"><path d="M19,3h-4.2c-0.4-1.2-1.5-2-2.8-2c-1.3,0-2.4,0.8-2.8,2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,3c0.6,0,1,0.4,1,1s-0.4,1-1,1s-1-0.4-1-1S11.4,3,12,3z M14,17H7v-2h7V17z M17,13H7v-2h10V13z M17,9H7V7h10V9z"/></g>
|
||
<g id="assignment-ind"><path d="M19,3h-4.2c-0.4-1.2-1.5-2-2.8-2c-1.3,0-2.4,0.8-2.8,2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,3c0.6,0,1,0.4,1,1s-0.4,1-1,1s-1-0.4-1-1S11.4,3,12,3z M12,7c1.7,0,3,1.3,3,3c0,1.7-1.3,3-3,3c-1.7,0-3-1.3-3-3C9,8.3,10.3,7,12,7z M18,19H6v-1.4c0-2,4-3.1,6-3.1s6,1.1,6,3.1V19z"/></g>
|
||
<g id="assignment-late"><path d="M19,3h-4.2c-0.4-1.2-1.5-2-2.8-2c-1.3,0-2.4,0.8-2.8,2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,3c0.6,0,1,0.4,1,1s-0.4,1-1,1s-1-0.4-1-1S11.4,3,12,3z M17,15.6L15.6,17L12,13.4L8.4,17L7,15.6l3.6-3.6L7,8.4L8.4,7l3.6,3.6L15.6,7L17,8.4L13.4,12L17,15.6z"/></g>
|
||
<g id="assignment-return"><path d="M19,3h-4.2c-0.4-1.2-1.5-2-2.8-2c-1.3,0-2.4,0.8-2.8,2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,3c0.6,0,1,0.4,1,1s-0.4,1-1,1c-0.6,0-1-0.4-1-1S11.4,3,12,3z M16,15h-4v3l-5-5l5-5v3h4V15z"/></g>
|
||
<g id="assignment-returned"><path d="M19,3h-4.2c-0.4-1.2-1.5-2-2.8-2c-1.3,0-2.4,0.8-2.8,2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,3c0.6,0,1,0.4,1,1s-0.4,1-1,1s-1-0.4-1-1S11.4,3,12,3z M12,18l-5-5h3V9h4v4h3L12,18z"/></g>
|
||
<g id="attachment"><path d="M7.5,18c-3,0-5.5-2.5-5.5-5.5S4.5,7,7.5,7H18c2.2,0,4,1.8,4,4s-1.8,4-4,4H9.5C8.1,15,7,13.9,7,12.5S8.1,10,9.5,10H17v1.5H9.5c-0.6,0-1,0.4-1,1s0.4,1,1,1H18c1.4,0,2.5-1.1,2.5-2.5S19.4,8.5,18,8.5H7.5c-2.2,0-4,1.8-4,4s1.8,4,4,4H17V18H7.5z"/></g>
|
||
<g id="backspace"><path d="M22,3H7C6.3,3,5.8,3.3,5.4,3.9L0,12l5.4,8.1C5.8,20.6,6.3,21,7,21h15c1.1,0,2-0.9,2-2V5C24,3.9,23.1,3,22,3z M19,15.6L17.6,17L14,13.4L10.4,17L9,15.6l3.6-3.6L9,8.4L10.4,7l3.6,3.6L17.6,7L19,8.4L15.4,12L19,15.6z"/></g>
|
||
<g id="backup"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z M14,13v4h-4v-4H7l5-5l5,5H14z"/></g>
|
||
<g id="block"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M4,12c0-4.4,3.6-8,8-8c1.8,0,3.5,0.6,4.9,1.7L5.7,16.9C4.6,15.5,4,13.8,4,12z M12,20c-1.8,0-3.5-0.6-4.9-1.7L18.3,7.1C19.4,8.5,20,10.2,20,12C20,16.4,16.4,20,12,20z"/></g>
|
||
<g id="book"><path d="M18,2H6C4.9,2,4,2.9,4,4v16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2z M6,4h5v8l-2.5-1.5L6,12V4z"/></g>
|
||
<g id="bookmark"><path d="M17,3H7C5.9,3,5,3.9,5,5l0,16l7-3l7,3V5C19,3.9,18.1,3,17,3z"/></g>
|
||
<g id="bookmark-outline"><path d="M17,3H7C5.9,3,5,3.9,5,5l0,16l7-3l7,3V5C19,3.9,18.1,3,17,3z M17,18l-5-2.2L7,18V5h10V18z"/></g>
|
||
<g id="bug-report"><path d="M20,8h-2.8c-0.5-0.8-1.1-1.5-1.8-2L17,4.4L15.6,3l-2.2,2.2C13,5.1,12.5,5,12,5s-1,0.1-1.4,0.2L8.4,3L7,4.4L8.6,6C7.9,6.5,7.3,7.2,6.8,8H4v2h2.1C6,10.3,6,10.7,6,11v1H4v2h2v1c0,0.3,0,0.7,0.1,1H4v2h2.8c1,1.8,3,3,5.2,3s4.2-1.2,5.2-3H20v-2h-2.1c0.1-0.3,0.1-0.7,0.1-1v-1h2v-2h-2v-1c0-0.3,0-0.7-0.1-1H20V8z M14,16h-4v-2h4V16z M14,12h-4v-2h4V12z"/></g>
|
||
<g id="cached"><path d="M19,8l-4,4h3c0,3.3-2.7,6-6,6c-1,0-2-0.3-2.8-0.7l-1.5,1.5C9,19.5,10.4,20,12,20c4.4,0,8-3.6,8-8h3L19,8z M6,12c0-3.3,2.7-6,6-6c1,0,2,0.3,2.8,0.7l1.5-1.5C15,4.5,13.6,4,12,4c-4.4,0-8,3.6-8,8H1l4,4l4-4H6z"/></g>
|
||
<g id="cancel"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M17,15.6L15.6,17L12,13.4L8.4,17L7,15.6l3.6-3.6L7,8.4L8.4,7l3.6,3.6L15.6,7L17,8.4L13.4,12L17,15.6z"/></g>
|
||
<g id="check"><polygon points="9,16.2 4.8,12 3.4,13.4 9,19 21,7 19.6,5.6 "/></g>
|
||
<g id="check-box"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M10,17l-5-5l1.4-1.4l3.6,3.6l7.6-7.6L19,8L10,17z"/></g>
|
||
<g id="check-box-blank"><path d="M19,3H5C3.9,3,3,3.9,3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z"/></g>
|
||
<g id="check-box-outline"><path d="M7.9,10.1l-1.4,1.4L11,16L21,6l-1.4-1.4L11,13.2L7.9,10.1z M19,19L5,19V5h10V3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2v-8h-2V19z"/></g>
|
||
<g id="check-box-outline-blank"><path d="M19,5v14L5,19V5H19 M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3L19,3z"/></g>
|
||
<g id="check-circle"><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M10,17l-5-5l1.4-1.4l3.6,3.6l7.6-7.6L19,8L10,17z"/></g>
|
||
<g id="check-circle-blank"><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z"/></g>
|
||
<g id="check-circle-outline"><path d="M7.9,10.1l-1.4,1.4L11,16L21,6l-1.4-1.4L11,13.2L7.9,10.1z M20,12c0,4.4-3.6,8-8,8s-8-3.6-8-8s3.6-8,8-8c0.8,0,1.5,0.1,2.2,0.3l1.6-1.6C14.6,2.3,13.3,2,12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10H20z"/></g>
|
||
<g id="check-circle-outline-blank"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="chevron-left"><polygon points="15.4,7.4 14,6 8,12 14,18 15.4,16.6 10.8,12 "/></g>
|
||
<g id="chevron-right"><polygon points="10,6 8.6,7.4 13.2,12 8.6,16.6 10,18 16,12 "/></g>
|
||
<g id="class"><path d="M18,2H6C4.9,2,4,2.9,4,4v16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2z M6,4h5v8l-2.5-1.5L6,12V4z"/></g>
|
||
<g id="clear"><polygon points="19,6.4 17.6,5 12,10.6 6.4,5 5,6.4 10.6,12 5,17.6 6.4,19 12,13.4 17.6,19 19,17.6 13.4,12 "/></g>
|
||
<g id="close"><polygon points="19,6.4 17.6,5 12,10.6 6.4,5 5,6.4 10.6,12 5,17.6 6.4,19 12,13.4 17.6,19 19,17.6 13.4,12 "/></g>
|
||
<g id="cloud"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z"/></g>
|
||
<g id="cloud-circle"><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M16.5,16c0,0-8.5,0-8.5,0c-1.7,0-3-1.3-3-3s1.3-3,3-3c0,0,0.1,0,0.1,0c0.4-1.7,2-3,3.9-3c2.2,0,4,1.8,4,4h0.5c1.4,0,2.5,1.1,2.5,2.5C19,14.9,17.9,16,16.5,16z"/></g>
|
||
<g id="cloud-done"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z M10,17l-3.5-3.5l1.4-1.4l2.1,2.1L15.2,9l1.4,1.4L10,17z"/></g>
|
||
<g id="cloud-download"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z M17,13l-5,5l-5-5h3V9h4v4H17z"/></g>
|
||
<g id="cloud-off"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6c-1.5,0-2.9,0.4-4,1.2l1.5,1.5C10.2,6.2,11.1,6,12,6c3,0,5.5,2.5,5.5,5.5V12H19c1.7,0,3,1.3,3,3c0,1.1-0.6,2.1-1.6,2.6l1.5,1.5c1.3-0.9,2.1-2.4,2.1-4.1C24,12.4,21.9,10.2,19.4,10z M3,5.3L5.8,8C2.6,8.2,0,10.8,0,14c0,3.3,2.7,6,6,6h11.7l2,2l1.3-1.3L4.3,4L3,5.3z M7.7,10l8,8H6c-2.2,0-4-1.8-4-4c0-2.2,1.8-4,4-4H7.7z"/></g>
|
||
<g id="cloud-queue"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z M19,18H6c-2.2,0-4-1.8-4-4c0-2.2,1.8-4,4-4h0.7C7.4,7.7,9.5,6,12,6c3,0,5.5,2.5,5.5,5.5V12H19c1.7,0,3,1.3,3,3S20.7,18,19,18z"/></g>
|
||
<g id="cloud-upload"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z M14,13v4h-4v-4H7l5-5l5,5H14z"/></g>
|
||
<g id="content-copy"><path d="M16,1H4C2.9,1,2,1.9,2,3v14h2V3h12V1z M19,5H8C6.9,5,6,5.9,6,7v14c0,1.1,0.9,2,2,2h11c1.1,0,2-0.9,2-2V7C21,5.9,20.1,5,19,5z M19,21H8V7h11V21z"/></g>
|
||
<g id="content-cut"><path d="M10,6c0-2.2-1.8-4-4-4S2,3.8,2,6c0,2.2,1.8,4,4,4c0.6,0,1.1-0.1,1.6-0.4L10,12l-2.4,2.4C7.1,14.1,6.6,14,6,14c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4s4-1.8,4-4c0-0.6-0.1-1.1-0.4-1.6L12,14l7,7h4L9.6,7.6C9.9,7.1,10,6.6,10,6z M6,8C4.9,8,4,7.1,4,6s0.9-2,2-2c1.1,0,2,0.9,2,2S7.1,8,6,8z M6,20c-1.1,0-2-0.9-2-2s0.9-2,2-2c1.1,0,2,0.9,2,2S7.1,20,6,20z M12,11.5c0.3,0,0.5,0.2,0.5,0.5c0,0.3-0.2,0.5-0.5,0.5c-0.3,0-0.5-0.2-0.5-0.5C11.5,11.7,11.7,11.5,12,11.5z M23,3h-4l-6,6l2,2L23,3z"/></g>
|
||
<g id="content-paste"><path d="M19,2h-4.2c-0.4-1.2-1.5-2-2.8-2c-1.3,0-2.4,0.8-2.8,2H5C3.9,2,3,2.9,3,4v16c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V4C21,2.9,20.1,2,19,2z M12,2c0.6,0,1,0.4,1,1s-0.4,1-1,1c-0.6,0-1-0.4-1-1S11.4,2,12,2z M19,20H5V4h2v3h10V4h2V20z"/></g>
|
||
<g id="create"><path d="M3,17.2V21h3.8L17.8,9.9l-3.8-3.8L3,17.2z M20.7,7c0.4-0.4,0.4-1,0-1.4l-2.3-2.3c-0.4-0.4-1-0.4-1.4,0l-1.8,1.8l3.8,3.8L20.7,7z"/></g>
|
||
<g id="credit-card"><path d="M20,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18H4v-6h16V18z M20,8H4V6h16V8z"/></g>
|
||
<g id="delete"><path d="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z M19,4h-3.5l-1-1h-5l-1,1H5v2h14V4z"/></g>
|
||
<g id="description"><path d="M14,2H6C4.9,2,4,2.9,4,4l0,16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V8L14,2z M16,18H8v-2h8V18z M16,14H8v-2h8V14z M13,9V3.5L18.5,9H13z"/></g>
|
||
<g id="developer-mode-tv"><path d="M4,5h16v2h2l0-2c0-1.1-0.9-2-2-2H4C2.9,3,2,3.9,2,5v2h2V5z M7.6,13.8L4.7,11l2.8-2.8L6.1,6.8L1.9,11l4.2,4.2L7.6,13.8z M20,17H4v-2H2v2c0,1.1,0.9,2,2,2h4v2h8v-2h4c1.1,0,2-0.9,2-2l0-2h-2V17z M22,11l-4.2-4.2l-1.4,1.4l2.8,2.8l-2.8,2.8l1.4,1.4L22,11L22,11L22,11L22,11L22,11z"/></g>
|
||
<g id="done"><polygon points="9,16.2 4.8,12 3.4,13.4 9,19 21,7 19.6,5.6 "/></g>
|
||
<g id="done-all"><path d="M18,7l-1.4-1.4l-6.3,6.3l1.4,1.4L18,7z M22.2,5.6L11.7,16.2L7.5,12l-1.4,1.4l5.6,5.6l12-12L22.2,5.6z M0.4,13.4L6,19l1.4-1.4L1.8,12L0.4,13.4z"/></g>
|
||
<g id="drafts"><path d="M22,8c0-0.7-0.4-1.3-0.9-1.7L12,1L2.9,6.3C2.4,6.7,2,7.3,2,8v10c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2L22,8z M12,13L3.7,7.8L12,3l8.3,4.8L12,13z"/></g>
|
||
<g id="drawer"><path d="M12,8c1.1,0,2-0.9,2-2s-0.9-2-2-2c-1.1,0-2,0.9-2,2S10.9,8,12,8z M12,10c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S13.1,10,12,10z M12,16c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S13.1,16,12,16z"/></g>
|
||
<g id="drive"><path d="M22.3,14L15.4,2H8.6l0,0l6.9,12H22.3z M9.7,15l-3.4,6h13.1l3.4-6H9.7z M7.7,3.5L1.2,15l3.4,6l6.6-11.5L7.7,3.5z"/></g>
|
||
<g id="drive-archive"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,18l-4-4h8L12,18z M16,12H8v-2h8V12z M16,8H8V6h8V8z"/></g>
|
||
<g id="drive-audio"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M7.2,18C6.5,18,6,17.5,6,16.8v-3.6V12c0-3.3,2.7-6,6-6s6,2.7,6,6v1.2v3.6c0,0.7-0.5,1.2-1.2,1.2H14v-4h2v-2c0-2.2-1.8-4-4-4s-4,1.8-4,4v2h2v4H7.2z"/></g>
|
||
<g id="drive-chart"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M9,17H7v-7h2V17z M13,17h-2V7h2V17z M17,17h-2v-4h2V17z"/></g>
|
||
<g id="drive-document"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M17,9H7V7h10V9z M17,13H7v-2h10V13z M14,17H7v-2h7V17z"/></g>
|
||
<g id="drive-drawing"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M18,18h-6v-5.8c-0.7,0.6-1.5,1-2.5,1c-2,0-3.7-1.7-3.7-3.7s1.7-3.7,3.7-3.7c2,0,3.7,1.7,3.7,3.7c0,1-0.4,1.8-1,2.5H18V18z"/></g>
|
||
<g id="drive-file"><path d="M6,2C4.9,2,4,2.9,4,4l0,16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V8l-6-6H6z M13,9V3.5L18.5,9H13z"/></g>
|
||
<g id="drive-file-move"><path d="M20,6h-8l-2-2H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M9,18v-3H5v-4h4V8l5,5L9,18z"/></g>
|
||
<g id="drive-file-rename"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M6,17v-2.5l7.9-7.9c0.2-0.2,0.5-0.2,0.7,0l1.8,1.8c0.2,0.2,0.2,0.5,0,0.7L8.5,17H6z M18,17h-7.5l2-2H18V17z"/></g>
|
||
<g id="drive-form"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M9,17H7v-2h2V17z M9,13H7v-2h2V13z M9,9H7V7h2V9z M17,17h-7v-2h7V17z M17,13h-7v-2h7V13z M17,9h-7V7h7V9z"/></g>
|
||
<g id="drive-fusiontable"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,10.2L13,17l-4-4l-4,4v-3l4-4l4,4l6-6.8V10.2z"/></g>
|
||
<g id="drive-image"><path d="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5L8.5,13.5z"/></g>
|
||
<g id="drive-keep"><path d="M9,21c0,0.6,0.4,1,1,1h4c0.6,0,1-0.4,1-1v-1H9V21z M12,2C8.1,2,5,5.1,5,9c0,2.4,1.2,4.5,3,5.7V17c0,0.6,0.4,1,1,1h6c0.6,0,1-0.4,1-1v-2.3c1.8-1.3,3-3.4,3-5.7C19,5.1,15.9,2,12,2z"/></g>
|
||
<g id="drive-ms-excel"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M16.2,17h-2L12,13.2L9.8,17h-2l3.2-5L7.8,7h2l2.2,3.8L14.2,7h2L13,12L16.2,17z"/></g>
|
||
<g id="drive-ms-powerpoint"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M9.8,13.4V17H8V7h4.3c1.5,0,2.2,0.3,2.8,0.9c0.7,0.6,0.9,1.4,0.9,2.3c0,1-0.3,1.8-0.9,2.3c-0.6,0.5-1.3,0.8-2.8,0.8H9.8z"/><path d="M9.8,12V8.4h2.3c0.7,0,1.2,0.2,1.5,0.6c0.3,0.4,0.5,0.7,0.5,1.2c0,0.6-0.2,0.9-0.5,1.3c-0.3,0.3-0.7,0.5-1.4,0.5H9.8z"/></g>
|
||
<g id="drive-ms-word"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M15.5,17H14l-2-7.5L10,17H8.5L6.1,7h1.7l1.5,7.5l2-7.5h1.4l2,7.5L16.2,7h1.7L15.5,17z"/></g>
|
||
<g id="drive-pdf"><path d="M11.3,8.6L11.3,8.6C11.4,8.6,11.4,8.6,11.3,8.6c0.1-0.4,0.2-0.6,0.2-0.9l0-0.2c0.1-0.5,0.1-0.9,0-1c0,0,0,0,0-0.1l-0.1-0.1c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0.1-0.1,0.1C11.1,7,11.1,7.7,11.3,8.6C11.3,8.6,11.3,8.6,11.3,8.6z M8.3,15.5c-0.2,0.1-0.4,0.2-0.5,0.3c-0.7,0.6-1.2,1.3-1.3,1.6c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0,0,0C7.1,17.3,7.7,16.7,8.3,15.5C8.4,15.5,8.4,15.5,8.3,15.5C8.4,15.5,8.3,15.5,8.3,15.5z M17.5,14c-0.1-0.1-0.5-0.4-1.9-0.4c-0.1,0-0.1,0-0.2,0c0,0,0,0,0,0c0,0,0,0,0,0.1c0.7,0.3,1.4,0.5,1.9,0.5c0.1,0,0.1,0,0.2,0l0,0c0,0,0.1,0,0.1,0c0,0,0,0,0-0.1c0,0,0,0,0,0C17.6,14.1,17.5,14.1,17.5,14z M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M17.9,14.8C17.7,14.9,17.4,15,17,15c-0.8,0-2-0.2-3-0.7c-1.7,0.2-3,0.4-4,0.8c-0.1,0-0.1,0-0.2,0.1c-1.2,2.1-2.2,3.1-3,3.1c-0.2,0-0.3,0-0.4-0.1l-0.5-0.3l0-0.1c-0.1-0.2-0.1-0.3-0.1-0.5c0.1-0.5,0.7-1.4,1.9-2.1c0.2-0.1,0.5-0.3,0.9-0.5c0.3-0.5,0.6-1.1,1-1.8c0.5-1,0.8-2,1.1-2.9l0,0c-0.4-1.2-0.6-1.9-0.2-3.3c0.1-0.4,0.4-0.8,0.8-0.8l0.2,0c0.2,0,0.4,0.1,0.6,0.2c0.7,0.7,0.4,2.3,0,3.6c0,0.1,0,0.1,0,0.1c0.4,1.1,1,2,1.6,2.6c0.3,0.2,0.5,0.4,0.9,0.6c0.5,0,0.9-0.1,1.3-0.1c1.2,0,2,0.2,2.3,0.7c0.1,0.2,0.1,0.4,0.1,0.6C18.2,14.3,18.1,14.6,17.9,14.8z M11.4,10.9c-0.2,0.7-0.6,1.5-1,2.4c-0.2,0.4-0.4,0.7-0.6,1.1c0,0,0.1,0,0.1,0l0.1,0v0c1.3-0.5,2.5-0.8,3.3-0.9c-0.2-0.1-0.3-0.2-0.4-0.3C12.4,12.6,11.8,11.8,11.4,10.9z"/></g>
|
||
<g id="drive-presentation"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,16H5V8h14V16z"/></g>
|
||
<g id="drive-script"><path d="M19,3H5C3.9,3,3,3.9,3,5l0,4h0v6h0l0,4c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M11,17v-3H5v-4h6V7l5,5L11,17z"/></g>
|
||
<g id="drive-site"><path d="M19,4H5C3.9,4,3,4.9,3,6l0,12c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V6C21,4.9,20.1,4,19,4z M14,18H5v-4h9V18z M14,13H5V9h9V13z M19,18h-4V9h4V18z"/></g>
|
||
<g id="drive-spreadsheet"><path d="M19,3H5C3.9,3,3,3.9,3,5l0,3h0v11c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,11h-8v8H9v-8H5V9h4V5h2v4h8V11z"/></g>
|
||
<g id="drive-text"><path d="M14,2H6C4.9,2,4,2.9,4,4l0,16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V8L14,2z M16,18H8v-2h8V18z M16,14H8v-2h8V14z M13,9V3.5L18.5,9H13z"/></g>
|
||
<g id="drive-video"><path d="M18,4l2,4h-3l-2-4h-2l2,4h-3l-2-4H8l2,4H7L5,4H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4H18z"/></g>
|
||
<g id="drive-zip"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M14,9h-2v2h2v2h-2v-2h-2V9h2V7h-2V5h2v2h2V9z M14,17h-2v-2h-2v-2h2v2h2V17z"/></g>
|
||
<g id="due-date"><path d="M17,12h-5v5h5V12z M16,1v2H8V1H6v2H5C3.9,3,3,3.9,3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2h-1V1H16z M19,19H5V8h14V19z"/></g>
|
||
<g id="error"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z"/></g>
|
||
<g id="event"><path d="M17,12h-5v5h5V12z M16,1v2H8V1H6v2H5C3.9,3,3,3.9,3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2h-1V1H16z M19,19H5V8h14V19z"/></g>
|
||
<g id="exit-to-app"><path d="M10.1,15.6l1.4,1.4l5-5l-5-5l-1.4,1.4l2.6,2.6H3v2h9.7L10.1,15.6z M19,3H5C3.9,3,3,3.9,3,5v4h2V5h14v14H5v-4H3v4c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z"/></g>
|
||
<g id="expand-less"><polygon points="12,8 6,14 7.4,15.4 12,10.8 16.6,15.4 18,14 "/></g>
|
||
<g id="expand-more"><polygon points="16.6,8.6 12,13.2 7.4,8.6 6,10 12,16 18,10 "/></g>
|
||
<g id="explore"><path d="M12,10.9c-0.6,0-1.1,0.5-1.1,1.1s0.5,1.1,1.1,1.1c0.6,0,1.1-0.5,1.1-1.1S12.6,10.9,12,10.9z M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M14.2,14.2L6,18l3.8-8.2L18,6L14.2,14.2z"/></g>
|
||
<g id="extension"><path d="M20.5,11H19V7c0-1.1-0.9-2-2-2h-4V3.5C13,2.1,11.9,1,10.5,1C9.1,1,8,2.1,8,3.5V5H4C2.9,5,2,5.9,2,7l0,3.8h1.5c1.5,0,2.7,1.2,2.7,2.7S5,16.2,3.5,16.2H2L2,20c0,1.1,0.9,2,2,2h3.8v-1.5c0-1.5,1.2-2.7,2.7-2.7c1.5,0,2.7,1.2,2.7,2.7V22H17c1.1,0,2-0.9,2-2v-4h1.5c1.4,0,2.5-1.1,2.5-2.5S21.9,11,20.5,11z"/></g>
|
||
<g id="favorite"><path d="M12,21.4L10.6,20C5.4,15.4,2,12.3,2,8.5C2,5.4,4.4,3,7.5,3c1.7,0,3.4,0.8,4.5,2.1C13.1,3.8,14.8,3,16.5,3C19.6,3,22,5.4,22,8.5c0,3.8-3.4,6.9-8.6,11.5L12,21.4z"/></g>
|
||
<g id="favorite-outline"><path d="M16.5,3c-1.7,0-3.4,0.8-4.5,2.1C10.9,3.8,9.2,3,7.5,3C4.4,3,2,5.4,2,8.5c0,3.8,3.4,6.9,8.6,11.5l1.4,1.3l1.4-1.3c5.1-4.7,8.6-7.8,8.6-11.5C22,5.4,19.6,3,16.5,3z M12.1,18.6L12,18.6l-0.1-0.1C7.1,14.2,4,11.4,4,8.5C4,6.5,5.5,5,7.5,5c1.5,0,3,1,3.6,2.4h1.9C13.5,6,15,5,16.5,5c2,0,3.5,1.5,3.5,3.5C20,11.4,16.9,14.2,12.1,18.6z"/></g>
|
||
<g id="file-download"><path d="M19,9h-4V3H9v6H5l7,7L19,9z M5,18v2h14v-2H5z"/></g>
|
||
<g id="file-map"><path d="M12,6.5c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5c0.8,0,1.5-0.7,1.5-1.5S12.8,6.5,12,6.5z M19,1H5C3.9,1,3,1.9,3,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C21,1.9,20.1,1,19,1z M12.5,17h-1c-1-4.1-4-5.8-4-9c0-2.5,2-4.5,4.5-4.5c2.5,0,4.5,2,4.5,4.5C16.5,11.2,13.5,12.9,12.5,17z"/></g>
|
||
<g id="file-upload"><polygon points="9,16 15,16 15,10 19,10 12,3 5,10 9,10 "/></g>
|
||
<g id="filter"><path d="M10,18h4v-2h-4V18z M3,6v2h18V6H3z M6,13h12v-2H6V13z"/></g>
|
||
<g id="flag"><polygon points="14.4,6 14,4 5,4 5,21 7,21 7,14 12.6,14 13,16 20,16 20,6 "/></g>
|
||
<g id="flip-to-back"><path d="M9,7H7l0,2h2V7z M9,11H7v2h2V11z M9,3C7.9,3,7,3.9,7,5h2V3z M13,15h-2v2h2V15z M19,3v2h2C21,3.9,20.1,3,19,3z M13,3h-2v2h2V3z M9,17v-2H7C7,16.1,7.9,17,9,17z M19,13h2v-2h-2V13z M19,9h2V7h-2V9z M19,17c1.1,0,2-0.9,2-2h-2V17z M5,7H3v2h0l0,10c0,1.1,0.9,2,2,2h12v-2H5V7z M15,5h2V3h-2V5z M15,17h2v-2h-2V17z"/></g>
|
||
<g id="flip-to-front"><path d="M3,13h2v-2H3L3,13z M3,17h2v-2H3V17z M5,21v-2H3C3,20.1,3.9,21,5,21z M3,9h2V7H3V9z M15,21h2v-2h-2V21z M19,3H9C7.9,3,7,3.9,7,5v2h0v2v6c0,1.1,0.9,2,2,2h5h4h1c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,15H9V5h10V15z M11,21h2v-2h-2V21z M7,21h2v-2H7V21z"/></g>
|
||
<g id="folder"><path d="M10,4H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8c0-1.1-0.9-2-2-2h-8L10,4z"/></g>
|
||
<g id="folder-mydrive"><path d="M20,6h-8l-2-2H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M11.5,17l-1.1-2.1l2.8-5l1.5,2.7L12.3,17H11.5z M18.3,17h-5.5l1.4-2.5h5.1l0.3,0.5L18.3,17z M13.8,9h2.4l2.8,5H16l-2.6-4.5L13.8,9z"/></g>
|
||
<g id="folder-open"><path d="M20,6h-8l-2-2H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M20,18H4V8h16V18z"/></g>
|
||
<g id="folder-shared"><path d="M20,6h-8l-2-2H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M15,9c1.1,0,2,0.9,2,2c0,1.1-0.9,2-2,2c-1.1,0-2-0.9-2-2C13,9.9,13.9,9,15,9z M19,17h-8v-1c0-1.3,2.7-2,4-2c1.3,0,4,0.7,4,2V17z"/></g>
|
||
<g id="forward"><polygon points="12,8 12,4 20,12 12,20 12,16 4,16 4,8 "/></g>
|
||
<g id="fullscreen"><path d="M7,14H5v5h5v-2H7V14z M5,10h2V7h3V5H5V10z M17,17h-3v2h5v-5h-2V17z M14,5v2h3v3h2V5H14z"/></g>
|
||
<g id="fullscreen-exit"><path d="M5,16h3v3h2v-5H5V16z M8,8H5v2h5V5H8V8z M14,19h2v-3h3v-2h-5V19z M16,8V5h-2v5h5V8H16z"/></g>
|
||
<g id="gesture"><path d="M4.6,6.9C5.3,6.2,6,5.5,6.3,5.7c0.5,0.2,0,1-0.3,1.5c-0.3,0.4-2.9,3.9-2.9,6.3c0,1.3,0.5,2.3,1.3,3c0.8,0.6,1.7,0.7,2.6,0.5c1.1-0.3,1.9-1.4,3.1-2.8c1.2-1.5,2.8-3.4,4.1-3.4c1.6,0,1.6,1,1.8,1.8c-3.8,0.6-5.4,3.7-5.4,5.4c0,1.7,1.4,3.1,3.2,3.1c1.6,0,4.3-1.3,4.7-6.1H21v-2.5h-2.5c-0.2-1.6-1.1-4.2-4-4.2c-2.2,0-4.2,1.9-4.9,2.8c-0.6,0.7-2.1,2.5-2.3,2.7c-0.3,0.3-0.7,0.8-1.1,0.8c-0.4,0-0.7-0.8-0.4-1.9c0.4-1.1,1.4-2.9,1.9-3.5C8.4,8,8.9,7.2,8.9,5.9C8.9,3.7,7.3,3,6.4,3C5.1,3,4,4,3.7,4.3C3.4,4.6,3.1,4.9,2.8,5.2L4.6,6.9z M13.9,18.6c-0.3,0-0.7-0.3-0.7-0.7c0-0.6,0.7-2.2,2.9-2.8C15.7,17.8,14.6,18.6,13.9,18.6z"/></g>
|
||
<g id="get-app"><path d="M19,9h-4V3H9v6H5l7,7L19,9z M5,18v2h14v-2H5z"/></g>
|
||
<g id="google"><path d="M16.3,13.4l-1.1-0.8c-0.4-0.3-0.8-0.7-0.8-1.4c0-0.7,0.5-1.3,1-1.6c1.3-1,2.6-2.1,2.6-4.3c0-2.1-1.3-3.3-2-3.9h1.7L18.9,0h-6.2C8.3,0,6.1,2.8,6.1,5.8c0,2.3,1.8,4.8,5,4.8h0.8c-0.1,0.3-0.4,0.8-0.4,1.3c0,1,0.4,1.4,0.9,2c-1.4,0.1-4,0.4-5.9,1.6c-1.8,1.1-2.3,2.6-2.3,3.7c0,2.3,2.1,4.5,6.6,4.5c5.4,0,8-3,8-5.9C18.8,15.7,17.7,14.6,16.3,13.4z M8.7,4.3c0-2.2,1.3-3.2,2.7-3.2c2.6,0,4,3.5,4,5.5c0,2.6-2.1,3.1-2.9,3.1C10,9.7,8.7,6.6,8.7,4.3z M12.3,22.3c-3.3,0-5.4-1.5-5.4-3.7c0-2.2,2-2.9,2.6-3.2c1.3-0.4,3-0.5,3.3-0.5c0.3,0,0.5,0,0.7,0c2.4,1.7,3.4,2.4,3.4,4C16.9,20.8,15,22.3,12.3,22.3z"/></g>
|
||
<g id="google-plus"><path d="M21,10V7h-2v3h-3v2h3v3h2v-3h3v-2H21z M13.3,13.4l-1.1-0.8c-0.4-0.3-0.8-0.7-0.8-1.4c0-0.7,0.5-1.3,1-1.6c1.3-1,2.6-2.1,2.6-4.3c0-2.1-1.3-3.3-2-3.9h1.7L15.9,0H9.7C5.3,0,3.1,2.8,3.1,5.8c0,2.3,1.8,4.8,5,4.8h0.8c-0.1,0.3-0.4,0.8-0.4,1.3c0,1,0.4,1.4,0.9,2c-1.4,0.1-4,0.4-5.9,1.6c-1.8,1.1-2.3,2.6-2.3,3.7c0,2.3,2.1,4.5,6.6,4.5c5.4,0,8-3,8-5.9C15.8,15.7,14.7,14.6,13.3,13.4z M5.7,4.3c0-2.2,1.3-3.2,2.7-3.2c2.6,0,4,3.5,4,5.5c0,2.6-2.1,3.1-2.9,3.1C7,9.7,5.7,6.6,5.7,4.3z M9.3,22.3c-3.3,0-5.4-1.5-5.4-3.7c0-2.2,2-2.9,2.6-3.2c1.3-0.4,3-0.5,3.3-0.5c0.3,0,0.5,0,0.7,0c2.4,1.7,3.4,2.4,3.4,4C13.9,20.8,12,22.3,9.3,22.3z"/></g>
|
||
<g id="grade"><polygon points="12,17.3 18.2,21 16.5,14 22,9.2 14.8,8.6 12,2 9.2,8.6 2,9.2 7.5,14 5.8,21 "/></g>
|
||
<g id="group-work"><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M8,17.5c-1.4,0-2.5-1.1-2.5-2.5s1.1-2.5,2.5-2.5s2.5,1.1,2.5,2.5S9.4,17.5,8,17.5z M9.5,8c0-1.4,1.1-2.5,2.5-2.5s2.5,1.1,2.5,2.5s-1.1,2.5-2.5,2.5S9.5,9.4,9.5,8z M16,17.5c-1.4,0-2.5-1.1-2.5-2.5s1.1-2.5,2.5-2.5s2.5,1.1,2.5,2.5S17.4,17.5,16,17.5z"/></g>
|
||
<g id="help"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M13,19h-2v-2h2V19z M15.1,11.3l-0.9,0.9C13.4,12.9,13,13.5,13,15h-2v-0.5c0-1.1,0.4-2.1,1.2-2.8l1.2-1.3C13.8,10.1,14,9.6,14,9c0-1.1-0.9-2-2-2c-1.1,0-2,0.9-2,2H8c0-2.2,1.8-4,4-4c2.2,0,4,1.8,4,4C16,9.9,15.6,10.7,15.1,11.3z"/></g>
|
||
<g id="highlight-remove"><path d="M14.6,8L12,10.6L9.4,8L8,9.4l2.6,2.6L8,14.6L9.4,16l2.6-2.6l2.6,2.6l1.4-1.4L13.4,12L16,9.4L14.6,8z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="history"><path opacity="0.9" d="M13,3c-5,0-9,4-9,9H1l3.9,3.9c0,0,0,0.1,0.1,0.1l4-4H6c0-3.9,3.1-7,7-7c3.9,0,7,3.1,7,7s-3.1,7-7,7c-1.9,0-3.7-0.8-4.9-2.1l-1.4,1.4C8.3,20,10.5,21,13,21c5,0,9-4,9-9S18,3,13,3z M12,8v5l4.3,2.5l0.7-1.2l-3.5-2.1V8H12z"/></g>
|
||
<g id="home"><polygon points="10,20 10,14 14,14 14,20 19,20 19,12 22,12 12,3 2,12 5,12 5,20 "/></g>
|
||
<g id="https"><path d="M18,8h-1V6c0-2.8-2.2-5-5-5C9.2,1,7,3.2,7,6v2H6c-1.1,0-2,0.9-2,2v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V10C20,8.9,19.1,8,18,8z M12,17c-1.1,0-2-0.9-2-2s0.9-2,2-2c1.1,0,2,0.9,2,2S13.1,17,12,17z M15.1,8H8.9V6c0-1.7,1.4-3.1,3.1-3.1c1.7,0,3.1,1.4,3.1,3.1V8z"/></g>
|
||
<g id="inbox"><path d="M19,3H5C3.9,3,3,3.9,3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,15h-4c0,1.7-1.3,3-3,3c-1.7,0-3-1.3-3-3H5V5h14V15z M16,10h-2V7h-4v3H8l4,4L16,10z"/></g>
|
||
<g id="info"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M13,17h-2v-6h2V17z M13,9h-2V7h2V9z"/></g>
|
||
<g id="info-outline"><path d="M11,17h2v-6h-2V17z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z M11,9h2V7h-2V9z"/></g>
|
||
<g id="input"><path d="M21,3H3C1.9,3,1,3.9,1,5v4h2V5h18v14H3v-4H1v4c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z M11,16l4-4l-4-4v3H1v2h10V16z"/></g>
|
||
<g id="invert-colors"><path d="M17.7,7.9L12,2.3l0,0v0L6.3,7.9c-3.1,3.1-3.1,8.2,0,11.3c1.6,1.6,3.6,2.3,5.7,2.3c2,0,4.1-0.8,5.7-2.3C20.8,16.1,20.8,11.1,17.7,7.9z M12,19.6L12,19.6c-1.6,0-3.1-0.6-4.2-1.8C6.6,16.7,6,15.2,6,13.6c0-1.6,0.6-3.1,1.8-4.2L12,5.1L12,19.6z"/></g>
|
||
<g id="keep"><path d="M16,12V4h1V2H7v2h1v8l-2,2v2h5.2v6h1.6v-6H18v-2L16,12z"/></g>
|
||
<g id="label"><path d="M17.6,5.8C17.3,5.3,16.7,5,16,5L5,5C3.9,5,3,5.9,3,7v10c0,1.1,0.9,2,2,2l11,0c0.7,0,1.3-0.3,1.6-0.8L22,12L17.6,5.8z"/></g>
|
||
<g id="label-outline"><path d="M17.6,5.8C17.3,5.3,16.7,5,16,5L5,5C3.9,5,3,5.9,3,7v10c0,1.1,0.9,2,2,2l11,0c0.7,0,1.3-0.3,1.6-0.8L22,12L17.6,5.8z M16,17H5V7h11l3.5,5L16,17z"/></g>
|
||
<g id="language"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M18.9,8H16c-0.3-1.3-0.8-2.4-1.4-3.6C16.4,5.1,18,6.3,18.9,8z M12,4c0.8,1.2,1.5,2.5,1.9,4h-3.8C10.5,6.6,11.2,5.2,12,4z M4.3,14C4.1,13.4,4,12.7,4,12s0.1-1.4,0.3-2h3.4c-0.1,0.7-0.1,1.3-0.1,2s0.1,1.3,0.1,2H4.3z M5.1,16H8c0.3,1.3,0.8,2.4,1.4,3.6C7.6,18.9,6,17.7,5.1,16z M8,8H5.1c1-1.7,2.5-2.9,4.3-3.6C8.8,5.6,8.3,6.7,8,8z M12,20c-0.8-1.2-1.5-2.5-1.9-4h3.8C13.5,17.4,12.8,18.8,12,20z M14.3,14H9.7c-0.1-0.7-0.2-1.3-0.2-2s0.1-1.3,0.2-2h4.7c0.1,0.7,0.2,1.3,0.2,2S14.4,13.3,14.3,14z M14.6,19.6c0.6-1.1,1.1-2.3,1.4-3.6h2.9C18,17.7,16.4,18.9,14.6,19.6z M16.4,14c0.1-0.7,0.1-1.3,0.1-2s-0.1-1.3-0.1-2h3.4c0.2,0.6,0.3,1.3,0.3,2s-0.1,1.4-0.3,2H16.4z"/></g>
|
||
<g id="launch"><path d="M19,19H5V5h7V3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2v-7h-2V19z M14,3v2h3.6l-9.8,9.8l1.4,1.4L19,6.4V10h2V3H14z"/></g>
|
||
<g id="link"><path d="M3.9,12c0-1.7,1.4-3.1,3.1-3.1h4V7H7c-2.8,0-5,2.2-5,5s2.2,5,5,5h4v-1.9H7C5.3,15.1,3.9,13.7,3.9,12z M8,13h8v-2H8V13z M17,7h-4v1.9h4c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1h-4V17h4c2.8,0,5-2.2,5-5S19.8,7,17,7z"/></g>
|
||
<g id="list"><path d="M3,13h2v-2H3V13z M3,17h2v-2H3V17z M3,9h2V7H3V9z M7,13h14v-2H7V13z M7,17h14v-2H7V17z M7,7v2h14V7H7z"/></g>
|
||
<g id="lock"><path d="M18,8h-1V6c0-2.8-2.2-5-5-5C9.2,1,7,3.2,7,6v2H6c-1.1,0-2,0.9-2,2v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V10C20,8.9,19.1,8,18,8z M12,17c-1.1,0-2-0.9-2-2s0.9-2,2-2c1.1,0,2,0.9,2,2S13.1,17,12,17z M15.1,8H8.9V6c0-1.7,1.4-3.1,3.1-3.1c1.7,0,3.1,1.4,3.1,3.1V8z"/></g>
|
||
<g id="lock-open"><path d="M12,17c1.1,0,2-0.9,2-2s-0.9-2-2-2c-1.1,0-2,0.9-2,2S10.9,17,12,17z M18,8h-1V6c0-2.8-2.2-5-5-5C9.2,1,7,3.2,7,6h1.9c0-1.7,1.4-3.1,3.1-3.1c1.7,0,3.1,1.4,3.1,3.1v2H6c-1.1,0-2,0.9-2,2v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V10C20,8.9,19.1,8,18,8z M18,20H6V10h12V20z"/></g>
|
||
<g id="lock-outline"><path d="M18,8h-1V6c0-2.8-2.2-5-5-5C9.2,1,7,3.2,7,6v2H6c-1.1,0-2,0.9-2,2v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V10C20,8.9,19.1,8,18,8z M12,2.9c1.7,0,3.1,1.4,3.1,3.1v2H9V6H8.9C8.9,4.3,10.3,2.9,12,2.9z M18,20H6V10h12V20z M12,17c1.1,0,2-0.9,2-2s-0.9-2-2-2c-1.1,0-2,0.9-2,2S10.9,17,12,17z"/></g>
|
||
<g id="loyalty"><path d="M21.4,11.6l-9-9C12.1,2.2,11.6,2,11,2H4C2.9,2,2,2.9,2,4v7c0,0.6,0.2,1.1,0.6,1.4l9,9c0.4,0.4,0.9,0.6,1.4,0.6c0.6,0,1.1-0.2,1.4-0.6l7-7c0.4-0.4,0.6-0.9,0.6-1.4C22,12.4,21.8,11.9,21.4,11.6z M5.5,7C4.7,7,4,6.3,4,5.5S4.7,4,5.5,4S7,4.7,7,5.5S6.3,7,5.5,7z M17.3,15.3L13,19.5l-4.3-4.3l0,0C8.3,14.8,8,14.2,8,13.5c0-1.4,1.1-2.5,2.5-2.5c0.7,0,1.3,0.3,1.8,0.7l0.7,0.7l0.7-0.7c0.5-0.5,1.1-0.7,1.8-0.7c1.4,0,2.5,1.1,2.5,2.5C18,14.2,17.7,14.8,17.3,15.3L17.3,15.3z"/></g>
|
||
<g id="mail"><path d="M20,4H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,8l-8,5L4,8V6l8,5l8-5V8z"/></g>
|
||
<g id="markunread"><path d="M20,6H10v6H8V4h6V0H6v6H4C2.9,6,2,6.9,2,8l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z"/></g>
|
||
<g id="markunread"><path d="M22,6l2-2l-2-2l-2,2l-2-2l-2,2l-2-2l-2,2l-2-2L8,4L6,2L4,4L2,2L0,4l2,2L0,8l2,2l-2,2l2,2l-2,2l2,2l-2,2l2,2l2-2l2,2l2-2l2,2l2-2l2,2l2-2l2,2l2-2l2,2l2-2l-2-2l2-2l-2-2l2-2l-2-2l2-2L22,6z M20,8l-8,5L4,8V6l8,5l8-5V8z"/></g>
|
||
<g id="menu"><path d="M3,18h18v-2H3V18z M3,13h18v-2H3V13z M3,6v2h18V6H3z"/></g>
|
||
<g id="more-horiz"><path d="M6,10c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S7.1,10,6,10z M18,10c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S19.1,10,18,10z M12,10c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S13.1,10,12,10z"/></g>
|
||
<g id="more-vert"><path d="M12,8c1.1,0,2-0.9,2-2s-0.9-2-2-2c-1.1,0-2,0.9-2,2S10.9,8,12,8z M12,10c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S13.1,10,12,10z M12,16c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S13.1,16,12,16z"/></g>
|
||
<g id="note-add"><path d="M14,2H6C4.9,2,4,2.9,4,4l0,16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V8L14,2z M16,16h-3v3h-2v-3H8v-2h3v-3h2v3h3V16z M13,9V3.5L18.5,9H13z"/></g>
|
||
<g id="open-in-browser"><path d="M19,4H5C3.9,4,3,4.9,3,6v12c0,1.1,0.9,2,2,2h3v-2H5V8h14v10h-3v2h3c1.1,0,2-0.9,2-2V6C21,4.9,20.1,4,19,4z M12,10l-5,5h3v5h4v-5h3L12,10z"/></g>
|
||
<g id="open-in-new"><path d="M19,19H5V5h7V3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2v-7h-2V19z M14,3v2h3.6l-9.8,9.8l1.4,1.4L19,6.4V10h2V3H14z"/></g>
|
||
<g id="open-with"><path d="M10,9h4V6h3l-5-5L7,6h3V9z M9,10H6V7l-5,5l5,5v-3h3V10z M23,12l-5-5v3h-3v4h3v3L23,12z M14,15h-4v3H7l5,5l5-5h-3V15z"/></g>
|
||
<g id="payment"><path d="M20,4H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18H4v-6h16V18z M20,8H4V6h16V8z"/></g>
|
||
<g id="perm-camera-mic"><path d="M20,5h-3.2L15,3H9L7.2,5H4C2.9,5,2,5.9,2,7v12c0,1.1,0.9,2,2,2h7v-2.1C8.2,18.4,6,16,6,13h2c0,2.2,1.8,4,4,4s4-1.8,4-4h2c0,3-2.2,5.4-5,5.9V21h7c1.1,0,2-0.9,2-2V7C22,5.9,21.1,5,20,5z M14,13c0,1.1-0.9,2-2,2s-2-0.9-2-2V9c0-1.1,0.9-2,2-2s2,0.9,2,2V13z"/></g>
|
||
<g id="perm-contact-cal"><path d="M19,3h-1V1h-2v2H8V1H6v2H5C3.9,3,3,3.9,3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,6c1.7,0,3,1.3,3,3c0,1.7-1.3,3-3,3s-3-1.3-3-3C9,7.3,10.3,6,12,6z M18,18H6v-1c0-2,4-3.1,6-3.1s6,1.1,6,3.1V18z"/></g>
|
||
<g id="perm-data-setting"><path d="M19,11.5c0.3,0,0.7,0,1,0.1V0L0,20h11.6c0-0.3-0.1-0.7-0.1-1C11.5,14.9,14.9,11.5,19,11.5z M22.7,19.5c0-0.2,0-0.3,0-0.5c0-0.2,0-0.3,0-0.5l1.1-0.8c0.1-0.1,0.1-0.2,0.1-0.3l-1-1.7c-0.1-0.1-0.2-0.2-0.3-0.1L21.3,16c-0.3-0.2-0.5-0.4-0.8-0.5l-0.2-1.3c0-0.1-0.1-0.2-0.2-0.2h-2c-0.1,0-0.2,0.1-0.2,0.2l-0.2,1.3c-0.3,0.1-0.6,0.3-0.8,0.5l-1.2-0.5c-0.1,0-0.2,0-0.3,0.1l-1,1.7c-0.1,0.1,0,0.2,0.1,0.3l1.1,0.8c0,0.2,0,0.3,0,0.5c0,0.2,0,0.3,0,0.5l-1.1,0.8c-0.1,0.1-0.1,0.2-0.1,0.3l1,1.7c0.1,0.1,0.2,0.2,0.3,0.1l1.2-0.5c0.3,0.2,0.5,0.4,0.8,0.5l0.2,1.3c0,0.1,0.1,0.2,0.2,0.2h2c0.1,0,0.2-0.1,0.2-0.2l0.2-1.3c0.3-0.1,0.6-0.3,0.8-0.5l1.2,0.5c0.1,0,0.2,0,0.3-0.1l1-1.7c0.1-0.1,0-0.2-0.1-0.3L22.7,19.5z M19,20.5c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5S19.8,20.5,19,20.5z"/></g>
|
||
<g id="perm-device-info"><path d="M13,7h-2v2h2V7z M13,11h-2v6h2V11z M17,1L7,1C5.9,1,5,1.9,5,3v18c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V3C19,1.9,18.1,1,17,1z M17,19H7V5h10V19z"/></g>
|
||
<g id="perm-identity"><path d="M12,5.9c1.2,0,2.1,0.9,2.1,2.1s-0.9,2.1-2.1,2.1S9.9,9.2,9.9,8S10.8,5.9,12,5.9 M12,14.9c3,0,6.1,1.5,6.1,2.1v1.1H5.9V17C5.9,16.4,9,14.9,12,14.9 M12,4C9.8,4,8,5.8,8,8c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,5.8,14.2,4,12,4L12,4z M12,13c-2.7,0-8,1.3-8,4v3h16v-3C20,14.3,14.7,13,12,13L12,13z"/></g>
|
||
<g id="perm-media"><path d="M2,6H0v5h0l0,9c0,1.1,0.9,2,2,2h18v-2H2V6z M22,4h-8l-2-2H6C4.9,2,4,2.9,4,4l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C24,4.9,23.1,4,22,4z M7,15l4.5-6l3.5,4.5l2.5-3L21,15H7z"/></g>
|
||
<g id="perm-phone-msg"><path d="M20,15.5c-1.2,0-2.4-0.2-3.6-0.6c-0.3-0.1-0.7,0-1,0.2l-2.2,2.2c-2.8-1.4-5.1-3.8-6.6-6.6l2.2-2.2c0.3-0.3,0.4-0.7,0.2-1C8.7,6.4,8.5,5.2,8.5,4c0-0.6-0.4-1-1-1H4C3.5,3,3,3.4,3,4c0,9.4,7.6,17,17,17c0.6,0,1-0.4,1-1v-3.5C21,15.9,20.6,15.5,20,15.5z M12,3v10l3-3h6V3H12z"/></g>
|
||
<g id="perm-scan-wifi"><path d="M12,3C7,3,3.2,4.9,0,7.2L12,22L24,7.3C20.9,4.9,17.1,3,12,3z M13,16h-2v-6h2V16z M11,8V6h2v2H11z"/></g>
|
||
<g id="picture-in-picture"><path d="M19,7h-8v6h8V7z M21,3H3C1.9,3,1,3.9,1,5v14c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z M21,19H3V5h18V19z"/></g>
|
||
<g id="polymer"><polygon points="19,4 15,4 7.1,16.6 4.5,12 9,4 5,4 0.5,12 5,20 9,20 16.9,7.4 19.5,12 15,20 19,20 23.5,12 "/></g>
|
||
<g id="print"><path d="M19,8H5c-1.7,0-3,1.3-3,3v6h4v4h12v-4h4v-6C22,9.3,20.7,8,19,8z M16,19H8v-5h8V19z M19,12c-0.6,0-1-0.4-1-1s0.4-1,1-1c0.6,0,1,0.4,1,1S19.6,12,19,12z M18,3H6v4h12V3z"/></g>
|
||
<g id="query-builder"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/><polygon points="12.5,7 11,7 11,13 16.2,16.2 17,14.9 12.5,12.3 "/></g>
|
||
<g id="question-answer"><path d="M21,6h-2v9H6v2c0,0.6,0.4,1,1,1h11l4,4V7C22,6.4,21.6,6,21,6z M17,12V3c0-0.6-0.4-1-1-1H3C2.4,2,2,2.4,2,3v14l4-4h10C16.6,13,17,12.6,17,12z"/></g>
|
||
<g id="radio-button-off"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="radio-button-on"><path d="M12,7c-2.8,0-5,2.2-5,5s2.2,5,5,5c2.8,0,5-2.2,5-5S14.8,7,12,7z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="receipt"><path d="M18,17H6v-2h12V17z M18,13H6v-2h12V13z M18,9H6V7h12V9z M3,22l1.5-1.5L6,22l1.5-1.5L9,22l1.5-1.5L12,22l1.5-1.5L15,22l1.5-1.5L18,22l1.5-1.5L21,22V2l-1.5,1.5L18,2l-1.5,1.5L15,2l-1.5,1.5L12,2l-1.5,1.5L9,2L7.5,3.5L6,2L4.5,3.5L3,2V22z"/></g>
|
||
<g id="redeem"><path d="M20,6h-2.2C17.9,5.7,18,5.4,18,5c0-1.7-1.3-3-3-3c-1,0-2,0.5-2.5,1.3l0,0L12,4l-0.5-0.7l0,0C11,2.5,10.1,2,9,2C7.4,2,6,3.3,6,5c0,0.4,0.1,0.7,0.2,1H4C2.9,6,2,6.9,2,8l0,11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M15,4c0.6,0,1,0.4,1,1s-0.4,1-1,1s-1-0.4-1-1S14.5,4,15,4z M9,4c0.6,0,1,0.4,1,1S9.6,6,9,6S8,5.6,8,5S8.5,4,9,4z M20,19H4v-2h16V19z M20,14H4V8h5.1L7,10.8L8.6,12L11,8.8l1-1.4l1,1.4l2.4,3.2l1.6-1.2L14.9,8H20V14z"/></g>
|
||
<g id="refresh"><path d="M17.6,6.4C16.2,4.9,14.2,4,12,4c-4.4,0-8,3.6-8,8s3.6,8,8,8c3.7,0,6.8-2.6,7.7-6h-2.1c-0.8,2.3-3,4-5.6,4c-3.3,0-6-2.7-6-6s2.7-6,6-6c1.7,0,3.1,0.7,4.2,1.8L13,11h7V4L17.6,6.4z"/></g>
|
||
<g id="reminder"><path d="M16.9,13c1.3-1.3,2.1-3,2.1-5c0-3.9-3.1-7-7-7C8.1,1,5,4.1,5,8c0,2,0.8,3.7,2.1,5l0,0l3.5,3.5L6,21.1l1.4,1.4L16.9,13z M15.5,11.5L15.5,11.5L12,15.1l-3.5-3.5l0,0l0,0C7.6,10.6,7,9.4,7,8c0-2.8,2.2-5,5-5c2.8,0,5,2.2,5,5C17,9.4,16.4,10.6,15.5,11.5L15.5,11.5z M13.4,19.3l3.2,3.2l1.4-1.4l-3.2-3.2L13.4,19.3z"/></g>
|
||
<g id="remove"><path d="M19,13H5v-2h14V13z"/></g>
|
||
<g id="remove-circle"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M17,13H7v-2h10V13z"/></g>
|
||
<g id="remove-circle-outline"><path d="M7,11v2h10v-2H7z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="reorder"><path d="M4,16h16v-2H4V16z M4,9v2h16V9H4z"/></g>
|
||
<g id="reply"><path d="M10,9V5l-7,7l7,7v-4.1c5,0,8.5,1.6,11,5.1C20,15,17,10,10,9z"/></g>
|
||
<g id="reply-all"><path d="M7,8V5l-7,7l7,7v-3l-4-4L7,8z M13,9V5l-7,7l7,7v-4.1c5,0,8.5,1.6,11,5.1C23,15,20,10,13,9z"/></g>
|
||
<g id="report"><path d="M15.7,3H8.3L3,8.3v7.5L8.3,21h7.5l5.3-5.3V8.3L15.7,3z M12,17.3c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3c0.7,0,1.3,0.6,1.3,1.3C13.3,16.7,12.7,17.3,12,17.3z M13,13h-2V7h2V13z"/></g>
|
||
<g id="report-problem"><path d="M1,21h22L12,2L1,21z M13,18h-2v-2h2V18z M13,14h-2v-4h2V14z"/></g>
|
||
<g id="restore"><path d="M13,3c-5,0-9,4-9,9H1l3.9,3.9c0,0,0,0.1,0.1,0.1l4-4H6c0-3.9,3.1-7,7-7c3.9,0,7,3.1,7,7s-3.1,7-7,7c-1.9,0-3.7-0.8-4.9-2.1l-1.4,1.4C8.3,20,10.5,21,13,21c5,0,9-4,9-9S18,3,13,3z M12,8v5l4.3,2.5l0.7-1.2l-3.5-2.1V8H12z"/></g>
|
||
<g id="room"><path d="M12,2C8.1,2,5,5.1,5,9c0,5.2,7,13,7,13s7-7.8,7-13C19,5.1,15.9,2,12,2z M12,11.5c-1.4,0-2.5-1.1-2.5-2.5s1.1-2.5,2.5-2.5c1.4,0,2.5,1.1,2.5,2.5S13.4,11.5,12,11.5z"/></g>
|
||
<g id="rotate-left"><path d="M7.1,8.5L5.7,7.1C4.8,8.3,4.2,9.6,4.1,11h2C6.2,10.1,6.6,9.3,7.1,8.5z M6.1,13h-2c0.2,1.4,0.7,2.7,1.6,3.9l1.4-1.4C6.6,14.7,6.2,13.9,6.1,13z M7.1,18.3c1.2,0.9,2.5,1.4,3.9,1.6v-2c-0.9-0.1-1.7-0.5-2.5-1L7.1,18.3z M13,4.1V1L8.5,5.5L13,10V6.1c2.8,0.5,5,2.9,5,5.9s-2.2,5.4-5,5.9v2c3.9-0.5,7-3.9,7-7.9S16.9,4.6,13,4.1z"/></g>
|
||
<g id="rotate-right"><path d="M15.5,5.5L11,1v3.1C7.1,4.6,4,7.9,4,12s3.1,7.4,7,7.9v-2C8.2,17.4,6,15,6,12s2.2-5.4,5-5.9V10L15.5,5.5z M19.9,11c-0.2-1.4-0.7-2.7-1.6-3.9l-1.4,1.4c0.5,0.8,0.9,1.6,1,2.5H19.9z M13,17.9v2c1.4-0.2,2.7-0.7,3.9-1.6l-1.4-1.4C14.7,17.4,13.9,17.8,13,17.9z M16.9,15.5l1.4,1.4c0.9-1.2,1.5-2.5,1.6-3.9h-2C17.8,13.9,17.4,14.7,16.9,15.5z"/></g>
|
||
<g id="rotation-3d"><path d="M11,14v-1c0-0.6-0.4-1-1-1c0.6,0,1-0.4,1-1v-1c0-1.1-0.9-2-2-2H6v2h3v1H7v2h2v1l0,0l0,0v0h0H6v2h3C10.1,16,11,15.1,11,14z M15,8h-3v8h3c1.7,0,3-1.3,3-3v-2C18,9.3,16.7,8,15,8z M16,13c0,0.6-0.4,1-1,1h-1v-4h1c0.6,0,1,0.4,1,1V13z M12,0c-0.2,0-0.4,0-0.7,0l3.8,3.8l1.3-1.3c3.3,1.5,5.6,4.7,6,8.5h1.5C23.4,4.8,18.3,0,12,0z M7.5,21.5c-3.3-1.5-5.6-4.7-6-8.5H0.1C0.6,19.2,5.7,24,12,24c0.2,0,0.4,0,0.7,0l-3.8-3.8L7.5,21.5z"/></g>
|
||
<g id="save"><path d="M17,3H5C3.9,3,3,3.9,3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V7L17,3z M12,19c-1.7,0-3-1.3-3-3s1.3-3,3-3c1.7,0,3,1.3,3,3S13.7,19,12,19z M15,9H5V5h10V9z"/></g>
|
||
<g id="schedule"><path fill-opacity="0.9" d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/><polygon fill-opacity="0.9" points="12.5,7 11,7 11,13 16.2,16.2 17,14.9 12.5,12.2 "/></g>
|
||
<g id="search"><path d="M15.5,14h-0.8l-0.3-0.3c1-1.1,1.6-2.6,1.6-4.2C16,5.9,13.1,3,9.5,3C5.9,3,3,5.9,3,9.5S5.9,16,9.5,16c1.6,0,3.1-0.6,4.2-1.6l0.3,0.3v0.8l5,5l1.5-1.5L15.5,14z M9.5,14C7,14,5,12,5,9.5S7,5,9.5,5C12,5,14,7,14,9.5S12,14,9.5,14z"/></g>
|
||
<g id="select-all"><path d="M3,5h2V3C3.9,3,3,3.9,3,5z M3,13h2v-2H3V13z M7,21h2v-2H7V21z M3,9h2V7H3V9z M13,3h-2v2h2V3z M19,3v2h2C21,3.9,20.1,3,19,3z M5,21v-2H3C3,20.1,3.9,21,5,21z M3,17h2v-2H3V17z M9,3H7v2h2V3z M11,21h2v-2h-2V21z M19,13h2v-2h-2V13z M19,21c1.1,0,2-0.9,2-2h-2V21z M19,9h2V7h-2V9z M19,17h2v-2h-2V17z M15,21h2v-2h-2V21z M15,5h2V3h-2V5z M7,17h10V7H7V17z M9,9h6v6H9V9z"/></g>
|
||
<g id="send"><polygon points="2,21 23,12 2,3 2,10 17,12 2,14 "/></g>
|
||
<g id="send-money"><path d="M2,12c0-2.6,1.7-4.8,4-5.7V4.3c-3.4,0.9-6,4-6,7.7s2.6,6.8,6,7.7v-2.1C3.7,16.8,2,14.6,2,12z M24,12l-4-4v3h-7v2h7v3L24,12z M14,18c-3.3,0-6-2.7-6-6s2.7-6,6-6c1.7,0,3.2,0.7,4.2,1.8l1.4-1.4C18.2,4.9,16.2,4,14,4c-4.4,0-8,3.6-8,8s3.6,8,8,8c2.2,0,4.2-0.9,5.7-2.3l-1.4-1.4C17.2,17.3,15.7,18,14,18z"/></g>
|
||
<g id="settings"><path d="M19.4,13c0-0.3,0.1-0.6,0.1-1s0-0.7-0.1-1l2.1-1.7c0.2-0.2,0.2-0.4,0.1-0.6l-2-3.5C19.5,5.1,19.3,5,19,5.1l-2.5,1c-0.5-0.4-1.1-0.7-1.7-1l-0.4-2.6C14.5,2.2,14.2,2,14,2h-4C9.8,2,9.5,2.2,9.5,2.4L9.1,5.1C8.5,5.3,8,5.7,7.4,6.1L5,5.1C4.7,5,4.5,5.1,4.3,5.3l-2,3.5C2.2,8.9,2.3,9.2,2.5,9.4L4.6,11c0,0.3-0.1,0.6-0.1,1s0,0.7,0.1,1l-2.1,1.7c-0.2,0.2-0.2,0.4-0.1,0.6l2,3.5C4.5,18.9,4.7,19,5,18.9l2.5-1c0.5,0.4,1.1,0.7,1.7,1l0.4,2.6c0,0.2,0.2,0.4,0.5,0.4h4c0.2,0,0.5-0.2,0.5-0.4l0.4-2.6c0.6-0.3,1.2-0.6,1.7-1l2.5,1c0.2,0.1,0.5,0,0.6-0.2l2-3.5c0.1-0.2,0.1-0.5-0.1-0.6L19.4,13z M12,15.5c-1.9,0-3.5-1.6-3.5-3.5s1.6-3.5,3.5-3.5s3.5,1.6,3.5,3.5S13.9,15.5,12,15.5z"/></g>
|
||
<g id="settings-applications"><path d="M12,10c-1.1,0-2,0.9-2,2s0.9,2,2,2s2-0.9,2-2S13.1,10,12,10z M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M17.2,12c0,0.2,0,0.5,0,0.7l1.5,1.2c0.1,0.1,0.2,0.3,0.1,0.4l-1.4,2.4c-0.1,0.2-0.3,0.2-0.4,0.2l-1.7-0.7c-0.4,0.3-0.8,0.5-1.2,0.7l-0.3,1.9c0,0.2-0.2,0.3-0.3,0.3h-2.8c-0.2,0-0.3-0.1-0.3-0.3L10,16.9c-0.4-0.2-0.8-0.4-1.2-0.7l-1.7,0.7c-0.2,0.1-0.3,0-0.4-0.2l-1.4-2.4c-0.1-0.2,0-0.3,0.1-0.4l1.5-1.2c0-0.2,0-0.5,0-0.7s0-0.5,0-0.7l-1.5-1.2c-0.1-0.1-0.2-0.3-0.1-0.4l1.4-2.4c0.1-0.2,0.3-0.2,0.4-0.2l1.7,0.7C9.2,7.6,9.6,7.3,10,7.1l0.3-1.9c0-0.2,0.2-0.3,0.3-0.3h2.8c0.2,0,0.3,0.1,0.3,0.3L14,7.1c0.4,0.2,0.8,0.4,1.2,0.7l1.7-0.7c0.2-0.1,0.3,0,0.4,0.2l1.4,2.4c0.1,0.2,0,0.3-0.1,0.4l-1.5,1.2C17.2,11.5,17.2,11.8,17.2,12z"/></g>
|
||
<g id="settings-backup-restore"><path d="M14,12c0-1.1-0.9-2-2-2s-2,0.9-2,2s0.9,2,2,2S14,13.1,14,12z M12,3c-5,0-9,4-9,9H0l4,4l4-4H5c0-3.9,3.1-7,7-7s7,3.1,7,7s-3.1,7-7,7c-1.5,0-2.9-0.5-4.1-1.3l-1.4,1.4C8,20.3,9.9,21,12,21c5,0,9-4,9-9S17,3,12,3z"/></g>
|
||
<g id="settings-bluetooth"><path d="M11,24h2v-2h-2V24z M7,24h2v-2H7V24z M15,24h2v-2h-2V24z M17.7,5.7L12,0h-1v7.6L6.4,3L5,4.4l5.6,5.6L5,15.6L6.4,17l4.6-4.6V20h1l5.7-5.7L13.4,10L17.7,5.7z M13,3.8l1.9,1.9L13,7.6V3.8z M14.9,14.3L13,16.2v-3.8L14.9,14.3z"/></g>
|
||
<g id="settings-cell"><path d="M7,24h2v-2H7V24z M11,24h2v-2h-2V24z M15,24h2v-2h-2V24z M16,0L8,0C6.9,0,6,0.9,6,2v16c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V2C18,0.9,17.1,0,16,0z M16,16H8V4h8V16z"/></g>
|
||
<g id="settings-display"><path d="M21,19H3V5h18V19z M21,3H3C1.9,3,1,3.9,1,5v14c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3L21,3z"/><path d="M10,12c0-1.1,0.9-2,2-2V8c0.3,0,0.7,0.1,1,0.1V6h-2v2.1c-0.4,0.1-0.7,0.2-1,0.4L8.5,7.1L7.1,8.5L8.6,10c-0.2,0.3-0.3,0.7-0.4,1H6v2h2.1c0.1,0.4,0.2,0.7,0.4,1l-1.5,1.5l1.4,1.4l1.5-1.5c0.3,0.2,0.7,0.3,1,0.4V18h2v-2.1c-0.3,0.1-0.7,0.1-1,0.1v-2C10.9,14,10,13.1,10,12z M15.4,10l1.5-1.5l-1.4-1.4L14,8.6C14.6,8.9,15.1,9.4,15.4,10z M14,15.4l1.5,1.5l1.4-1.4L15.4,14C15.1,14.6,14.6,15.1,14,15.4z M12,10v4c1.1,0,2-0.9,2-2C14,10.9,13.1,10,12,10z M15.9,11c0.1,0.3,0.1,0.7,0.1,1s-0.1,0.7-0.1,1H18v-2H15.9z"/></g>
|
||
<g id="settings-ethernet"><path d="M7.8,6.8L6.2,5.5L0.8,12l5.4,6.5l1.5-1.3L3.4,12L7.8,6.8z M7,13h2v-2H7V13z M17,11h-2v2h2V11z M11,13h2v-2h-2V13z M17.8,5.5l-1.5,1.3l4.3,5.2l-4.3,5.2l1.5,1.3l5.4-6.5L17.8,5.5z"/></g>
|
||
<g id="settings-input-antenna"><path d="M12,5c-3.9,0-7,3.1-7,7h2c0-2.8,2.2-5,5-5s5,2.2,5,5h2C19,8.1,15.9,5,12,5z M13,14.3c0.9-0.4,1.5-1.3,1.5-2.3c0-1.4-1.1-2.5-2.5-2.5S9.5,10.6,9.5,12c0,1,0.6,1.9,1.5,2.3v3.3L7.6,21L9,22.4l3-3l3,3l1.4-1.4L13,17.6V14.3z M12,1C5.9,1,1,5.9,1,12h2c0-5,4-9,9-9s9,4,9,9h2C23,5.9,18.1,1,12,1z"/></g>
|
||
<g id="settings-input-component"><path d="M5,2c0-0.6-0.4-1-1-1S3,1.4,3,2v4H1v6h6V6H5V2z M9,16c0,1.3,0.8,2.4,2,2.8V23h2v-4.2c1.2-0.4,2-1.5,2-2.8v-2H9V16z M1,16c0,1.3,0.8,2.4,2,2.8V23h2v-4.2c1.2-0.4,2-1.5,2-2.8v-2H1V16z M21,6V2c0-0.6-0.4-1-1-1s-1,0.4-1,1v4h-2v6h6V6H21z M13,2c0-0.6-0.4-1-1-1s-1,0.4-1,1v4H9v6h6V6h-2V2z M17,16c0,1.3,0.8,2.4,2,2.8V23h2v-4.2c1.2-0.4,2-1.5,2-2.8v-2h-6V16z"/></g>
|
||
<g id="settings-input-composite"><path d="M5,2c0-0.6-0.4-1-1-1S3,1.4,3,2v4H1v6h6V6H5V2z M9,16c0,1.3,0.8,2.4,2,2.8V23h2v-4.2c1.2-0.4,2-1.5,2-2.8v-2H9V16z M1,16c0,1.3,0.8,2.4,2,2.8V23h2v-4.2c1.2-0.4,2-1.5,2-2.8v-2H1V16z M21,6V2c0-0.6-0.4-1-1-1s-1,0.4-1,1v4h-2v6h6V6H21z M13,2c0-0.6-0.4-1-1-1s-1,0.4-1,1v4H9v6h6V6h-2V2z M17,16c0,1.3,0.8,2.4,2,2.8V23h2v-4.2c1.2-0.4,2-1.5,2-2.8v-2h-6V16z"/></g>
|
||
<g id="settings-input-hdmi"><path d="M18,7V4c0-1.1-0.9-2-2-2H8C6.9,2,6,2.9,6,4v3H5v6l3,6v3h8v-3l3-6V7H18z M8,4h8v3h-2V5h-1v2h-2V5h-1v2H8V4z"/></g>
|
||
<g id="settings-input-svideo"><path d="M8,11.5C8,10.7,7.3,10,6.5,10S5,10.7,5,11.5S5.7,13,6.5,13S8,12.3,8,11.5z M15,6.5C15,5.7,14.3,5,13.5,5h-3C9.7,5,9,5.7,9,6.5S9.7,8,10.5,8h3C14.3,8,15,7.3,15,6.5z M8.5,15C7.7,15,7,15.7,7,16.5S7.7,18,8.5,18s1.5-0.7,1.5-1.5S9.3,15,8.5,15z M12,1C5.9,1,1,5.9,1,12s4.9,11,11,11s11-4.9,11-11S18.1,1,12,1z M12,21c-5,0-9-4-9-9s4-9,9-9s9,4,9,9S17,21,12,21z M17.5,10c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S18.3,10,17.5,10z M15.5,15c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S16.3,15,15.5,15z"/></g>
|
||
<g id="settings-overscan"><path d="M12,5.5L10,8h4L12,5.5z M18,10v4l2.5-2L18,10z M6,10l-2.5,2L6,14V10z M14,16h-4l2,2.5L14,16z M21,3H3C1.9,3,1,3.9,1,5v14c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z M21,19H3V5h18V19z"/></g>
|
||
<g id="settings-phone"><path d="M13,9h-2v2h2V9z M17,9h-2v2h2V9z M20,15.5c-1.2,0-2.4-0.2-3.6-0.6c-0.3-0.1-0.7,0-1,0.2l-2.2,2.2c-2.8-1.4-5.1-3.8-6.6-6.6l2.2-2.2c0.3-0.3,0.4-0.7,0.2-1C8.7,6.4,8.5,5.2,8.5,4c0-0.6-0.4-1-1-1H4C3.4,3,3,3.4,3,4c0,9.4,7.6,17,17,17c0.6,0,1-0.4,1-1v-3.5C21,15.9,20.6,15.5,20,15.5z M19,9v2h2V9H19z"/></g>
|
||
<g id="settings-power"><path d="M7,24h2v-2H7V24z M11,24h2v-2h-2V24z M13,2h-2v10h2V2z M16.6,4.4l-1.4,1.4C16.8,6.9,18,8.8,18,11c0,3.3-2.7,6-6,6c-3.3,0-6-2.7-6-6c0-2.2,1.2-4.1,2.9-5.1L7.4,4.4C5.4,5.9,4,8.3,4,11c0,4.4,3.6,8,8,8c4.4,0,8-3.6,8-8C20,8.3,18.6,5.9,16.6,4.4z M15,24h2v-2h-2V24z"/></g>
|
||
<g id="settings-remote"><path d="M15,9H9c-0.6,0-1,0.4-1,1v12c0,0.6,0.4,1,1,1h6c0.6,0,1-0.4,1-1V10C16,9.4,15.6,9,15,9z M12,15c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S13.1,15,12,15z M7.1,6.1l1.4,1.4C9.4,6.6,10.6,6,12,6s2.6,0.6,3.5,1.5l1.4-1.4C15.7,4.8,13.9,4,12,4S8.3,4.8,7.1,6.1z M12,0C9,0,6.2,1.2,4.2,3.2l1.4,1.4C7.3,3,9.5,2,12,2s4.7,1,6.4,2.6l1.4-1.4C17.8,1.2,15,0,12,0z"/></g>
|
||
<g id="settings-voice"><path d="M7,24h2v-2H7V24z M12,13c1.7,0,3-1.3,3-3l0-6c0-1.7-1.3-3-3-3c-1.7,0-3,1.3-3,3v6C9,11.7,10.3,13,12,13z M11,24h2v-2h-2V24z M15,24h2v-2h-2V24z M19,10h-1.7c0,3-2.5,5.1-5.3,5.1c-2.8,0-5.3-2.1-5.3-5.1H5c0,3.4,2.7,6.2,6,6.7V20h2v-3.3C16.3,16.2,19,13.4,19,10z"/></g>
|
||
<g id="shop"><path d="M16,6V4l-2-2h-4L8,4v2H2v13c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6H16z M10,4h4v2h-4V4z M9,18V9l7.5,4L9,18z"/></g>
|
||
<g id="shop-two"><path d="M18,5V3l-2-2h-4l-2,2v2H5v11c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5H18z M12,3h4v2h-4V3z M12,15V8l5.5,3L12,15z M3,9H1v11c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2H3V9z"/></g>
|
||
<g id="shopping-basket"><path d="M17.2,9l-4.4-6.6C12.6,2.2,12.3,2,12,2c-0.3,0-0.6,0.1-0.8,0.4L6.8,9H2c-0.6,0-1,0.4-1,1c0,0.1,0,0.2,0,0.3l2.5,9.3c0.2,0.8,1,1.5,1.9,1.5h13c0.9,0,1.7-0.6,1.9-1.5l2.5-9.3c0-0.1,0-0.2,0-0.3c0-0.6-0.4-1-1-1H17.2z M9,9l3-4.4L15,9H9z M12,17c-1.1,0-2-0.9-2-2s0.9-2,2-2c1.1,0,2,0.9,2,2S13.1,17,12,17z"/></g>
|
||
<g id="shopping-cart"><path d="M7,18c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S8.1,18,7,18z M1,2v2h2l3.6,7.6L5.2,14C5.1,14.3,5,14.7,5,15c0,1.1,0.9,2,2,2h12v-2H7.4c-0.1,0-0.2-0.1-0.2-0.2c0,0,0-0.1,0-0.1L8.1,13h7.4c0.8,0,1.4-0.4,1.7-1l3.6-6.5C21,5.3,21,5.2,21,5c0-0.6-0.4-1-1-1H5.2L4.3,2H1z M17,18c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S18.1,18,17,18z"/></g>
|
||
<g id="sort"><path d="M3,18h6v-2H3V18z M3,6v2h18V6H3z M3,13h12v-2H3V13z"/></g>
|
||
<g id="star"><polygon points="12,17.273 18.18,21 16.545,13.971 22,9.244 14.809,8.627 12,2 9.191,8.627 2,9.244 7.455,13.971 5.82,21 "/></g>
|
||
<g id="star-half"><path d="M22,9.744l-7.191-0.617L12,2.5L9.191,9.127L2,9.744v0l0,0l5.455,4.727L5.82,21.5L12,17.772l0,0l6.18,3.727l-1.635-7.029L22,9.744z M12,15.896V6.595l1.71,4.036l4.38,0.376l-3.322,2.878l0.996,4.281L12,15.896z"/></g>
|
||
<g id="star-outline"><path d="M22,9.244l-7.191-0.617L12,2L9.191,8.627L2,9.244l5.455,4.727L5.82,21L12,17.272L18.18,21l-1.635-7.029L22,9.244z M12,15.396l-3.763,2.27l0.996-4.281L5.91,10.507l4.38-0.376L12,6.095l1.71,4.036l4.38,0.376l-3.322,2.878l0.996,4.281L12,15.396z"/></g>
|
||
<g id="star-rate"><polygon points="12,14.3 15.7,17 14.3,12.6 18,10 13.5,10 12,5.5 10.5,10 6,10 9.7,12.6 8.3,17 "/></g>
|
||
<g id="stars"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M16.2,18L12,15.4L7.8,18l1.1-4.8L5.2,10l4.9-0.4L12,5l1.9,4.5l4.9,0.4l-3.7,3.2L16.2,18z"/></g>
|
||
<g id="store"><path d="M20,4H4v2h16V4z M21,14v-2l-1-5H4l-1,5v2h1v6h10v-6h4v6h2v-6H21z M12,18H6v-4h6V18z"/></g>
|
||
<g id="subject"><path d="M14,17H4v2h10V17z M20,9H4v2h16V9z M4,15h16v-2H4V15z M4,5v2h16V5H4z"/></g>
|
||
<g id="swap-driving-apps"><circle cx="6.5" cy="15.5" r="1.5"/><circle cx="17.5" cy="15.5" r="1.5"/><path d="M18.9,7c-0.2-0.6-0.8-1-1.4-1H16H6V4L3,7l2,2l1,1V8h11.7l1.3,4H3v9c0,0.6,0.4,1,1,1h1c0.6,0,1-0.4,1-1v-1h12v1c0,0.6,0.4,1,1,1h1c0.6,0,1-0.4,1-1v-8L18.9,7z M6.5,17C5.7,17,5,16.3,5,15.5S5.7,14,6.5,14C7.3,14,8,14.7,8,15.5S7.3,17,6.5,17z M17.5,17c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5c0.8,0,1.5,0.7,1.5,1.5S18.3,17,17.5,17z M16,0v2H8v2h8v2l3-3L16,0z"/></g>
|
||
<g id="swap-driving-apps-wheel"><path d="M14.4,6.1c-0.5-0.2-1.1,0-1.3,0.6L11.7,10c-1,0.1-1.7,1-1.7,2c0,1.1,0.9,2,2,2s2-0.9,2-2c0-0.5-0.2-0.9-0.4-1.2l1.4-3.4C15.1,6.9,14.9,6.3,14.4,6.1z M7,9c-0.6,0-1,0.4-1,1c0,0.6,0.4,1,1,1s1-0.4,1-1C8,9.4,7.6,9,7,9z M11,7c0-0.6-0.4-1-1-1S9,6.4,9,7c0,0.6,0.4,1,1,1S11,7.6,11,7z M17,9c-0.6,0-1,0.4-1,1c0,0.6,0.4,1,1,1s1-0.4,1-1C18,9.4,17.6,9,17,9z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M17.3,18c-1.4-1.2-3.2-2-5.3-2s-3.9,0.8-5.3,2C5.1,16.5,4,14.4,4,12c0-4.4,3.6-8,8-8s8,3.6,8,8C20,14.4,18.9,16.5,17.3,18z"/></g>
|
||
<g id="swap-horiz"><path d="M7,11l-4,4l4,4v-3h7v-2H7V11z M21,9l-4-4v3h-7v2h7v3L21,9z"/></g>
|
||
<g id="swap-vert"><path d="M16,17v-7h-2v7h-3l4,4l4-4H16z M9,3L5,7h3v7h2V7h3L9,3z"/></g>
|
||
<g id="swap-vert-circle"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M6.5,9L10,5.5L13.5,9H11v4H9V9H6.5z M17.5,15L14,18.5L10.5,15H13v-4h2v4H17.5z"/></g>
|
||
<g id="system-update-tv"><path d="M12,15l4-4h-3V3h-2v8H8L12,15z M20,3h-5v2h5v12H4V5h5V3H4C2.9,3,2,3.9,2,5v12c0,1.1,0.9,2,2,2h4v2h8v-2h4c1.1,0,2-0.9,2-2l0-12C22,3.9,21.1,3,20,3z"/></g>
|
||
<g id="tab"><path d="M21,3H3C1.9,3,1,3.9,1,5v14c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z M21,19L3,19V5h10v4h8V19z"/></g>
|
||
<g id="tab-unselected"><path d="M1,9h2V7H1V9z M1,13h2v-2H1V13z M1,5h2V3C1.9,3,1,3.9,1,5z M9,21h2v-2l-2,0V21z M1,17h2v-2H1V17z M3,21v-2H1C1,20.1,1.9,21,3,21z M21,3h-8v6h10V5C23,3.9,22.1,3,21,3z M21,17h2v-2h-2V17z M9,5h2V3H9V5z M5,21h2v-2l-2,0V21z M5,5h2V3H5V5z M21,21c1.1,0,2-0.9,2-2h-2V21z M21,13h2v-2h-2V13z M13,21h2v-2l-2,0V21z M17,21h2v-2l-2,0V21z"/></g>
|
||
<g id="text-format"><path d="M5,17v2h14v-2H5z M9.5,12.8h5l0.9,2.2h2.1L12.8,4h-1.5L6.5,15h2.1L9.5,12.8z M12,6l1.9,5h-3.7L12,6z"/></g>
|
||
<g id="theaters"><path d="M18,3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3H18z M8,17H6v-2h2V17z M8,13H6v-2h2V13z M8,9H6V7h2V9z M18,17h-2v-2h2V17z M18,13h-2v-2h2V13z M18,9h-2V7h2V9z"/></g>
|
||
<g id="thumb-down"><path d="M15,3H6C5.2,3,4.5,3.5,4.2,4.2l-3,7.1C1.1,11.5,1,11.7,1,12v1.9l0,0c0,0,0,0.1,0,0.1c0,1.1,0.9,2,2,2h6.3l-1,4.6c0,0.1,0,0.2,0,0.3c0,0.4,0.2,0.8,0.4,1.1L9.8,23l6.6-6.6c0.4-0.4,0.6-0.9,0.6-1.4V5C17,3.9,16.1,3,15,3z M19,3v12h4V3H19z"/></g>
|
||
<g id="thumb-up"><path d="M1,21h4V9H1V21z M23,10c0-1.1-0.9-2-2-2h-6.3l1-4.6c0-0.1,0-0.2,0-0.3c0-0.4-0.2-0.8-0.4-1.1L14.2,1L7.6,7.6C7.2,7.9,7,8.4,7,9v10c0,1.1,0.9,2,2,2h9c0.8,0,1.5-0.5,1.8-1.2l3-7.1c0.1-0.2,0.1-0.5,0.1-0.7V10L23,10C23,10.1,23,10,23,10z"/></g>
|
||
<g id="toc"><path d="M3,9h14V7H3V9z M3,13h14v-2H3V13z M3,17h14v-2H3V17z M19,17h2v-2h-2V17z M19,7v2h2V7H19z M19,13h2v-2h-2V13z"/></g>
|
||
<g id="today"><path d="M19,3h-1V1h-2v2H8V1H6v2H5C3.9,3,3,3.9,3,5l0,14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19H5V8h14V19z"/><rect x="7" y="10" width="5" height="5"/></g>
|
||
<g id="translate"><path d="M12.9,15.1l-2.5-2.5l0,0c1.7-1.9,3-4.2,3.7-6.5H17V4h-7V2H8v2H1v2l11.2,0c-0.7,1.9-1.7,3.8-3.2,5.4c-0.9-1-1.7-2.2-2.3-3.4h-2c0.7,1.6,1.7,3.2,3,4.6l-5.1,5L4,19l5-5l3.1,3.1L12.9,15.1z M18.5,10h-2L12,22h2l1.1-3h4.8l1.1,3h2L18.5,10z M15.9,17l1.6-4.3l1.6,4.3H15.9z"/></g>
|
||
<g id="trending-down"><polygon points="16,18 18.3,15.7 13.4,10.8 9.4,14.8 2,7.4 3.4,6 9.4,12 13.4,8 19.7,14.3 22,12 22,18 "/></g>
|
||
<g id="trending-neutral"><polygon points="22,12 18,8 18,11 3,11 3,13 18,13 18,16 "/></g>
|
||
<g id="trending-up"><polygon points="16,6 18.3,8.3 13.4,13.2 9.4,9.2 2,16.6 3.4,18 9.4,12 13.4,16 19.7,9.7 22,12 22,6 "/></g>
|
||
<g id="turned-in"><path d="M17,3H7C5.9,3,5,3.9,5,5l0,16l7-3l7,3V5C19,3.9,18.1,3,17,3z"/></g>
|
||
<g id="turned-in-not"><path d="M17,3H7C5.9,3,5,3.9,5,5l0,16l7-3l7,3V5C19,3.9,18.1,3,17,3z M17,18l-5-2.2L7,18V5h10V18z"/></g>
|
||
<g id="undo"><path d="M12,5V1.5l-5,5l5,5V7c3.3,0,6,2.7,6,6s-2.7,6-6,6c-3.3,0-6-2.7-6-6H4c0,4.4,3.6,8,8,8c4.4,0,8-3.6,8-8S16.4,5,12,5z"/></g>
|
||
<g id="unfold-less"><path d="M7.4,18.6L8.8,20l3.2-3.2l3.2,3.2l1.4-1.4L12,14L7.4,18.6z M16.6,5.4L15.2,4L12,7.2L8.8,4L7.4,5.4L12,10L16.6,5.4z"/></g>
|
||
<g id="unfold-more"><path d="M12,5.8L15.2,9l1.4-1.4L12,3L7.4,7.6L8.8,9L12,5.8z M12,18.2L8.8,15l-1.4,1.4L12,21l4.6-4.6L15.2,15L12,18.2z"/></g>
|
||
<g id="view-array"><path d="M4,18h3V5H4V18z M18,5v13h3V5H18z M8,18h9V5H8V18z"/></g>
|
||
<g id="view-column"><path d="M10,18h5V5h-5V18z M4,18h5V5H4V18z M16,5v13h5V5H16z"/></g>
|
||
<g id="view-headline"><path d="M4,15h17v-2H4V15z M4,19h17v-2H4V19z M4,11h17V9H4V11z M4,5v2h17V5H4z"/></g>
|
||
<g id="view-list"><path d="M4,14h4v-4H4V14z M4,19h4v-4H4V19z M4,9h4V5H4V9z M9,14h12v-4H9V14z M9,19h12v-4H9V19z M9,5v4h12V5H9z"/></g>
|
||
<g id="view-module"><path d="M4,11h5V5H4V11z M4,18h5v-6H4V18z M10,18h5v-6h-5V18z M16,18h5v-6h-5V18z M10,11h5V5h-5V11z M16,5v6h5V5H16z"/></g>
|
||
<g id="view-quilt"><path d="M10,18h5v-6h-5V18z M4,18h5V5H4V18z M16,18h5v-6h-5V18z M10,5v6h11V5H10z"/></g>
|
||
<g id="view-stream"><path d="M4,18h17v-6H4V18z M4,5v6h17V5H4z"/></g>
|
||
<g id="visibility"><path d="M12,4.5C7,4.5,2.7,7.6,1,12c1.7,4.4,6,7.5,11,7.5c5,0,9.3-3.1,11-7.5C21.3,7.6,17,4.5,12,4.5z M12,17c-2.8,0-5-2.2-5-5s2.2-5,5-5c2.8,0,5,2.2,5,5S14.8,17,12,17z M12,9c-1.7,0-3,1.3-3,3s1.3,3,3,3c1.7,0,3-1.3,3-3S13.7,9,12,9z"/></g>
|
||
<g id="visibility-off"><path d="M12,7c2.8,0,5,2.2,5,5c0,0.6-0.1,1.3-0.4,1.8l2.9,2.9c1.5-1.3,2.7-2.9,3.4-4.7c-1.7-4.4-6-7.5-11-7.5c-1.4,0-2.7,0.3-4,0.7l2.2,2.2C10.7,7.1,11.4,7,12,7z M2,4.3l2.3,2.3L4.7,7c-1.7,1.3-3,3-3.7,5c1.7,4.4,6,7.5,11,7.5c1.5,0,3-0.3,4.4-0.8l0.4,0.4l2.9,2.9l1.3-1.3L3.3,3L2,4.3z M7.5,9.8l1.5,1.5C9,11.6,9,11.8,9,12c0,1.7,1.3,3,3,3c0.2,0,0.4,0,0.7-0.1l1.5,1.5C13.5,16.8,12.8,17,12,17c-2.8,0-5-2.2-5-5C7,11.2,7.2,10.5,7.5,9.8z M11.8,9l3.1,3.1c0-0.1,0-0.1,0-0.2c0-1.7-1.3-3-3-3C11.9,9,11.9,9,11.8,9z"/></g>
|
||
<g id="wallet-giftcard"><path d="M20,6h-2.2C17.9,5.7,18,5.4,18,5c0-1.7-1.3-3-3-3c-1,0-2,0.5-2.5,1.3l0,0L12,4l-0.5-0.7l0,0C11,2.5,10,2,9,2C7.3,2,6,3.3,6,5c0,0.4,0.1,0.7,0.2,1H4C2.9,6,2,6.9,2,8l0,11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M15,4c0.6,0,1,0.4,1,1s-0.4,1-1,1s-1-0.4-1-1S14.4,4,15,4z M9,4c0.6,0,1,0.4,1,1S9.6,6,9,6S8,5.6,8,5S8.4,4,9,4z M20,19H4v-2h16V19z M20,14H4V8h5.1L7,10.8L8.6,12L11,8.8l1-1.4l1,1.4l2.4,3.2l1.6-1.2L14.9,8H20V14z"/></g>
|
||
<g id="wallet-membership"><path d="M20,2H4C2.9,2,2,2.9,2,4v11c0,1.1,0.9,2,2,2h4v5l4-2l4,2v-5h4c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M20,15H4v-2h16V15z M20,10H4V4h16V10z"/></g>
|
||
<g id="wallet-travel"><path d="M20,6h-3V4l-2-2H9L7,4v2H4C2.9,6,2,6.9,2,8v11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M9,4h6v2H9V4z M20,19H4v-2h16V19z M20,14H4V8h3v4h2V8h6v4h2V8h3V14z"/></g>
|
||
<g id="warning"><path d="M1,21h22L12,2L1,21z M13,18h-2v-2h2V18z M13,14h-2v-4h2V14z"/></g>
|
||
<g id="work"><path d="M20,6h-4V4l-2-2h-4L8,4v2H4C2.9,6,2,6.9,2,8l0,11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C22,6.9,21.1,6,20,6z M14,6h-4V4h4V6z"/></g>
|
||
</defs></svg>
|
||
</core-iconset-svg>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
|
||
-->
|
||
|
||
<!--
|
||
/**
|
||
* core-input is an unstyled single- or multi-line text field where user can
|
||
* enter input.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-input placeholder="Placeholder text here"></core-input>
|
||
*
|
||
* <core-input multiline placeholder="Enter multiple lines here"></core-input>
|
||
*
|
||
* The text input's value is considered "committed" if the user hits the "enter"
|
||
* key or blurs the input after changing the value. The `change` event is fired
|
||
* when the value becomes committed, and the committed value is stored in the
|
||
* `value` property. The current value of the input is stored in the `inputValue`
|
||
* property.
|
||
*
|
||
* Validation
|
||
* ----------
|
||
*
|
||
* core-input can optionally validate the value using the HTML5 constraints API,
|
||
* similar to native inputs. There are two methods to configure input validation:
|
||
*
|
||
* 1. By setting the `type` attribute. For example, setting it to `email` will
|
||
* check the value is a valid email, and setting it to `number` will check
|
||
* the input is a number.
|
||
*
|
||
* 2. By setting attributes related to validation. The attributes are `pattern`,
|
||
* `min`, `max`, `step` and `required`.
|
||
*
|
||
* Only `required` is supported for multiline inputs currently.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-input type="email" placeholder="enter your email"></core-input>
|
||
*
|
||
* <core-input type="number" min="5" placeholder="enter a number greater than or equal to 5"></core-input>
|
||
*
|
||
* <core-input pattern=".*abc.*" placeholder="enter something containing 'abc'"></core-input>
|
||
*
|
||
* See https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation
|
||
* for more info on validation.
|
||
*
|
||
* @group Polymer Core Elements
|
||
* @element core-input
|
||
* @homepage github.io
|
||
*/
|
||
-->
|
||
|
||
<!--
|
||
Fired when the inputValue of is changed. This is the same event as the DOM
|
||
"input" event.
|
||
|
||
@event input
|
||
-->
|
||
|
||
<!--
|
||
Fired when the user commits the value of the input, either by the hitting the
|
||
`enter` key or blurring the input after the changing the inputValue. Also see the
|
||
DOM "change" event.
|
||
|
||
@event change
|
||
-->
|
||
|
||
<!--
|
||
Fired when the inputValue of this text input changes and fails validation.
|
||
|
||
@event input-invalid
|
||
@param {Object} detail
|
||
@param {string} value The text input's inputValue.
|
||
-->
|
||
|
||
<!--
|
||
Fired when the inputValue of this text input changes and passes validation.
|
||
|
||
@event input-valid
|
||
@param {Object} detail
|
||
@param {string} value The text input's inputValue.
|
||
-->
|
||
|
||
|
||
<polymer-element name="core-input" on-focus="{{focusAction}}" assetpath="polymer/bower_components/core-input/">
|
||
|
||
<template>
|
||
|
||
<style>/*
|
||
* @license
|
||
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
* Code distributed by Google as part of the polymer project is also
|
||
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: inline-block;
|
||
text-align: inherit;
|
||
position: relative;
|
||
width: 20em;
|
||
}
|
||
|
||
:host:hover {
|
||
cursor: text;
|
||
}
|
||
|
||
input,
|
||
textarea {
|
||
font: inherit;
|
||
color: inherit;
|
||
width: 100%;
|
||
margin: 0;
|
||
padding: 0;
|
||
background-color: transparent;
|
||
border: none;
|
||
outline: none;
|
||
width: 100%;
|
||
}
|
||
|
||
textarea {
|
||
resize: none;
|
||
}
|
||
|
||
textarea[rows=fit] {
|
||
height: 100%;
|
||
}</style>
|
||
|
||
<template if="{{multiline}}">
|
||
<textarea id="input" value="{{inputValue}}" rows="{{rows}}" disabled?="{{disabled}}" placeholder="{{placeholder}}" autofocus?="{{autofocus}}" required?="{{required}}" readonly?="{{readonly}}" maxlength="{{maxlength}}" aria-label="{{label || placeholder}}" aria-invalid="{{invalid}}" on-change="{{inputChangeAction}}" on-focus="{{inputFocusAction}}" on-blur="{{inputBlurAction}}"></textarea>
|
||
</template>
|
||
|
||
<template if="{{!multiline}}">
|
||
<input id="input" value="{{inputValue}}" disabled?="{{disabled}}" type="{{type}}" placeholder="{{placeholder}}" autofocus?="{{autofocus}}" required?="{{required}}" readonly?="{{readonly}}" pattern="{{pattern}}" min="{{min}}" max="{{max}}" step="{{step}}" maxlength="{{maxlength}}" aria-label="{{label || placeholder}}" aria-invalid="{{invalid}}" on-keypress="{{keypressAction}}" on-change="{{inputChangeAction}}" on-focus="{{inputFocusAction}}" on-blur="{{inputBlurAction}}">
|
||
</template>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
|
||
Polymer('core-input', {
|
||
publish: {
|
||
/**
|
||
* Placeholder text that hints to the user what can be entered in
|
||
* the input.
|
||
*
|
||
* @attribute placeholder
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
placeholder: '',
|
||
|
||
/**
|
||
* If true, this input cannot be focused and the user cannot change
|
||
* its value.
|
||
*
|
||
* @attribute disabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
disabled: false,
|
||
|
||
/**
|
||
* If true, the user cannot modify the value of the input.
|
||
*
|
||
* @attribute readonly
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
readonly: false,
|
||
|
||
/**
|
||
* If true, this input will automatically gain focus on page load.
|
||
*
|
||
* @attribute autofocus
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
autofocus: false,
|
||
|
||
/**
|
||
* If true, this input accepts multi-line input like a `<textarea>`
|
||
*
|
||
* @attribute multiline
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
multiline: false,
|
||
|
||
/**
|
||
* (multiline only) The height of this text input in rows. The input
|
||
* will scroll internally if more input is entered beyond the size
|
||
* of the component. This property is meaningless if multiline is
|
||
* false. You can also set this property to "fit" and size the
|
||
* component with CSS to make the input fit the CSS size.
|
||
*
|
||
* @attribute rows
|
||
* @type number|'fit'
|
||
* @default 'fit'
|
||
*/
|
||
rows: 'fit',
|
||
|
||
/**
|
||
* The current value of this input. Changing inputValue programmatically
|
||
* will cause value to be out of sync. Instead, change value directly
|
||
* or call commit() after changing inputValue.
|
||
*
|
||
* @attribute inputValue
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
inputValue: '',
|
||
|
||
/**
|
||
* The value of the input committed by the user, either by changing the
|
||
* inputValue and blurring the input, or by hitting the `enter` key.
|
||
*
|
||
* @attribute value
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
value: '',
|
||
|
||
/**
|
||
* Set the input type. Not supported for `multiline`.
|
||
*
|
||
* @attribute type
|
||
* @type string
|
||
* @default text
|
||
*/
|
||
type: 'text',
|
||
|
||
/**
|
||
* If true, the input is invalid if its value is null.
|
||
*
|
||
* @attribute required
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
required: false,
|
||
|
||
/**
|
||
* A regular expression to validate the input value against. See
|
||
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
|
||
* for more info. Not supported if `multiline` is true.
|
||
*
|
||
* @attribute pattern
|
||
* @type string
|
||
* @default '.*'
|
||
*/
|
||
// FIXME(yvonne): The default is set to .* because we can't bind to pattern such
|
||
// that the attribute is unset if pattern is null.
|
||
pattern: '.*',
|
||
|
||
/**
|
||
* If set, the input is invalid if the value is less than this property. See
|
||
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
|
||
* for more info. Not supported if `multiline` is true.
|
||
*
|
||
* @attribute min
|
||
*/
|
||
min: null,
|
||
|
||
/**
|
||
* If set, the input is invalid if the value is greater than this property. See
|
||
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
|
||
* for more info. Not supported if `multiline` is true.
|
||
*
|
||
* @attribute max
|
||
*/
|
||
max: null,
|
||
|
||
/**
|
||
* If set, the input is invalid if the value is not `min` plus an integral multiple
|
||
* of this property. See
|
||
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
|
||
* for more info. Not supported if `multiline` is true.
|
||
*
|
||
* @attribute step
|
||
*/
|
||
step: null,
|
||
|
||
/**
|
||
* The maximum length of the input value.
|
||
*
|
||
* @attribute maxlength
|
||
* @type number
|
||
*/
|
||
maxlength: null,
|
||
|
||
/**
|
||
* If this property is true, the text input's inputValue failed validation.
|
||
*
|
||
* @attribute invalid
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
invalid: false,
|
||
|
||
/**
|
||
* If this property is true, validate the input as they are entered.
|
||
*
|
||
* @attribute validateImmediately
|
||
* @type boolean
|
||
* @default true
|
||
*/
|
||
validateImmediately: true
|
||
},
|
||
|
||
ready: function() {
|
||
this.handleTabindex(this.getAttribute('tabindex'));
|
||
},
|
||
|
||
disabledChanged: function() {
|
||
if (this.disabled) {
|
||
this.setAttribute('aria-disabled', true);
|
||
} else {
|
||
this.removeAttribute('aria-disabled');
|
||
}
|
||
},
|
||
|
||
invalidChanged: function() {
|
||
this.classList.toggle('invalid', this.invalid);
|
||
this.fire('input-'+ (this.invalid ? 'invalid' : 'valid'), {value: this.inputValue});
|
||
},
|
||
|
||
inputValueChanged: function() {
|
||
if (this.validateImmediately) {
|
||
this.updateValidity_();
|
||
}
|
||
},
|
||
|
||
valueChanged: function() {
|
||
this.inputValue = this.value;
|
||
},
|
||
|
||
requiredChanged: function() {
|
||
if (this.validateImmediately) {
|
||
this.updateValidity_();
|
||
}
|
||
},
|
||
|
||
attributeChanged: function(attr, oldVal, curVal) {
|
||
if (attr === 'tabindex') {
|
||
this.handleTabindex(curVal);
|
||
}
|
||
},
|
||
|
||
handleTabindex: function(tabindex) {
|
||
if (tabindex > 0) {
|
||
this.$.input.setAttribute('tabindex', -1);
|
||
} else {
|
||
this.$.input.removeAttribute('tabindex');
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Commits the inputValue to value.
|
||
*
|
||
* @method commit
|
||
*/
|
||
commit: function() {
|
||
this.value = this.inputValue;
|
||
},
|
||
|
||
updateValidity_: function() {
|
||
if (this.$.input.willValidate) {
|
||
this.invalid = !this.$.input.validity.valid;
|
||
}
|
||
},
|
||
|
||
keypressAction: function(e) {
|
||
// disallow non-numeric input if type = number
|
||
if (this.type !== 'number') {
|
||
return;
|
||
}
|
||
var c = String.fromCharCode(e.charCode);
|
||
if (e.charCode !== 0 && !c.match(/[\d-\.e]/)) {
|
||
e.preventDefault();
|
||
}
|
||
},
|
||
|
||
inputChangeAction: function() {
|
||
this.commit();
|
||
if (!window.ShadowDOMPolyfill) {
|
||
// re-fire event that does not bubble across shadow roots
|
||
this.fire('change', null, this);
|
||
}
|
||
},
|
||
|
||
focusAction: function(e) {
|
||
if (this.getAttribute('tabindex') > 0) {
|
||
// Forward focus to the inner input if tabindex is set on the element
|
||
// This will not cause an infinite loop because focus will not fire on the <input>
|
||
// again if it's already focused.
|
||
this.$.input.focus();
|
||
}
|
||
},
|
||
|
||
inputFocusAction: function(e) {
|
||
if (window.ShadowDOMPolyfill) {
|
||
// re-fire non-bubbling event if polyfill
|
||
this.fire('focus', null, this, false);
|
||
}
|
||
},
|
||
|
||
inputBlurAction: function() {
|
||
if (window.ShadowDOMPolyfill) {
|
||
// re-fire non-bubbling event
|
||
this.fire('blur', null, this, false);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input / textarea element.
|
||
*
|
||
* @method blur
|
||
*/
|
||
blur: function() {
|
||
this.$.input.blur();
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input / textarea element.
|
||
*
|
||
* @method click
|
||
*/
|
||
click: function() {
|
||
this.$.input.click();
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input / textarea element.
|
||
*
|
||
* @method focus
|
||
*/
|
||
focus: function() {
|
||
this.$.input.focus();
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input / textarea element.
|
||
*
|
||
* @method select
|
||
*/
|
||
select: function() {
|
||
this.$.input.select();
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input / textarea element.
|
||
*
|
||
* @method setSelectionRange
|
||
* @param {number} selectionStart
|
||
* @param {number} selectionEnd
|
||
* @param {String} selectionDirection (optional)
|
||
*/
|
||
setSelectionRange: function(selectionStart, selectionEnd, selectionDirection) {
|
||
this.$.input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input element, not implemented for multiline.
|
||
*
|
||
* @method setRangeText
|
||
* @param {String} replacement
|
||
* @param {number} start (optional)
|
||
* @param {number} end (optional)
|
||
* @param {String} selectMode (optional)
|
||
*/
|
||
setRangeText: function(replacement, start, end, selectMode) {
|
||
if (!this.multiline) {
|
||
this.$.input.setRangeText(replacement, start, end, selectMode);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input, not implemented for multiline.
|
||
*
|
||
* @method stepDown
|
||
* @param {number} n (optional)
|
||
*/
|
||
stepDown: function(n) {
|
||
if (!this.multiline) {
|
||
this.$.input.stepDown(n);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input, not implemented for multiline.
|
||
*
|
||
* @method stepUp
|
||
* @param {number} n (optional)
|
||
*/
|
||
stepUp: function(n) {
|
||
if (!this.multiline) {
|
||
this.$.input.stepUp(n);
|
||
}
|
||
},
|
||
|
||
get willValidate() {
|
||
return this.$.input.willValidate;
|
||
},
|
||
|
||
get validity() {
|
||
return this.$.input.validity;
|
||
},
|
||
|
||
get validationMessage() {
|
||
return this.$.input.validationMessage;
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input / textarea element and updates state.
|
||
*
|
||
* @method checkValidity
|
||
* @return {boolean}
|
||
*/
|
||
checkValidity: function() {
|
||
var r = this.$.input.checkValidity();
|
||
this.updateValidity_();
|
||
return r;
|
||
},
|
||
|
||
/**
|
||
* Forwards to the internal input / textarea element and updates state.
|
||
*
|
||
* @method setCustomValidity
|
||
* @param {String} message
|
||
*/
|
||
setCustomValidity: function(message) {
|
||
this.$.input.setCustomValidity(message);
|
||
this.updateValidity_();
|
||
}
|
||
|
||
});
|
||
</script>
|
||
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<!--
|
||
|
||
The `core-style` element helps manage styling inside other elements and can
|
||
be used to make themes. The `core-style` element can be either a producer
|
||
or consumer of styling. If it has its `id` property set, it's a producer.
|
||
Elements that are producers should include css styling as their text content.
|
||
If a `core-style` has its `ref` property set, it's a consumer. A `core-style`
|
||
typically sets its `ref` property to the value of the `id` property of the
|
||
`core-style` it wants to use. This allows a single producer to be used in
|
||
multiple places, for example, in many different elements.
|
||
|
||
It's common to place `core-style` producer elements inside HTMLImports.
|
||
Remote stylesheets should be included this way, the @import css mechanism is
|
||
not currently supported.
|
||
|
||
Here's a basic example:
|
||
|
||
<polymer-element name="x-test" noscript>
|
||
<template>
|
||
<core-style ref="x-test"></core-style>
|
||
<content></content>
|
||
</template>
|
||
</polymer-element>
|
||
|
||
The `x-test` element above will be styled by any `core-style` elements that have
|
||
`id` set to `x-test`. These `core-style` producers are separate from the element
|
||
definition, allowing a user of the element to style it independent of the author's
|
||
styling. For example:
|
||
|
||
<core-style id="x-test">
|
||
:host {
|
||
backgound-color: steelblue;
|
||
}
|
||
</core-style>
|
||
|
||
The content of the `x-test` `core-style` producer gets included inside the
|
||
shadowRoot of the `x-test` element. If the content of the `x-test` producer
|
||
`core-style` changes, all consumers of it are automatically kept in sync. This
|
||
allows updating styling on the fly.
|
||
|
||
The `core-style` element also supports bindings and it is the producer
|
||
`core-style` element is the model for its content. Here's an example:
|
||
|
||
<core-style id="x-test">
|
||
:host {
|
||
background-color: {{myColor}};
|
||
}
|
||
</core-style>
|
||
<script>
|
||
document._currentScript.ownerDocument.getElementById('x-test').myColor = 'orange';
|
||
</script>
|
||
|
||
Finally, to facilitate sharing data between `core-style` elements, all
|
||
`core-style` elements have a `g` property which is set to the global
|
||
`CoreStyle.g`. Here's an example:
|
||
|
||
<core-style id="x-test">
|
||
:host {
|
||
background-color: {{g.myColor}};
|
||
}
|
||
</core-style>
|
||
<script>
|
||
CoreStyle.g.myColor = 'tomato';
|
||
</script>
|
||
|
||
Finally, one `core-style` can be nested inside another. The `core-style`
|
||
element has a `list` property which is a map of all the `core-style` producers.
|
||
A `core-style` producer's content is available via its `cssText` property.
|
||
Putting this together:
|
||
|
||
<core-style id="common">
|
||
:host {
|
||
font-family: sans-serif;
|
||
}
|
||
</core-style>
|
||
|
||
<core-style id="x-test">
|
||
{{list.common.cssText}}
|
||
|
||
:host {
|
||
background-color: {{g.myColor}};
|
||
}
|
||
</core-style>
|
||
|
||
|
||
@group Polymer Core Elements
|
||
@element core-style
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-style" hidden assetpath="polymer/bower_components/core-style/">
|
||
<script>
|
||
(function() {
|
||
|
||
window.CoreStyle = window.CoreStyle || {
|
||
g: {},
|
||
list: {},
|
||
refMap: {}
|
||
};
|
||
|
||
Polymer('core-style', {
|
||
/**
|
||
* The `id` property should be set if the `core-style` is a producer
|
||
* of styles. In this case, the `core-style` should have text content
|
||
* that is cssText.
|
||
*
|
||
* @attribute id
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
|
||
|
||
publish: {
|
||
/**
|
||
* The `ref` property should be set if the `core-style` element is a
|
||
* consumer of styles. Set it to the `id` of the desired `core-style`
|
||
* element.
|
||
*
|
||
* @attribute ref
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
ref: ''
|
||
},
|
||
|
||
// static
|
||
g: CoreStyle.g,
|
||
refMap: CoreStyle.refMap,
|
||
|
||
/**
|
||
* The `list` is a map of all `core-style` producers stored by `id`. It
|
||
* should be considered readonly. It's useful for nesting one `core-style`
|
||
* inside another.
|
||
*
|
||
* @attribute list
|
||
* @type object (readonly)
|
||
* @default {map of all `core-style` producers}
|
||
*/
|
||
list: CoreStyle.list,
|
||
|
||
// if we have an id, we provide style
|
||
// if we have a ref, we consume/require style
|
||
ready: function() {
|
||
if (this.id) {
|
||
this.provide();
|
||
} else {
|
||
this.registerRef(this.ref);
|
||
if (!window.ShadowDOMPolyfill) {
|
||
this.require();
|
||
}
|
||
}
|
||
},
|
||
|
||
// can't shim until attached if using SD polyfill because need to find host
|
||
attached: function() {
|
||
if (!this.id && window.ShadowDOMPolyfill) {
|
||
this.require();
|
||
}
|
||
},
|
||
|
||
/****** producer stuff *******/
|
||
|
||
provide: function() {
|
||
this.register();
|
||
// we want to do this asap, especially so we can do so before definitions
|
||
// that use this core-style are registered.
|
||
if (this.textContent) {
|
||
this._completeProvide();
|
||
} else {
|
||
this.async(this._completeProvide);
|
||
}
|
||
},
|
||
|
||
register: function() {
|
||
var i = this.list[this.id];
|
||
if (i) {
|
||
if (!Array.isArray(i)) {
|
||
this.list[this.id] = [i];
|
||
}
|
||
this.list[this.id].push(this);
|
||
} else {
|
||
this.list[this.id] = this;
|
||
}
|
||
},
|
||
|
||
// stamp into a shadowRoot so we can monitor dom of the bound output
|
||
_completeProvide: function() {
|
||
this.createShadowRoot();
|
||
this.domObserver = new MutationObserver(this.domModified.bind(this))
|
||
.observe(this.shadowRoot, {subtree: true,
|
||
characterData: true, childList: true});
|
||
this.provideContent();
|
||
},
|
||
|
||
provideContent: function() {
|
||
this.ensureTemplate();
|
||
this.shadowRoot.textContent = '';
|
||
this.shadowRoot.appendChild(this.instanceTemplate(this.template));
|
||
this.cssText = this.shadowRoot.textContent;
|
||
},
|
||
|
||
ensureTemplate: function() {
|
||
if (!this.template) {
|
||
this.template = this.querySelector('template:not([repeat]):not([bind])');
|
||
// move content into the template
|
||
if (!this.template) {
|
||
this.template = document.createElement('template');
|
||
var n = this.firstChild;
|
||
while (n) {
|
||
this.template.content.appendChild(n.cloneNode(true));
|
||
n = n.nextSibling;
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
domModified: function() {
|
||
this.cssText = this.shadowRoot.textContent;
|
||
this.notify();
|
||
},
|
||
|
||
// notify instances that reference this element
|
||
notify: function() {
|
||
var s$ = this.refMap[this.id];
|
||
if (s$) {
|
||
for (var i=0, s; (s=s$[i]); i++) {
|
||
s.require();
|
||
}
|
||
}
|
||
},
|
||
|
||
/****** consumer stuff *******/
|
||
|
||
registerRef: function(ref) {
|
||
//console.log('register', ref);
|
||
this.refMap[this.ref] = this.refMap[this.ref] || [];
|
||
this.refMap[this.ref].push(this);
|
||
},
|
||
|
||
applyRef: function(ref) {
|
||
this.ref = ref;
|
||
this.registerRef(this.ref);
|
||
this.require();
|
||
},
|
||
|
||
require: function() {
|
||
var cssText = this.cssTextForRef(this.ref);
|
||
//console.log('require', this.ref, cssText);
|
||
if (cssText) {
|
||
this.ensureStyleElement();
|
||
// do nothing if cssText has not changed
|
||
if (this.styleElement._cssText === cssText) {
|
||
return;
|
||
}
|
||
this.styleElement._cssText = cssText;
|
||
if (window.ShadowDOMPolyfill) {
|
||
this.styleElement.textContent = cssText;
|
||
cssText = Platform.ShadowCSS.shimStyle(this.styleElement,
|
||
this.getScopeSelector());
|
||
}
|
||
this.styleElement.textContent = cssText;
|
||
}
|
||
},
|
||
|
||
cssTextForRef: function(ref) {
|
||
var s$ = this.byId(ref);
|
||
var cssText = '';
|
||
if (s$) {
|
||
if (Array.isArray(s$)) {
|
||
var p = [];
|
||
for (var i=0, l=s$.length, s; (i<l) && (s=s$[i]); i++) {
|
||
p.push(s.cssText);
|
||
}
|
||
cssText = p.join('\n\n');
|
||
} else {
|
||
cssText = s$.cssText;
|
||
}
|
||
}
|
||
if (s$ && !cssText) {
|
||
console.warn('No styles provided for ref:', ref);
|
||
}
|
||
return cssText;
|
||
},
|
||
|
||
byId: function(id) {
|
||
return this.list[id];
|
||
},
|
||
|
||
ensureStyleElement: function() {
|
||
if (!this.styleElement) {
|
||
this.styleElement = window.ShadowDOMPolyfill ?
|
||
this.makeShimStyle() :
|
||
this.makeRootStyle();
|
||
}
|
||
if (!this.styleElement) {
|
||
console.warn(this.localName, 'could not setup style.');
|
||
}
|
||
},
|
||
|
||
makeRootStyle: function() {
|
||
var style = document.createElement('style');
|
||
this.appendChild(style);
|
||
return style;
|
||
},
|
||
|
||
makeShimStyle: function() {
|
||
var host = this.findHost(this);
|
||
if (host) {
|
||
var name = host.localName;
|
||
var style = document.querySelector('style[' + name + '=' + this.ref +']');
|
||
if (!style) {
|
||
style = document.createElement('style');
|
||
style.setAttribute(name, this.ref);
|
||
document.head.appendChild(style);
|
||
}
|
||
return style;
|
||
}
|
||
},
|
||
|
||
getScopeSelector: function() {
|
||
if (!this._scopeSelector) {
|
||
var selector = '', host = this.findHost(this);
|
||
if (host) {
|
||
var typeExtension = host.hasAttribute('is');
|
||
var name = typeExtension ? host.getAttribute('is') : host.localName;
|
||
selector = Platform.ShadowCSS.makeScopeSelector(name,
|
||
typeExtension);
|
||
}
|
||
this._scopeSelector = selector;
|
||
}
|
||
return this._scopeSelector;
|
||
},
|
||
|
||
findHost: function(node) {
|
||
while (node.parentNode) {
|
||
node = node.parentNode;
|
||
}
|
||
return node.host || wrap(document.documentElement);
|
||
},
|
||
|
||
/* filters! */
|
||
// TODO(dfreedm): add more filters!
|
||
|
||
cycle: function(rgb, amount) {
|
||
if (rgb.match('#')) {
|
||
var o = this.hexToRgb(rgb);
|
||
if (!o) {
|
||
return rgb;
|
||
}
|
||
rgb = 'rgb(' + o.r + ',' + o.b + ',' + o.g + ')';
|
||
}
|
||
|
||
function cycleChannel(v) {
|
||
return Math.abs((Number(v) - amount) % 255);
|
||
}
|
||
|
||
return rgb.replace(/rgb\(([^,]*),([^,]*),([^,]*)\)/, function(m, a, b, c) {
|
||
return 'rgb(' + cycleChannel(a) + ',' + cycleChannel(b) + ', '
|
||
+ cycleChannel(c) + ')';
|
||
});
|
||
},
|
||
|
||
hexToRgb: function(hex) {
|
||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||
return result ? {
|
||
r: parseInt(result[1], 16),
|
||
g: parseInt(result[2], 16),
|
||
b: parseInt(result[3], 16)
|
||
} : null;
|
||
}
|
||
|
||
});
|
||
|
||
|
||
})();
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<core-style id="paper-input">
|
||
|
||
:host([focused]) .floated-label {
|
||
color: {{g.paperInput.focusedColor}};
|
||
}
|
||
|
||
.focused-underline,
|
||
.cursor {
|
||
background-color: {{g.paperInput.focusedColor}};
|
||
}
|
||
|
||
|
||
:host(.invalid[focused]) .floated-label,
|
||
:host([focused]) .error-text,
|
||
:host([focused]) .error-icon {
|
||
color: {{g.paperInput.invalidColor}};
|
||
}
|
||
|
||
:host(.invalid) .focused-underline,
|
||
:host(.invalid) .cursor {
|
||
background-color: {{g.paperInput.invalidColor}};
|
||
}
|
||
|
||
</core-style>
|
||
|
||
<polymer-element name="paper-input" extends="core-input" layout="" vertical="" attributes="label floatingLabel maxRows error" on-transitionend="{{transitionEndAction}}" on-webkittransitionend="{{transitionEndAction}}" assetpath="polymer/bower_components/paper-input/">
|
||
|
||
<template>
|
||
|
||
<!--
|
||
Input tests:
|
||
|
||
- set value to integer 0
|
||
- various html5 input types
|
||
- sizing:
|
||
- single-line: size with CSS
|
||
- single-line: can fit to container
|
||
- multi-line: size with CSS
|
||
- multi-line: size with rows
|
||
- multi-line: can fit to container
|
||
- multi-line: grows with typing
|
||
- multi-line: max rows
|
||
- multi-line: max rows, scrolls after
|
||
-->
|
||
|
||
<style>/*
|
||
* @license
|
||
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
* Code distributed by Google as part of the polymer project is also
|
||
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: inline-block;
|
||
outline: none;
|
||
text-align: inherit;
|
||
color: #757575;
|
||
padding: 0.75em 0;
|
||
}
|
||
|
||
:host /deep/ input,
|
||
:host /deep/ textarea {
|
||
font: inherit;
|
||
color: #000;
|
||
padding: 0;
|
||
margin: 0;
|
||
background-color: transparent;
|
||
border: none;
|
||
outline: none;
|
||
/* see comments in template */
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
input:invalid,
|
||
textarea:invalid {
|
||
box-shadow: none;
|
||
}
|
||
|
||
textarea {
|
||
resize: none;
|
||
}
|
||
|
||
[invisible] {
|
||
visibility: hidden;
|
||
}
|
||
|
||
[animated] {
|
||
visibility: visible !important;
|
||
-webkit-transition: -webkit-transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
.floated-label {
|
||
font-size: 0.75em;
|
||
background: transparent;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.mirror-text {
|
||
padding: 0.5em 0 0.25em;
|
||
max-width: 100%;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
:host([multiline]) .mirror-text {
|
||
white-space: pre-wrap;
|
||
word-wrap: break-word;
|
||
}
|
||
|
||
.label {
|
||
padding: 0.5em 0 0.25em;
|
||
background: transparent;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.label-text {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
display: inline-block;
|
||
max-width: 100%;
|
||
-moz-transform-origin: 0% 0%;
|
||
-webkit-transform-origin: 0% 0%;
|
||
transform-origin: 0% 0%;
|
||
}
|
||
|
||
.cursor {
|
||
position: absolute;
|
||
top: 0.4em;
|
||
left: 0;
|
||
width: 1px;
|
||
height: 1.4em;
|
||
opacity: 0.4;
|
||
-moz-transform-origin: 0%;
|
||
-webkit-transform-origin: 0%;
|
||
transform-origin: 0%;
|
||
-webkit-transform: none;
|
||
transform: none;
|
||
}
|
||
|
||
.cursor[invisible] {
|
||
opacity: 0.75;
|
||
-webkit-transform: translate3d(3em,0,0) scale3d(50,1,1);
|
||
transform: translate3d(3em,0,0) scale3d(50,1,1);
|
||
}
|
||
|
||
.input-container {
|
||
position: absolute;
|
||
/* simulate padding so the input/textarea can use 100% width/height */
|
||
top: 0.5em;
|
||
right: 0;
|
||
bottom: 0.25em;
|
||
left: 0;
|
||
}
|
||
|
||
.underline {
|
||
height: 0px;
|
||
overflow: visible;
|
||
}
|
||
|
||
:host([disabled]) .underline {
|
||
border-bottom: 1px dashed;
|
||
}
|
||
|
||
.unfocused-underline {
|
||
height: 1px;
|
||
background: #757575;
|
||
border-bottom-color: #757575;
|
||
}
|
||
|
||
.focused-underline {
|
||
height: 2px;
|
||
-webkit-transform: none;
|
||
transform: none;
|
||
}
|
||
|
||
.focused-underline[invisible] {
|
||
-webkit-transform: scale3d(0,1,1);
|
||
transform: scale3d(0,1,1);
|
||
}
|
||
|
||
.error-text {
|
||
font-size: 0.75em;
|
||
padding: 0.5em 0;
|
||
}
|
||
|
||
.error-icon {
|
||
height: 20px;
|
||
width: 20px;
|
||
}
|
||
</style>
|
||
<core-style ref="paper-input"></core-style>
|
||
|
||
<div class="floated-label" aria-hidden="true" hidden?="{{!floatingLabel}}" invisible?="{{!inputValue && !(type === 'number' && !validity.valid) || labelAnimated}}">
|
||
<!-- needed for floating label animation measurement -->
|
||
<span id="floatedLabelText" class="label-text">{{label}}</span>
|
||
</div>
|
||
|
||
<!-- <div class="input-body" flex auto relative on-down="{{downAction}}" on-up="{{upAction}}"> -->
|
||
<div class="input-body" flex="" auto="" relative="">
|
||
|
||
<!-- the mirror sizes the input/textarea so it grows with typing -->
|
||
<div id="mirror" class="mirror-text" invisible="" aria-hidden="true"></div>
|
||
|
||
<div class="label" fit="" aria-hidden="true">
|
||
<!-- needed for floating label animation measurement -->
|
||
<span id="labelText" class="label-text" invisible?="{{inputValue || !inputValue && type === 'number' && !validity.valid}}" animated?="{{labelAnimated}}">{{label}}</span>
|
||
</div>
|
||
|
||
<div class="cursor" invisible?="{{!cursorAnimated}}" animated?="{{cursorAnimated}}"></div>
|
||
|
||
<!-- size the input/textarea with a div, because the textarea has intrinsic size in ff -->
|
||
<div class="input-container" on-down="{{downAction}}" on-up="{{upAction}}">
|
||
<shadow></shadow>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div id="underline" class="underline" relative="">
|
||
<div class="unfocused-underline" fit="" invisible?="{{disabled}}"></div>
|
||
<div id="focusedUnderline" class="focused-underline" fit="" invisible?="{{!focused}}" animated?="{{underlineAnimated}}"></div>
|
||
</div>
|
||
|
||
<div layout="" horizontal="" center="" hidden?="{{!invalid}}">
|
||
<div class="error-text" flex="" auto="" role="alert" aria-hidden="{{!invalid}}">{{error || validationMessage}}</div>
|
||
<core-icon class="error-icon" icon="warning"></core-icon>
|
||
</div>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
|
||
(function() {
|
||
|
||
var paperInput = CoreStyle.g.paperInput = CoreStyle.g.paperInput || {};
|
||
paperInput.focusedColor = '#4059a9';
|
||
paperInput.invalidColor = '#d34336';
|
||
|
||
Polymer('paper-input', {
|
||
|
||
publish: {
|
||
/**
|
||
* The label for this input. It normally appears as grey text inside
|
||
* the text input and disappears once the user enters text.
|
||
*
|
||
* @attribute label
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
label: '',
|
||
|
||
/**
|
||
* If true, the label will "float" above the text input once the
|
||
* user enters text instead of disappearing.
|
||
*
|
||
* @attribute floatingLabel
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
floatingLabel: false,
|
||
|
||
/**
|
||
* (multiline only) If set to a non-zero value, the height of this
|
||
* text input will grow with the value changes until it is maxRows
|
||
* rows tall. If the maximum size does not fit the value, the text
|
||
* input will scroll internally.
|
||
*
|
||
* @attribute maxRows
|
||
* @type number
|
||
* @default 0
|
||
*/
|
||
maxRows: 0,
|
||
|
||
/**
|
||
* The message to display if the input value fails validation. If this
|
||
* is unset or the empty string, a default message is displayed depending
|
||
* on the type of validation error.
|
||
*
|
||
* @attribute error
|
||
* @type string
|
||
*/
|
||
error: '',
|
||
|
||
focused: {value: false, reflect: true}
|
||
|
||
},
|
||
|
||
get inputValueForMirror() {
|
||
var tokens = this.inputValue ? String(this.inputValue).replace(/&/gm, '&').replace(/"/gm, '"').replace(/'/gm, ''').replace(/</gm, '<').replace(/>/gm, '>').split('\n') : [''];
|
||
|
||
// Enforce the min and max heights for a multiline input here to
|
||
// avoid measurement
|
||
if (this.multiline) {
|
||
if (this.maxRows && tokens.length > this.maxRows) {
|
||
tokens = tokens.slice(0, this.maxRows);
|
||
}
|
||
while (this.rows && tokens.length < this.rows) {
|
||
tokens.push('');
|
||
}
|
||
}
|
||
|
||
return tokens.join('<br>') + ' ';
|
||
},
|
||
|
||
get inputHasValue() {
|
||
// if type = number, the input value is the empty string until a valid number
|
||
// is entered so we must do some hacks here
|
||
return this.inputValue || (this.type === 'number' && !this.validity.valid);
|
||
},
|
||
|
||
syncInputValueToMirror: function() {
|
||
this.$.mirror.innerHTML = this.inputValueForMirror;
|
||
},
|
||
|
||
ready: function() {
|
||
this.syncInputValueToMirror();
|
||
},
|
||
|
||
prepareLabelTransform: function() {
|
||
var toRect = this.$.floatedLabelText.getBoundingClientRect();
|
||
var fromRect = this.$.labelText.getBoundingClientRect();
|
||
if (toRect.width !== 0) {
|
||
var sy = toRect.height / fromRect.height;
|
||
this.$.labelText.cachedTransform =
|
||
'scale3d(' + (toRect.width / fromRect.width) + ',' + sy + ',1) ' +
|
||
'translate3d(0,' + (toRect.top - fromRect.top) / sy + 'px,0)';
|
||
}
|
||
},
|
||
|
||
animateFloatingLabel: function() {
|
||
if (!this.floatingLabel || this.labelAnimated) {
|
||
return;
|
||
}
|
||
|
||
if (!this.$.labelText.cachedTransform) {
|
||
this.prepareLabelTransform();
|
||
}
|
||
|
||
// If there's still no cached transform, the input is invisible so don't
|
||
// do the animation.
|
||
if (!this.$.labelText.cachedTransform) {
|
||
return;
|
||
}
|
||
|
||
this.labelAnimated = true;
|
||
// Handle interrupted animation
|
||
this.async(function() {
|
||
this.transitionEndAction();
|
||
}, null, 250);
|
||
|
||
if (this.inputHasValue) {
|
||
this.$.labelText.style.webkitTransform = this.$.labelText.cachedTransform;
|
||
this.$.labelText.style.transform = this.$.labelText.cachedTransform;
|
||
} else {
|
||
// Handle if the label started out floating
|
||
if (!this.$.labelText.style.webkitTransform && !this.$.labelText.style.transform) {
|
||
this.$.labelText.style.webkitTransform = this.$.labelText.cachedTransform;
|
||
this.$.labelText.style.transform = this.$.labelText.cachedTransform;
|
||
this.$.labelText.offsetTop;
|
||
}
|
||
this.$.labelText.style.webkitTransform = '';
|
||
this.$.labelText.style.transform = '';
|
||
}
|
||
},
|
||
|
||
inputValueChanged: function(old) {
|
||
this.super();
|
||
|
||
this.syncInputValueToMirror();
|
||
if (old && !this.inputValue || !old && this.inputValue) {
|
||
this.animateFloatingLabel();
|
||
}
|
||
},
|
||
|
||
placeholderChanged: function() {
|
||
this.label = this.placeholder;
|
||
},
|
||
|
||
inputFocusAction: function() {
|
||
this.super(arguments);
|
||
this.focused = true;
|
||
},
|
||
|
||
inputBlurAction: function(e) {
|
||
this.super(arguments);
|
||
this.focused = false;
|
||
},
|
||
|
||
downAction: function(e) {
|
||
if (this.disabled) {
|
||
return;
|
||
}
|
||
|
||
if (this.focused) {
|
||
return;
|
||
}
|
||
|
||
// The underline spills from the tap location
|
||
var rect = this.$.underline.getBoundingClientRect();
|
||
var right = e.x - rect.left;
|
||
this.$.focusedUnderline.style.mozTransformOrigin = right + 'px';
|
||
this.$.focusedUnderline.style.webkitTransformOrigin = right + 'px ';
|
||
this.$.focusedUnderline.style.transformOriginX = right + 'px';
|
||
|
||
// Animations only run when the user interacts with the input
|
||
this.underlineAnimated = true;
|
||
|
||
// Cursor animation only runs if the input is empty
|
||
if (!this.inputHasValue) {
|
||
this.cursorAnimated = true;
|
||
}
|
||
// Handle interrupted animation
|
||
this.async(function() {
|
||
this.transitionEndAction();
|
||
}, null, 250);
|
||
},
|
||
|
||
keydownAction: function() {
|
||
this.super();
|
||
|
||
// more type = number hacks. see core-input for more info
|
||
if (this.type === 'number') {
|
||
var valid = !this.inputValue && this.validity.valid;
|
||
this.async(function() {
|
||
if (valid !== (!this.inputValue && this.validity.valid)) {
|
||
this.animateFloatingLabel();
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
transitionEndAction: function() {
|
||
this.underlineAnimated = false;
|
||
this.cursorAnimated = false;
|
||
this.labelAnimated = false;
|
||
}
|
||
|
||
});
|
||
|
||
}());
|
||
|
||
</script>
|
||
|
||
</polymer-element>
|
||
</div>
|
||
|
||
<div hidden><!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`core-header-panel` contains a header section and a content panel section.
|
||
|
||
__Important:__ The `core-header-panel` will not display if its parent does not have a height.
|
||
|
||
Using [layout attributes](http://www.polymer-project.org/docs/polymer/layout-attrs.html), you can easily make the `core-header-panel` fill the screen
|
||
|
||
<body fullbleed layout vertical>
|
||
<core-header-panel flex>
|
||
<core-toolbar>
|
||
<div>Hello World!</div>
|
||
</core-toolbar>
|
||
</core-header-panel>
|
||
</body>
|
||
|
||
or, if you would prefer to do it in CSS, just give `html`, `body`, and `core-header-panel` a height of 100%:
|
||
|
||
html, body {
|
||
height: 100%;
|
||
margin: 0;
|
||
}
|
||
core-header-panel {
|
||
height: 100%;
|
||
}
|
||
|
||
Special support is provided for scrolling modes when one uses a core-toolbar or equivalent
|
||
for the header section.
|
||
|
||
Example:
|
||
|
||
<core-header-panel>
|
||
<core-toolbar>Header</core-toolbar>
|
||
<div>Content goes here...</div>
|
||
</core-header-panel>
|
||
|
||
If you want to use other than `core-toolbar` for the header, add
|
||
`core-header` class to that element.
|
||
|
||
Example:
|
||
|
||
<core-header-panel>
|
||
<div class="core-header">Header</div>
|
||
<div>Content goes here...</div>
|
||
</core-header-panel>
|
||
|
||
To have the content fits to the main area, use `fit` attribute.
|
||
|
||
<core-header-panel>
|
||
<div class="core-header">standard</div>
|
||
<div class="content" fit>content fits 100% below the header</div>
|
||
</core-header-panel>
|
||
|
||
Use `mode` to control the header and scrolling behavior.
|
||
|
||
@group Polymer Core Elements
|
||
@element core-header-panel
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-header-panel" assetpath="polymer/bower_components/core-header-panel/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: block;
|
||
position: relative;
|
||
}
|
||
|
||
#outerContainer {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
#mainPanel {
|
||
position: relative;
|
||
}
|
||
|
||
#mainContainer {
|
||
position: relative;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
#dropShadow {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 6px;
|
||
box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
#dropShadow.hidden {
|
||
display: none;
|
||
}
|
||
|
||
/*
|
||
mode: scroll
|
||
*/
|
||
:host([mode=scroll]) #mainContainer {
|
||
overflow: visible;
|
||
}
|
||
|
||
:host([mode=scroll]) #outerContainer {
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
/*
|
||
mode: cover
|
||
*/
|
||
:host([mode=cover]) #mainPanel {
|
||
position: static;
|
||
}
|
||
|
||
:host([mode=cover]) #mainContainer {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
:host([mode=cover]) #dropShadow {
|
||
position: static;
|
||
width: 100%;
|
||
}
|
||
</style>
|
||
|
||
<div id="outerContainer" vertical="" layout="">
|
||
|
||
<content id="headerContent" select="core-toolbar, .core-header"></content>
|
||
|
||
<div id="mainPanel" flex="" vertical="" layout="">
|
||
|
||
<div id="mainContainer" flex?="{{mode !== 'cover'}}">
|
||
<content id="mainContent" select="*"></content>
|
||
</div>
|
||
|
||
<div id="dropShadow"></div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('core-header-panel', {
|
||
|
||
/**
|
||
* Fired when the content has been scrolled. `event.detail.target` returns
|
||
* the scrollable element which you can use to access scroll info such as
|
||
* `scrollTop`.
|
||
*
|
||
* <core-header-panel on-scroll="{{scrollHandler}}">
|
||
* ...
|
||
* </core-header-panel>
|
||
*
|
||
*
|
||
* scrollHandler: function(event) {
|
||
* var scroller = event.detail.target;
|
||
* console.log(scroller.scrollTop);
|
||
* }
|
||
*
|
||
* @event scroll
|
||
*/
|
||
|
||
publish: {
|
||
/**
|
||
* Controls header and scrolling behavior. Options are
|
||
* `standard`, `seamed`, `waterfall`, `waterfall-tall`, `scroll` and
|
||
* `cover`. Default is `standard`.
|
||
*
|
||
* `standard`: The header is a step above the panel. The header will consume the
|
||
* panel at the point of entry, preventing it from passing through to the
|
||
* opposite side.
|
||
*
|
||
* `seamed`: The header is presented as seamed with the panel.
|
||
*
|
||
* `waterfall`: Similar to standard mode, but header is initially presented as
|
||
* seamed with panel, but then separates to form the step.
|
||
*
|
||
* `waterfall-tall`: The header is initially taller (`tall` class is added to
|
||
* the header). As the user scrolls, the header separates (forming an edge)
|
||
* while condensing (`tall` class is removed from the header).
|
||
*
|
||
* `scroll`: The header keeps its seam with the panel, and is pushed off screen.
|
||
*
|
||
* `cover`: The panel covers the whole `core-header-panel` including the
|
||
* header. This allows user to style the panel in such a way that the panel is
|
||
* partially covering the header.
|
||
*
|
||
* <style>
|
||
* core-header-panel[mode=cover]::shadow #mainContainer {
|
||
* left: 80px;
|
||
* }
|
||
* .content {
|
||
* margin: 60px 60px 60px 0;
|
||
* }
|
||
* </style>
|
||
*
|
||
* <core-header-panel mode="cover">
|
||
* <core-appbar class="tall">
|
||
* <core-icon-button icon="menu"></core-icon-button>
|
||
* </core-appbar>
|
||
* <div class="content"></div>
|
||
* </core-header-panel>
|
||
*
|
||
* @attribute mode
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
mode: {value: '', reflect: true},
|
||
|
||
/**
|
||
* The class used in waterfall-tall mode. Change this if the header
|
||
* accepts a different class for toggling height, e.g. "medium-tall"
|
||
*
|
||
* @attribute tallClass
|
||
* @type string
|
||
* @default 'tall'
|
||
*/
|
||
tallClass: 'tall',
|
||
|
||
/**
|
||
* If true, the drop-shadow is always shown no matter what mode is set to.
|
||
*
|
||
* @attribute shadow
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
shadow: false
|
||
},
|
||
|
||
animateDuration: 200,
|
||
|
||
modeConfigs: {
|
||
shadowMode: {'waterfall': 1, 'waterfall-tall': 1},
|
||
noShadow: {'seamed': 1, 'cover': 1, 'scroll': 1},
|
||
tallMode: {'waterfall-tall': 1},
|
||
outerScroll: {'scroll': 1}
|
||
},
|
||
|
||
ready: function() {
|
||
this.scrollHandler = this.scroll.bind(this);
|
||
this.addListener();
|
||
},
|
||
|
||
detached: function() {
|
||
this.removeListener(this.mode);
|
||
},
|
||
|
||
addListener: function() {
|
||
this.scroller.addEventListener('scroll', this.scrollHandler);
|
||
},
|
||
|
||
removeListener: function(mode) {
|
||
var s = this.getScrollerForMode(mode);
|
||
s.removeEventListener('scroll', this.scrollHandler);
|
||
},
|
||
|
||
domReady: function() {
|
||
this.async('scroll');
|
||
},
|
||
|
||
modeChanged: function(old) {
|
||
var header = this.header;
|
||
if (header) {
|
||
var configs = this.modeConfigs;
|
||
// in tallMode it may add tallClass to the header; so do the cleanup
|
||
// when mode is changed from tallMode to not tallMode
|
||
if (configs.tallMode[old] && !configs.tallMode[this.mode]) {
|
||
header.classList.remove(this.tallClass);
|
||
this.async(function() {
|
||
header.classList.remove('animate');
|
||
}, null, this.animateDuration);
|
||
} else {
|
||
header.classList.toggle('animate', configs.tallMode[this.mode]);
|
||
}
|
||
}
|
||
if (configs.outerScroll[this.mode] || configs.outerScroll[old]) {
|
||
this.removeListener(old);
|
||
this.addListener();
|
||
}
|
||
this.scroll();
|
||
},
|
||
|
||
get header() {
|
||
return this.$.headerContent.getDistributedNodes()[0];
|
||
},
|
||
|
||
getScrollerForMode: function(mode) {
|
||
return this.modeConfigs.outerScroll[mode] ?
|
||
this.$.outerContainer : this.$.mainContainer;
|
||
},
|
||
|
||
/**
|
||
* Returns the scrollable element.
|
||
*
|
||
* @property scroller
|
||
* @type Object
|
||
*/
|
||
get scroller() {
|
||
return this.getScrollerForMode(this.mode);
|
||
},
|
||
|
||
scroll: function() {
|
||
var configs = this.modeConfigs;
|
||
var main = this.$.mainContainer;
|
||
var header = this.header;
|
||
|
||
var sTop = main.scrollTop;
|
||
var atTop = sTop === 0;
|
||
|
||
this.$.dropShadow.classList.toggle('hidden', !this.shadow &&
|
||
(atTop && configs.shadowMode[this.mode] || configs.noShadow[this.mode]));
|
||
|
||
if (header && configs.tallMode[this.mode]) {
|
||
header.classList.toggle(this.tallClass, atTop ||
|
||
header.classList.contains(this.tallClass) &&
|
||
main.scrollHeight < this.$.outerContainer.offsetHeight);
|
||
}
|
||
|
||
this.fire('scroll', {target: this.scroller}, this, false);
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`core-toolbar` is a horizontal bar containing elements that can be used for
|
||
label, navigation, search and actions.
|
||
|
||
<core-toolbar>
|
||
<core-icon-button icon="menu" on-tap="{{menuAction}}"></core-icon-button>
|
||
<div flex>Title</div>
|
||
<core-icon-button icon="more" on-tap="{{moreAction}}"></core-icon-button>
|
||
</core-toolbar>
|
||
|
||
`core-toolbar` has a standard height, but can made be taller by setting `tall`
|
||
class on the `core-toolbar`. This will make the toolbar 3x the normal height.
|
||
|
||
<core-toolbar class="tall">
|
||
<core-icon-button icon="menu"></core-icon-button>
|
||
</core-toolbar>
|
||
|
||
Apply `medium-tall` class to make the toolbar medium tall. This will make the
|
||
toolbar 2x the normal height.
|
||
|
||
<core-toolbar class="medium-tall">
|
||
<core-icon-button icon="menu"></core-icon-button>
|
||
</core-toolbar>
|
||
|
||
When taller, elements can pin to either the top (default), middle or bottom.
|
||
|
||
<core-toolbar class="tall">
|
||
<core-icon-button icon="menu"></core-icon-button>
|
||
<div class="middle indent">Middle Title</div>
|
||
<div class="bottom indent">Bottom Title</div>
|
||
</core-toolbar>
|
||
|
||
To make an element completely fit at the bottom of the toolbar, use `fit` along
|
||
with `bottom`.
|
||
|
||
<core-toolbar class="tall">
|
||
<div id="progressBar" class="bottom fit"></div>
|
||
</core-toolbar>
|
||
|
||
`core-toolbar` adapts to mobile/narrow layout when there is a `core-narrow` class set
|
||
on itself or any of its ancestors.
|
||
|
||
@group Polymer Core Elements
|
||
@element core-toolbar
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-toolbar" assetpath="polymer/bower_components/core-toolbar/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
/* technical */
|
||
display: block;
|
||
position: relative;
|
||
box-sizing: border-box;
|
||
-moz-box-sizing: border-box;
|
||
/* size */
|
||
height: 64px;
|
||
/* typography */
|
||
font-size: 1.3em;
|
||
/* background */
|
||
background-color: #CFD8DC;
|
||
}
|
||
|
||
:host(.animate) {
|
||
/* transition */
|
||
transition: height 0.18s ease-in;
|
||
}
|
||
|
||
:host(.medium-tall) {
|
||
height: 128px;
|
||
}
|
||
|
||
:host(.tall) {
|
||
height: 192px;
|
||
}
|
||
|
||
.toolbar-tools {
|
||
position: relative;
|
||
height: 64px;
|
||
padding: 0 8px;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* narrow layout */
|
||
:host(.core-narrow),
|
||
:host-context(.core-narrow) {
|
||
height: 56px;
|
||
}
|
||
|
||
polyfill-next-selector { content: ':host.core-narrow.medium-tall, .core-narrow :host.medium-tall'; }
|
||
:host(.core-narrow.medium-tall),
|
||
:host-context(.core-narrow):host(.medium-tall) {
|
||
height: 112px;
|
||
}
|
||
|
||
polyfill-next-selector { content: ':host.core-narrow.tall, .core-narrow :host.tall'; }
|
||
:host(.core-narrow.tall),
|
||
:host-context(.core-narrow):host(.tall) {
|
||
height: 168px;
|
||
}
|
||
|
||
polyfill-next-selector { content: ':host.core-narrow .toolbar-tools, .core-narrow :host .toolbar-tools'; }
|
||
:host(.core-narrow) .toolbar-tools,
|
||
:host-context(.core-narrow) .toolbar-tools {
|
||
height: 56px;
|
||
padding: 0;
|
||
}
|
||
|
||
/* middle bar */
|
||
#middleBar {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
left: 0;
|
||
}
|
||
|
||
:host(.tall, .medium-tall) #middleBar {
|
||
-webkit-transform: translateY(100%);
|
||
transform: translateY(100%);
|
||
}
|
||
|
||
/* bottom bar */
|
||
#bottomBar {
|
||
position: absolute;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
/* make elements (e.g. buttons) respond to mouse/touch events */
|
||
polyfill-next-selector { content: '.toolbar-tools > *'; }
|
||
::content > * {
|
||
pointer-events: auto;
|
||
}
|
||
|
||
/* elements spacing */
|
||
polyfill-next-selector { content: '.toolbar-tools > *'; }
|
||
::content > * {
|
||
margin: 0 8px;
|
||
}
|
||
|
||
/* misc helpers */
|
||
polyfill-next-selector { content: '.toolbar-tools > .fit'; }
|
||
::content > .fit {
|
||
position: absolute;
|
||
top: auto;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: auto;
|
||
margin: 0;
|
||
}
|
||
|
||
polyfill-next-selector { content: ':host .indent'; }
|
||
::content > .indent {
|
||
margin-left: 60px;
|
||
}
|
||
</style>
|
||
|
||
<div id="bottomBar" class="toolbar-tools" center="" horizontal="" layout="">
|
||
<content select=".bottom"></content>
|
||
</div>
|
||
|
||
<div id="middleBar" class="toolbar-tools" center="" horizontal="" layout="">
|
||
<content select=".middle"></content>
|
||
</div>
|
||
|
||
<div id="topBar" class="toolbar-tools" center="" horizontal="" layout="">
|
||
<content></content>
|
||
</div>
|
||
|
||
</template>
|
||
<script>Polymer('core-toolbar');</script></polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
|
||
-->
|
||
|
||
<!--
|
||
@group Paper Elements
|
||
|
||
Material Design: <a href="https://spec.googleplex.com/quantum/components/buttons.html">Buttons</a>
|
||
|
||
`paper-icon-button` is a button with an image placed at the center. When the user touches
|
||
the button, a ripple effect emanates from the center of the button.
|
||
|
||
You may import `core-icons` to use with this element, or provide an URL to a custom icon.
|
||
See `core-iconset` for more information about how to use a custom icon set.
|
||
|
||
Example:
|
||
|
||
<link href="path/to/core-icons/core-icons.html" rel="import">
|
||
|
||
<paper-icon-button icon="favorite"></paper-icon-button>
|
||
<paper-icon-button src="star.png"></paper-icon-button>
|
||
|
||
Styling
|
||
-------
|
||
|
||
Style the button with CSS as you would a normal DOM element. If you are using the icons
|
||
provided by `core-icons`, they will inherit the foreground color of the button.
|
||
|
||
/* make a red "favorite" button */
|
||
<paper-icon-button icon="favorite" style="color: red;"></paper-icon-button>
|
||
|
||
By default, the ripple is the same color as the foreground at 25% opacity. You may
|
||
customize the color using this selector:
|
||
|
||
/* make #my-button use a blue ripple instead of foreground color */
|
||
#my-button::shadow #ripple {
|
||
color: blue;
|
||
}
|
||
|
||
The opacity of the ripple is not customizable via CSS.
|
||
|
||
Accessibility
|
||
-------------
|
||
|
||
The button is accessible by default if you use the `icon` property. By default, the
|
||
`aria-label` attribute will be set to the `icon` property. If you use a custom icon,
|
||
you should ensure that the `aria-label` attribute is set.
|
||
|
||
<paper-icon-button src="star.png" aria-label="star"></paper-icon-button>
|
||
|
||
@element paper-icon-button
|
||
@extends paper-button-base
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<polymer-element name="paper-icon-button" extends="paper-button-base" attributes="src icon" role="button" assetpath="polymer/bower_components/paper-icon-button/">
|
||
|
||
<template>
|
||
|
||
<style>
|
||
:host {
|
||
display: inline-block;
|
||
position: relative;
|
||
padding: 8px;
|
||
outline: none;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
cursor: pointer;
|
||
z-index: 0;
|
||
}
|
||
|
||
:host([disabled]) {
|
||
color: #c9c9c9;
|
||
pointer-events: none;
|
||
cursor: auto;
|
||
}
|
||
|
||
#ripple {
|
||
pointer-events: none;
|
||
z-index: -1;
|
||
}
|
||
</style>
|
||
|
||
<!-- to position to ripple behind the icon -->
|
||
<core-icon relative="" id="icon" src="{{src}}" icon="{{icon}}"></core-icon>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
Polymer('paper-icon-button',{
|
||
|
||
publish: {
|
||
|
||
/**
|
||
* The URL of an image for the icon. If the src property is specified,
|
||
* the icon property should not be.
|
||
*
|
||
* @attribute src
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
src: '',
|
||
|
||
/**
|
||
* Specifies the icon name or index in the set of icons available in
|
||
* the icon's icon set. If the icon property is specified,
|
||
* the src property should not be.
|
||
*
|
||
* @attribute icon
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
icon: '',
|
||
|
||
recenteringTouch: true,
|
||
fill: false
|
||
|
||
},
|
||
|
||
iconChanged: function(oldIcon) {
|
||
this.setAttribute('aria-label', this.icon);
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
@group Paper Elements
|
||
|
||
`paper-item` is a list-item object for use in menus. It may contain and icon and/or
|
||
a text label.
|
||
|
||
Example:
|
||
|
||
<core-menu>
|
||
<paper-item icon="refresh" label="Refresh"></paper-item>
|
||
<paper-item label="Help"></paper-item>
|
||
<paper-item label="Sign Out"></paper-item>
|
||
</core-menu>
|
||
|
||
To use as a link, put an `<a>` element in the item.
|
||
|
||
Example:
|
||
|
||
<paper-item icon="home" label="Home">
|
||
<a href="http://www.polymer-project.org"></a>
|
||
</paper-item>
|
||
|
||
@class paper-item
|
||
-->
|
||
|
||
|
||
|
||
|
||
|
||
<style shim-shadowdom="">/*
|
||
* @license
|
||
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
* Code distributed by Google as part of the polymer project is also
|
||
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
html /deep/ paper-item {
|
||
display: block;
|
||
position: relative;
|
||
font-size: 16px;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
cursor: pointer;
|
||
box-sizing: border-box;
|
||
height: 48px;
|
||
padding: 0 16px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
html /deep/ paper-item::shadow #ripple {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
bottom: 0;
|
||
right: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
html /deep/ paper-item::shadow #icon {
|
||
margin-right: 8px;
|
||
}
|
||
|
||
html /deep/ paper-item::shadow ::content > a {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
</style>
|
||
|
||
<polymer-element name="paper-item" attributes="label iconSrc icon" center="" horizontal="" layout="" assetpath="polymer/bower_components/paper-item/">
|
||
|
||
<template>
|
||
|
||
<paper-ripple id="ripple"></paper-ripple>
|
||
|
||
<core-icon id="icon" hidden?="{{!iconSrc && !icon}}" src="{{iconSrc}}" icon="{{icon}}"></core-icon>
|
||
<div id="label">{{label}}</div>
|
||
<content></content>
|
||
</template>
|
||
|
||
<script>
|
||
Polymer('paper-item', {
|
||
|
||
publish: {
|
||
|
||
/**
|
||
* The label for the item.
|
||
*
|
||
* @attribute label
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
label: '',
|
||
|
||
/**
|
||
* (optional) The URL of an image for an icon to use in the button.
|
||
* Should not use `icon` property if you are using this property.
|
||
*
|
||
* @attribute iconSrc
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
iconSrc: '',
|
||
|
||
/**
|
||
* (optional) Specifies the icon name or index in the set of icons
|
||
* available in the icon set. If using this property, load the icon
|
||
* set separately where the icon is used. Should not use `src`
|
||
* if you are using this property.
|
||
*
|
||
* @attribute icon
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
icon: ''
|
||
|
||
},
|
||
|
||
eventDelegates: {
|
||
'down': 'downAction',
|
||
'up': 'upAction'
|
||
},
|
||
|
||
downAction: function(e) {
|
||
this.$.ripple.downAction(e);
|
||
},
|
||
|
||
upAction: function(e) {
|
||
this.$.ripple.upAction(e);
|
||
}
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<!--
|
||
A `paper-menu-button` is a `paper-icon-button` that opens a drop down menu when tapped.
|
||
|
||
Example:
|
||
|
||
<paper-menu-button icon="menu">
|
||
<div>Menu Item 1</div>
|
||
<div>Menu Item 2</div>
|
||
<div>Menu Item 3</div>
|
||
</paper-menu-button>
|
||
|
||
Theming
|
||
=======
|
||
|
||
To change the text color in the menu:
|
||
|
||
paper-menu-button::shadow #menu {
|
||
color: white;
|
||
}
|
||
|
||
To change the overlay background color:
|
||
|
||
paper-menu-button::shadow .paper-menu-button-overlay-bg {
|
||
background: green;
|
||
}
|
||
|
||
To change the color of the ripple effect:
|
||
|
||
paper-menu-button:shadow .paper-menu-button-overlay-ink {
|
||
background: red;
|
||
}
|
||
|
||
@group Paper Elements
|
||
@element paper-menu-button
|
||
@extends paper-focusable
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
|
||
`core-dropdown` is an element that is initially hidden and is positioned relatively to another
|
||
element, usually the element that triggers the dropdown. The dropdown and the triggering element
|
||
should be children of the same offsetParent, e.g. the same `<div>` with `position: relative`.
|
||
It can be used to implement dropdown menus, menu buttons, etc..
|
||
|
||
Example:
|
||
|
||
<template is="auto-binding">
|
||
<div relative>
|
||
<core-icon-button id="trigger" icon="menu"></core-icon-button>
|
||
<core-dropdown relatedTarget="{{$.trigger}}">
|
||
<core-menu>
|
||
<core-item>Cut</core-item>
|
||
<core-item>Copy</core-item>
|
||
<core-item>Paste</core-item>
|
||
</core-menu>
|
||
</core-dropdown>
|
||
</div>
|
||
</template>
|
||
|
||
Positioning
|
||
-----------
|
||
|
||
By default, the dropdown is absolutely positioned on top of the `relatedTarget` with the top and
|
||
left edges aligned. The `halign` and `valign` properties controls the various alignments. The size
|
||
of the dropdown is automatically restrained such that it is entirely visible on the screen. Use the
|
||
`margin`
|
||
|
||
If you need more control over the dropdown's position, use CSS. The `halign` and `valign` properties are
|
||
ignored if the dropdown is positioned with CSS.
|
||
|
||
Example:
|
||
|
||
<style>
|
||
/* manually position the dropdown below the trigger */
|
||
core-dropdown {
|
||
position: absolute;
|
||
top: 38px;
|
||
left: 0;
|
||
}
|
||
</style>
|
||
|
||
<template is="auto-binding">
|
||
<div relative>
|
||
<core-icon-button id="trigger" icon="menu"></core-icon-button>
|
||
<core-dropdown relatedTarget="{{$.trigger}}">
|
||
<core-menu>
|
||
<core-item>Cut</core-item>
|
||
<core-item>Copy</core-item>
|
||
<core-item>Paste</core-item>
|
||
</core-menu>
|
||
</core-dropdown>
|
||
</div>
|
||
</template>
|
||
|
||
@group Polymer Core Elements
|
||
@element core-dropdown
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
|
||
`<core-transition>` is an abstraction of an animation. It is used to implement pluggable
|
||
transitions, for example in `<core-overlay>`. You can extend this class to create a custom
|
||
animation, instantiate it, and import it where you need the animation.
|
||
|
||
All instances of `<core-transition>` are stored in a single database with `type=transition`.
|
||
For more about the database, please see the documentation for `<core-meta>`.
|
||
|
||
Each instance of `<core-transition>` objects are shared across all the clients, so you should
|
||
not store state information specific to the animated element in the transition. Rather, store
|
||
it on the element.
|
||
|
||
Example:
|
||
|
||
my-transition.html:
|
||
|
||
<polymer-element name="my-transition" extends="core-transition">
|
||
<script>
|
||
go: function(node) {
|
||
node.style.transition = 'opacity 1s ease-out';
|
||
node.style.opacity = 0;
|
||
}
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<my-transition id="my-fade-out"></my-transition>
|
||
|
||
my-transition-demo.html:
|
||
|
||
<link href="components/core-meta/core-meta.html" rel="import">
|
||
<link href="my-transition.html" rel="import">
|
||
|
||
<div id="animate-me"></div>
|
||
|
||
<script>
|
||
// Get the core-transition
|
||
var meta = document.createElement('core-meta');
|
||
meta.type = 'transition';
|
||
var transition = meta.byId('my-fade-out');
|
||
|
||
// Run the animation
|
||
var animated = document.getElementById('animate-me');
|
||
transition.go(animated);
|
||
</script>
|
||
|
||
@group Polymer Core Elements
|
||
@element core-transition
|
||
@extends core-meta
|
||
@status beta
|
||
@homepage github.io
|
||
-->
|
||
<!--
|
||
Fired when the animation finishes.
|
||
|
||
@event core-transitionend
|
||
@param {Object} detail
|
||
@param {Object} detail.node The animated node
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-transition" extends="core-meta" assetpath="polymer/bower_components/core-transition/">
|
||
|
||
<script>
|
||
Polymer('core-transition', {
|
||
|
||
type: 'transition',
|
||
|
||
/**
|
||
* Run the animation.
|
||
*
|
||
* @method go
|
||
* @param {Node} node The node to apply the animation on
|
||
* @param {Object} state State info
|
||
*/
|
||
go: function(node, state) {
|
||
this.complete(node);
|
||
},
|
||
|
||
/**
|
||
* Set up the animation. This may include injecting a stylesheet,
|
||
* applying styles, creating a web animations object, etc.. This
|
||
*
|
||
* @method setup
|
||
* @param {Node} node The animated node
|
||
*/
|
||
setup: function(node) {
|
||
},
|
||
|
||
/**
|
||
* Tear down the animation.
|
||
*
|
||
* @method teardown
|
||
* @param {Node} node The animated node
|
||
*/
|
||
teardown: function(node) {
|
||
},
|
||
|
||
/**
|
||
* Called when the animation completes. This function also fires the
|
||
* `core-transitionend` event.
|
||
*
|
||
* @method complete
|
||
* @param {Node} node The animated node
|
||
*/
|
||
complete: function(node) {
|
||
this.fire('core-transitionend', null, node);
|
||
},
|
||
|
||
/**
|
||
* Utility function to listen to an event on a node once.
|
||
*
|
||
* @method listenOnce
|
||
* @param {Node} node The animated node
|
||
* @param {string} event Name of an event
|
||
* @param {Function} fn Event handler
|
||
* @param {Array} args Additional arguments to pass to `fn`
|
||
*/
|
||
listenOnce: function(node, event, fn, args) {
|
||
var self = this;
|
||
var listener = function() {
|
||
fn.apply(self, args);
|
||
node.removeEventListener(event, listener, false);
|
||
}
|
||
node.addEventListener(event, listener, false);
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-key-helper" assetpath="polymer/bower_components/core-overlay/">
|
||
<script>
|
||
Polymer('core-key-helper', {
|
||
ENTER_KEY: 13,
|
||
ESCAPE_KEY: 27
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<polymer-element name="core-overlay-layer" assetpath="polymer/bower_components/core-overlay/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 1000;
|
||
display: none;
|
||
}
|
||
|
||
:host(.core-opened) {
|
||
display: block;
|
||
}
|
||
</style>
|
||
<content></content>
|
||
</template>
|
||
<script>
|
||
(function() {
|
||
|
||
Polymer('core-overlay-layer', {
|
||
publish: {
|
||
opened: false
|
||
},
|
||
openedChanged: function() {
|
||
this.classList.toggle('core-opened', this.opened);
|
||
},
|
||
/**
|
||
* Adds an element to the overlay layer
|
||
*/
|
||
addElement: function(element) {
|
||
if (!this.parentNode) {
|
||
document.querySelector('body').appendChild(this);
|
||
}
|
||
if (element.parentNode !== this) {
|
||
element.__contents = [];
|
||
var ip$ = element.querySelectorAll('content');
|
||
for (var i=0, l=ip$.length, n; (i<l) && (n = ip$[i]); i++) {
|
||
this.moveInsertedElements(n);
|
||
this.cacheDomLocation(n);
|
||
n.parentNode.removeChild(n);
|
||
element.__contents.push(n);
|
||
}
|
||
this.cacheDomLocation(element);
|
||
this.updateEventController(element);
|
||
var h = this.makeHost();
|
||
h.shadowRoot.appendChild(element);
|
||
element.__host = h;
|
||
}
|
||
},
|
||
makeHost: function() {
|
||
var h = document.createElement('overlay-host');
|
||
h.createShadowRoot();
|
||
this.appendChild(h);
|
||
return h;
|
||
},
|
||
moveInsertedElements: function(insertionPoint) {
|
||
var n$ = insertionPoint.getDistributedNodes();
|
||
var parent = insertionPoint.parentNode;
|
||
insertionPoint.__contents = [];
|
||
for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
|
||
this.cacheDomLocation(n);
|
||
this.updateEventController(n);
|
||
insertionPoint.__contents.push(n);
|
||
parent.appendChild(n);
|
||
}
|
||
},
|
||
updateEventController: function(element) {
|
||
element.eventController = this.element.findController(element);
|
||
},
|
||
/**
|
||
* Removes an element from the overlay layer
|
||
*/
|
||
removeElement: function(element) {
|
||
element.eventController = null;
|
||
this.replaceElement(element);
|
||
var h = element.__host;
|
||
if (h) {
|
||
h.parentNode.removeChild(h);
|
||
}
|
||
},
|
||
replaceElement: function(element) {
|
||
if (element.__contents) {
|
||
for (var i=0, c$=element.__contents, c; (c=c$[i]); i++) {
|
||
this.replaceElement(c);
|
||
}
|
||
element.__contents = null;
|
||
}
|
||
if (element.__parentNode) {
|
||
var n = element.__nextElementSibling && element.__nextElementSibling
|
||
=== element.__parentNode ? element.__nextElementSibling : null;
|
||
element.__parentNode.insertBefore(element, n);
|
||
}
|
||
},
|
||
cacheDomLocation: function(element) {
|
||
element.__nextElementSibling = element.nextElementSibling;
|
||
element.__parentNode = element.parentNode;
|
||
}
|
||
});
|
||
|
||
})();
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<!--
|
||
The `core-overlay` element displays overlayed on top of other content. It starts
|
||
out hidden and is displayed by setting its `opened` property to true.
|
||
A `core-overlay's` opened state can be toggled by calling the `toggle`
|
||
method.
|
||
|
||
The `core-overlay` will, by default, show/hide itself when it's opened. The
|
||
`target` property may be set to another element to cause that element to
|
||
be shown when the overlay is opened.
|
||
|
||
It's common to want a `core-overlay` to animate to its opened
|
||
position. The `core-overlay` element uses a `core-transition` to handle
|
||
animation. The default transition is `core-transition-fade` which
|
||
causes the overlay to fade in when displayed. See
|
||
<a href="../core-transition/">`core-transition`</a> for more
|
||
information about customizing a `core-overlay's` opening animation. The
|
||
`backdrop` property can be set to true to show a backdrop behind the overlay
|
||
that will darken the rest of the window.
|
||
|
||
An element that should close the `core-overlay` will automatically
|
||
do so if it's given the `core-overlay-toggle` attribute. This attribute
|
||
can be customized with the `closeAttribute` property. You can also use
|
||
`closeSelector` if more general matching is needed.
|
||
|
||
By default `core-overlay` will close whenever the user taps outside it or
|
||
presses the escape key. This behavior can be turned off via the
|
||
`autoCloseDisabled` property.
|
||
|
||
<core-overlay>
|
||
<h2>Dialog</h2>
|
||
<input placeholder="say something..." autofocus>
|
||
<div>I agree with this wholeheartedly.</div>
|
||
<button core-overlay-toggle>OK</button>
|
||
</core-overlay>
|
||
|
||
`core-overlay` will automatically size and position itself according to the
|
||
following rules. The overlay's size is constrained such that it does not
|
||
overflow the screen. This is done by setting maxHeight/maxWidth on the
|
||
`sizingTarget`. If the `sizingTarget` already has a setting for one of these
|
||
properties, it will not be overridden. The overlay should
|
||
be positioned via css or imperatively using the `core-overlay-position` event.
|
||
If the overlay is not positioned vertically via setting `top` or `bottom`, it
|
||
will be centered vertically. The same is true horizontally via a setting to
|
||
`left` or `right`. In addition, css `margin` can be used to provide some space
|
||
around the overlay. This can be used to ensure
|
||
that, for example, a drop shadow is always visible around the overlay.
|
||
|
||
@group Core Elements
|
||
@element core-overlay
|
||
@homepage github.io
|
||
-->
|
||
<!--
|
||
Fired when the `core-overlay`'s `opened` property changes.
|
||
|
||
@event core-overlay-open
|
||
@param {Object} detail
|
||
@param {Object} detail.opened the opened state
|
||
-->
|
||
<!--
|
||
Fired when the `core-overlay` has completely opened.
|
||
|
||
@event core-overlay-open-completed
|
||
-->
|
||
<!--
|
||
Fired when the `core-overlay` has completely closed.
|
||
|
||
@event core-overlay-close-completed
|
||
-->
|
||
<!--
|
||
Fired when the `core-overlay` needs to position itself. Optionally, implement
|
||
in order to position an overlay via code. If the overlay was not otherwise
|
||
positioned, it's important to indicate how the overlay has been positioned by
|
||
setting the `dimensions.position` object. For example, if the overlay has been
|
||
positioned via setting `right` and `top`, set dimensions.position to an
|
||
object like this: `{v: 'top', h: 'right'}`.
|
||
|
||
@event core-overlay-position
|
||
@param {Object} detail
|
||
@param {Object} detail.target the overlay target
|
||
@param {Object} detail.sizingTarget the overlay sizing target
|
||
@param {Object} detail.opened the opened state
|
||
-->
|
||
<style>
|
||
.core-overlay-backdrop {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
background-color: black;
|
||
opacity: 0;
|
||
transition: opacity 0.2s;
|
||
}
|
||
|
||
.core-overlay-backdrop.core-opened {
|
||
opacity: 0.6;
|
||
}
|
||
</style>
|
||
|
||
<polymer-element name="core-overlay" assetpath="polymer/bower_components/core-overlay/">
|
||
<script>
|
||
(function() {
|
||
|
||
Polymer('core-overlay', {
|
||
|
||
publish: {
|
||
/**
|
||
* The target element that will be shown when the overlay is
|
||
* opened. If unspecified, the core-overlay itself is the target.
|
||
*
|
||
* @attribute target
|
||
* @type Object
|
||
* @default the overlay element
|
||
*/
|
||
target: null,
|
||
|
||
|
||
/**
|
||
* A `core-overlay`'s size is guaranteed to be
|
||
* constrained to the window size. To achieve this, the sizingElement
|
||
* is sized with a max-height/width. By default this element is the
|
||
* target element, but it can be specifically set to a specific element
|
||
* inside the target if that is more appropriate. This is useful, for
|
||
* example, when a region inside the overlay should scroll if needed.
|
||
*
|
||
* @attribute sizingTarget
|
||
* @type Object
|
||
* @default the target element
|
||
*/
|
||
sizingTarget: null,
|
||
|
||
/**
|
||
* Set opened to true to show an overlay and to false to hide it.
|
||
* A `core-overlay` may be made initially opened by setting its
|
||
* `opened` attribute.
|
||
* @attribute opened
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
opened: false,
|
||
|
||
/**
|
||
* If true, the overlay has a backdrop darkening the rest of the screen.
|
||
* The backdrop element is attached to the document body and may be styled
|
||
* with the class `core-overlay-backdrop`. When opened the `core-opened`
|
||
* class is applied.
|
||
*
|
||
* @attribute backdrop
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
backdrop: false,
|
||
|
||
/**
|
||
* If true, the overlay is guaranteed to display above page content.
|
||
*
|
||
* @attribute layered
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
layered: false,
|
||
|
||
/**
|
||
* By default an overlay will close automatically if the user
|
||
* taps outside it or presses the escape key. Disable this
|
||
* behavior by setting the `autoCloseDisabled` property to true.
|
||
* @attribute autoCloseDisabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
autoCloseDisabled: false,
|
||
|
||
/**
|
||
* By default an overlay will focus its target or an element inside
|
||
* it with the `autoFocus` attribute. Disable this
|
||
* behavior by setting the `autoFocusDisabled` property to true.
|
||
* @attribute autoFocusDisabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
autoFocusDisabled: false,
|
||
|
||
/**
|
||
* This property specifies an attribute on elements that should
|
||
* close the overlay on tap. Should not set `closeSelector` if this
|
||
* is set.
|
||
*
|
||
* @attribute closeAttribute
|
||
* @type string
|
||
* @default "core-overlay-toggle"
|
||
*/
|
||
closeAttribute: 'core-overlay-toggle',
|
||
|
||
/**
|
||
* This property specifies a selector matching elements that should
|
||
* close the overlay on tap. Should not set `closeAttribute` if this
|
||
* is set.
|
||
*
|
||
* @attribute closeSelector
|
||
* @type string
|
||
* @default ""
|
||
*/
|
||
closeSelector: '',
|
||
|
||
/**
|
||
* The transition property specifies a string which identifies a
|
||
* <a href="../core-transition/">`core-transition`</a> element that
|
||
* will be used to help the overlay open and close. The default
|
||
* `core-transition-fade` will cause the overlay to fade in and out.
|
||
*
|
||
* @attribute transition
|
||
* @type string
|
||
* @default 'core-transition-fade'
|
||
*/
|
||
transition: 'core-transition-fade'
|
||
|
||
},
|
||
|
||
captureEventName: 'tap',
|
||
targetListeners: {
|
||
'tap': 'tapHandler',
|
||
'keydown': 'keydownHandler',
|
||
'core-transitionend': 'transitionend'
|
||
},
|
||
|
||
registerCallback: function(element) {
|
||
this.layer = document.createElement('core-overlay-layer');
|
||
this.keyHelper = document.createElement('core-key-helper');
|
||
this.meta = document.createElement('core-transition');
|
||
this.scrim = document.createElement('div');
|
||
this.scrim.className = 'core-overlay-backdrop';
|
||
},
|
||
|
||
ready: function() {
|
||
this.target = this.target || this;
|
||
// flush to ensure styles are installed before paint
|
||
Platform.flush();
|
||
},
|
||
|
||
/**
|
||
* Toggle the opened state of the overlay.
|
||
* @method toggle
|
||
*/
|
||
toggle: function() {
|
||
this.opened = !this.opened;
|
||
},
|
||
|
||
/**
|
||
* Open the overlay. This is equivalent to setting the `opened`
|
||
* property to true.
|
||
* @method open
|
||
*/
|
||
open: function() {
|
||
this.opened = true;
|
||
},
|
||
|
||
/**
|
||
* Close the overlay. This is equivalent to setting the `opened`
|
||
* property to false.
|
||
* @method close
|
||
*/
|
||
close: function() {
|
||
this.opened = false;
|
||
},
|
||
|
||
domReady: function() {
|
||
this.ensureTargetSetup();
|
||
},
|
||
|
||
targetChanged: function(old) {
|
||
if (this.target) {
|
||
// really make sure tabIndex is set
|
||
if (this.target.tabIndex < 0) {
|
||
this.target.tabIndex = -1;
|
||
}
|
||
this.addElementListenerList(this.target, this.targetListeners);
|
||
this.target.style.display = 'none';
|
||
this.target.__overlaySetup = false;
|
||
}
|
||
if (old) {
|
||
this.removeElementListenerList(old, this.targetListeners);
|
||
var transition = this.getTransition();
|
||
if (transition) {
|
||
transition.teardown(old);
|
||
} else {
|
||
old.style.position = '';
|
||
old.style.outline = '';
|
||
}
|
||
old.style.display = '';
|
||
}
|
||
},
|
||
|
||
transitionChanged: function(old) {
|
||
if (!this.target) {
|
||
return;
|
||
}
|
||
if (old) {
|
||
this.getTransition(old).teardown(this.target);
|
||
}
|
||
this.target.__overlaySetup = false;
|
||
},
|
||
|
||
// NOTE: wait to call this until we're as sure as possible that target
|
||
// is styled.
|
||
ensureTargetSetup: function() {
|
||
if (!this.target || this.target.__overlaySetup) {
|
||
return;
|
||
}
|
||
if (!this.sizingTarget) {
|
||
this.sizingTarget = this.target;
|
||
}
|
||
this.target.__overlaySetup = true;
|
||
this.target.style.display = '';
|
||
var transition = this.getTransition();
|
||
if (transition) {
|
||
transition.setup(this.target);
|
||
}
|
||
var style = this.target.style;
|
||
var computed = getComputedStyle(this.target);
|
||
if (computed.position === 'static') {
|
||
style.position = 'fixed';
|
||
}
|
||
style.outline = 'none';
|
||
style.display = 'none';
|
||
},
|
||
|
||
openedChanged: function() {
|
||
this.transitioning = true;
|
||
this.ensureTargetSetup();
|
||
this.prepareRenderOpened();
|
||
// async here to allow overlay layer to become visible.
|
||
this.async(function() {
|
||
this.target.style.display = '';
|
||
// force layout to ensure transitions will go
|
||
this.target.offsetWidth;
|
||
this.renderOpened();
|
||
});
|
||
this.fire('core-overlay-open', this.opened);
|
||
},
|
||
|
||
// tasks which must occur before opening; e.g. making the element visible
|
||
prepareRenderOpened: function() {
|
||
if (this.opened) {
|
||
addOverlay(this);
|
||
}
|
||
this.prepareBackdrop();
|
||
// async so we don't auto-close immediately via a click.
|
||
this.async(function() {
|
||
if (!this.autoCloseDisabled) {
|
||
this.enableElementListener(this.opened, document,
|
||
this.captureEventName, 'captureHandler', true);
|
||
}
|
||
});
|
||
this.enableElementListener(this.opened, window, 'resize',
|
||
'resizeHandler');
|
||
|
||
if (this.opened) {
|
||
// force layout so SD Polyfill renders
|
||
this.target.offsetHeight;
|
||
this.discoverDimensions();
|
||
// if we are showing, then take care when positioning
|
||
this.preparePositioning();
|
||
this.positionTarget();
|
||
this.updateTargetDimensions();
|
||
this.finishPositioning();
|
||
if (this.layered) {
|
||
this.layer.addElement(this.target);
|
||
this.layer.opened = this.opened;
|
||
}
|
||
}
|
||
},
|
||
|
||
// tasks which cause the overlay to actually open; typically play an
|
||
// animation
|
||
renderOpened: function() {
|
||
var transition = this.getTransition();
|
||
if (transition) {
|
||
transition.go(this.target, {opened: this.opened});
|
||
} else {
|
||
this.transitionend();
|
||
}
|
||
this.renderBackdropOpened();
|
||
},
|
||
|
||
// finishing tasks; typically called via a transition
|
||
transitionend: function(e) {
|
||
// make sure this is our transition event.
|
||
if (e && e.target !== this.target) {
|
||
return;
|
||
}
|
||
this.transitioning = false;
|
||
if (!this.opened) {
|
||
this.resetTargetDimensions();
|
||
this.target.style.display = 'none';
|
||
this.completeBackdrop();
|
||
removeOverlay(this);
|
||
if (this.layered) {
|
||
if (!currentOverlay()) {
|
||
this.layer.opened = this.opened;
|
||
}
|
||
this.layer.removeElement(this.target);
|
||
}
|
||
}
|
||
this.fire('core-overlay-' + (this.opened ? 'open' : 'close') +
|
||
'-completed');
|
||
this.applyFocus();
|
||
},
|
||
|
||
prepareBackdrop: function() {
|
||
if (this.backdrop && this.opened) {
|
||
if (!this.scrim.parentNode) {
|
||
document.body.appendChild(this.scrim);
|
||
this.scrim.style.zIndex = currentOverlayZ() - 1;
|
||
}
|
||
trackBackdrop(this);
|
||
}
|
||
},
|
||
|
||
renderBackdropOpened: function() {
|
||
if (this.backdrop && getBackdrops().length < 2) {
|
||
this.scrim.classList.toggle('core-opened', this.opened);
|
||
}
|
||
},
|
||
|
||
completeBackdrop: function() {
|
||
if (this.backdrop) {
|
||
trackBackdrop(this);
|
||
if (getBackdrops().length === 0) {
|
||
this.scrim.parentNode.removeChild(this.scrim);
|
||
}
|
||
}
|
||
},
|
||
|
||
preparePositioning: function() {
|
||
this.target.style.transition = this.target.style.webkitTransition = 'none';
|
||
this.target.style.transform = this.target.style.webkitTransform = 'none';
|
||
this.target.style.display = '';
|
||
},
|
||
|
||
discoverDimensions: function() {
|
||
if (this.dimensions) {
|
||
return;
|
||
}
|
||
var target = getComputedStyle(this.target);
|
||
var sizer = getComputedStyle(this.sizingTarget);
|
||
this.dimensions = {
|
||
position: {
|
||
v: target.top !== 'auto' ? 'top' : (target.bottom !== 'auto' ?
|
||
'bottom' : null),
|
||
h: target.left !== 'auto' ? 'left' : (target.right !== 'auto' ?
|
||
'right' : null),
|
||
css: target.position
|
||
},
|
||
size: {
|
||
v: sizer.maxHeight !== 'none',
|
||
h: sizer.maxWidth !== 'none'
|
||
},
|
||
margin: {
|
||
top: parseInt(target.marginTop) || 0,
|
||
right: parseInt(target.marginRight) || 0,
|
||
bottom: parseInt(target.marginBottom) || 0,
|
||
left: parseInt(target.marginLeft) || 0
|
||
}
|
||
};
|
||
},
|
||
|
||
finishPositioning: function(target) {
|
||
this.target.style.display = 'none';
|
||
this.target.style.transform = this.target.style.webkitTransform = '';
|
||
// force layout to avoid application of transform
|
||
this.target.offsetWidth;
|
||
this.target.style.transition = this.target.style.webkitTransition = '';
|
||
},
|
||
|
||
getTransition: function(name) {
|
||
return this.meta.byId(name || this.transition);
|
||
},
|
||
|
||
getFocusNode: function() {
|
||
return this.target.querySelector('[autofocus]') || this.target;
|
||
},
|
||
|
||
applyFocus: function() {
|
||
var focusNode = this.getFocusNode();
|
||
if (this.opened) {
|
||
if (!this.autoFocusDisabled) {
|
||
focusNode.focus();
|
||
}
|
||
} else {
|
||
focusNode.blur();
|
||
if (currentOverlay() == this) {
|
||
console.warn('Current core-overlay is attempting to focus itself as next! (bug)');
|
||
} else {
|
||
focusOverlay();
|
||
}
|
||
}
|
||
},
|
||
|
||
positionTarget: function() {
|
||
// fire positioning event
|
||
this.fire('core-overlay-position', {target: this.target,
|
||
sizingTarget: this.sizingTarget, opened: this.opened});
|
||
if (!this.dimensions.position.v) {
|
||
this.target.style.top = '0px';
|
||
}
|
||
if (!this.dimensions.position.h) {
|
||
this.target.style.left = '0px';
|
||
}
|
||
},
|
||
|
||
updateTargetDimensions: function() {
|
||
this.sizeTarget();
|
||
this.repositionTarget();
|
||
},
|
||
|
||
sizeTarget: function() {
|
||
this.sizingTarget.style.boxSizing = 'border-box';
|
||
var dims = this.dimensions;
|
||
var rect = this.target.getBoundingClientRect();
|
||
if (!dims.size.v) {
|
||
this.sizeDimension(rect, dims.position.v, 'top', 'bottom', 'Height');
|
||
}
|
||
if (!dims.size.h) {
|
||
this.sizeDimension(rect, dims.position.h, 'left', 'right', 'Width');
|
||
}
|
||
},
|
||
|
||
sizeDimension: function(rect, positionedBy, start, end, extent) {
|
||
var dims = this.dimensions;
|
||
var flip = (positionedBy === end);
|
||
var m = flip ? start : end;
|
||
var ws = window['inner' + extent];
|
||
var o = dims.margin[m] + (flip ? ws - rect[end] :
|
||
rect[start]);
|
||
var offset = 'offset' + extent;
|
||
var o2 = this.target[offset] - this.sizingTarget[offset];
|
||
this.sizingTarget.style['max' + extent] = (ws - o - o2) + 'px';
|
||
},
|
||
|
||
// vertically and horizontally center if not positioned
|
||
repositionTarget: function() {
|
||
// only center if position fixed.
|
||
if (this.dimensions.position.css !== 'fixed') {
|
||
return;
|
||
}
|
||
if (!this.dimensions.position.v) {
|
||
var t = (window.innerHeight - this.target.offsetHeight) / 2;
|
||
t -= this.dimensions.margin.top;
|
||
this.target.style.top = t + 'px';
|
||
}
|
||
|
||
if (!this.dimensions.position.h) {
|
||
var l = (window.innerWidth - this.target.offsetWidth) / 2;
|
||
l -= this.dimensions.margin.left;
|
||
this.target.style.left = l + 'px';
|
||
}
|
||
},
|
||
|
||
resetTargetDimensions: function() {
|
||
if (!this.dimensions.size.v) {
|
||
this.sizingTarget.style.maxHeight = '';
|
||
}
|
||
if (!this.dimensions.size.h) {
|
||
this.sizingTarget.style.maxWidth = '';
|
||
}
|
||
this.dimensions = null;
|
||
},
|
||
|
||
tapHandler: function(e) {
|
||
// closeSelector takes precedence since closeAttribute has a default non-null value.
|
||
if (e.target &&
|
||
(this.closeSelector && e.target.matches(this.closeSelector)) ||
|
||
(this.closeAttribute && e.target.hasAttribute(this.closeAttribute))) {
|
||
this.toggle();
|
||
} else {
|
||
if (this.autoCloseJob) {
|
||
this.autoCloseJob.stop();
|
||
this.autoCloseJob = null;
|
||
}
|
||
}
|
||
},
|
||
|
||
// We use the traditional approach of capturing events on document
|
||
// to to determine if the overlay needs to close. However, due to
|
||
// ShadowDOM event retargeting, the event target is not useful. Instead
|
||
// of using it, we attempt to close asynchronously and prevent the close
|
||
// if a tap event is immediately heard on the target.
|
||
// TODO(sorvell): This approach will not work with modal. For
|
||
// this we need a scrim.
|
||
captureHandler: function(e) {
|
||
if (!this.autoCloseDisabled && (currentOverlay() == this)) {
|
||
this.autoCloseJob = this.job(this.autoCloseJob, function() {
|
||
this.close();
|
||
});
|
||
}
|
||
},
|
||
|
||
keydownHandler: function(e) {
|
||
if (!this.autoCloseDisabled && (e.keyCode == this.keyHelper.ESCAPE_KEY)) {
|
||
this.close();
|
||
e.stopPropagation();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Extensions of core-overlay should implement the `resizeHandler`
|
||
* method to adjust the size and position of the overlay when the
|
||
* browser window resizes.
|
||
* @method resizeHandler
|
||
*/
|
||
resizeHandler: function() {
|
||
this.updateTargetDimensions();
|
||
},
|
||
|
||
// TODO(sorvell): these utility methods should not be here.
|
||
addElementListenerList: function(node, events) {
|
||
for (var i in events) {
|
||
this.addElementListener(node, i, events[i]);
|
||
}
|
||
},
|
||
|
||
removeElementListenerList: function(node, events) {
|
||
for (var i in events) {
|
||
this.removeElementListener(node, i, events[i]);
|
||
}
|
||
},
|
||
|
||
enableElementListener: function(enable, node, event, methodName, capture) {
|
||
if (enable) {
|
||
this.addElementListener(node, event, methodName, capture);
|
||
} else {
|
||
this.removeElementListener(node, event, methodName, capture);
|
||
}
|
||
},
|
||
|
||
addElementListener: function(node, event, methodName, capture) {
|
||
var fn = this._makeBoundListener(methodName);
|
||
if (node && fn) {
|
||
Polymer.addEventListener(node, event, fn, capture);
|
||
}
|
||
},
|
||
|
||
removeElementListener: function(node, event, methodName, capture) {
|
||
var fn = this._makeBoundListener(methodName);
|
||
if (node && fn) {
|
||
Polymer.removeEventListener(node, event, fn, capture);
|
||
}
|
||
},
|
||
|
||
_makeBoundListener: function(methodName) {
|
||
var self = this, method = this[methodName];
|
||
if (!method) {
|
||
return;
|
||
}
|
||
var bound = '_bound' + methodName;
|
||
if (!this[bound]) {
|
||
this[bound] = function(e) {
|
||
method.call(self, e);
|
||
};
|
||
}
|
||
return this[bound];
|
||
},
|
||
});
|
||
|
||
// TODO(sorvell): This should be an element with private state so it can
|
||
// be independent of overlay.
|
||
// track overlays for z-index and focus managemant
|
||
var overlays = [];
|
||
function addOverlay(overlay) {
|
||
var z0 = currentOverlayZ();
|
||
overlays.push(overlay);
|
||
var z1 = currentOverlayZ();
|
||
if (z1 <= z0) {
|
||
applyOverlayZ(overlay, z0);
|
||
}
|
||
}
|
||
|
||
function removeOverlay(overlay) {
|
||
var i = overlays.indexOf(overlay);
|
||
if (i >= 0) {
|
||
overlays.splice(i, 1);
|
||
setZ(overlay, '');
|
||
}
|
||
}
|
||
|
||
function applyOverlayZ(overlay, aboveZ) {
|
||
setZ(overlay.target, aboveZ + 2);
|
||
}
|
||
|
||
function setZ(element, z) {
|
||
element.style.zIndex = z;
|
||
}
|
||
|
||
function currentOverlay() {
|
||
return overlays[overlays.length-1];
|
||
}
|
||
|
||
var DEFAULT_Z = 10;
|
||
|
||
function currentOverlayZ() {
|
||
var z;
|
||
var current = currentOverlay();
|
||
if (current) {
|
||
var z1 = window.getComputedStyle(current.target).zIndex;
|
||
if (!isNaN(z1)) {
|
||
z = Number(z1);
|
||
}
|
||
}
|
||
return z || DEFAULT_Z;
|
||
}
|
||
|
||
function focusOverlay() {
|
||
var current = currentOverlay();
|
||
// We have to be careful to focus the next overlay _after_ any current
|
||
// transitions are complete (due to the state being toggled prior to the
|
||
// transition). Otherwise, we risk infinite recursion when a transitioning
|
||
// (closed) overlay becomes the current overlay.
|
||
//
|
||
// NOTE: We make the assumption that any overlay that completes a transition
|
||
// will call into focusOverlay to kick the process back off. Currently:
|
||
// transitionend -> applyFocus -> focusOverlay.
|
||
if (current && !current.transitioning) {
|
||
current.applyFocus();
|
||
}
|
||
}
|
||
|
||
var backdrops = [];
|
||
function trackBackdrop(element) {
|
||
if (element.opened) {
|
||
backdrops.push(element);
|
||
} else {
|
||
var i = backdrops.indexOf(element);
|
||
if (i >= 0) {
|
||
backdrops.splice(i, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
function getBackdrops() {
|
||
return backdrops;
|
||
}
|
||
})();
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<!--
|
||
|
||
`core-dropdown-overlay` is a helper class to position an overlay relative to another
|
||
element within the same offsetParent.
|
||
|
||
@group Polymer Core Elements
|
||
@element core-dropdown-overlay
|
||
@extends core-overlay
|
||
@homepage github.io
|
||
-->
|
||
|
||
<polymer-element name="core-dropdown-overlay" extends="core-overlay" assetpath="polymer/bower_components/core-dropdown/">
|
||
<script>
|
||
Polymer('core-dropdown-overlay',{
|
||
|
||
publish: {
|
||
|
||
/**
|
||
* The `relatedTarget` is an element used to position the overlay. It should have
|
||
* the same offsetParent as the target.
|
||
*
|
||
* @attribute relatedTarget
|
||
* @type Node
|
||
*/
|
||
relatedTarget: null,
|
||
|
||
/**
|
||
* The horizontal alignment of the overlay relative to the `relatedTarget`.
|
||
* `left` means the left edges are aligned together and `right` means the right
|
||
* edges are aligned together.
|
||
*
|
||
* @attribute halign
|
||
* @type 'left' | 'right'
|
||
* @default 'auto'
|
||
*/
|
||
halign: 'left',
|
||
|
||
/**
|
||
* The vertical alignment of the overlay relative to the `relatedTarget`. `top`
|
||
* means the top edges are aligned together and `bottom` means the bottom edges
|
||
* are aligned together.
|
||
*
|
||
* @attribute valign
|
||
* @type 'top' | 'bottom'
|
||
* @default 'top'
|
||
*/
|
||
valign: 'top'
|
||
|
||
},
|
||
|
||
measure: function() {
|
||
var target = this.target;
|
||
// remember position, because core-overlay may have set the property
|
||
var pos = target.style.position;
|
||
|
||
// get the size of the target as if it's positioned in the top left
|
||
// corner of the screen
|
||
target.style.position = 'fixed';
|
||
target.style.left = '0px';
|
||
target.style.top = '0px';
|
||
|
||
var rect = target.getBoundingClientRect();
|
||
|
||
target.style.position = pos;
|
||
target.style.left = null;
|
||
target.style.top = null;
|
||
|
||
return rect;
|
||
},
|
||
|
||
resetTargetDimensions: function() {
|
||
var dims = this.dimensions;
|
||
var style = this.target.style;
|
||
if (dims.position.h_by === this.localName) {
|
||
style[dims.position.h] = null;
|
||
}
|
||
if (dims.position.v_by === this.localName) {
|
||
style[dims.position.v] = null;
|
||
}
|
||
this.super();
|
||
},
|
||
|
||
positionTarget: function() {
|
||
if (!this.relatedTarget) {
|
||
this.super();
|
||
return;
|
||
}
|
||
|
||
var target = this.target;
|
||
var related = this.relatedTarget;
|
||
|
||
// explicitly set width/height, because we don't want it constrained
|
||
// to the offsetParent
|
||
var rect = this.measure();
|
||
target.style.width = rect.width + 'px';
|
||
target.style.height = rect.height + 'px';
|
||
|
||
var t_op = target.offsetParent;
|
||
var r_op = related.offsetParent;
|
||
if (window.ShadowDOMPolyfill) {
|
||
t_op = wrap(t_op);
|
||
r_op = wrap(r_op);
|
||
}
|
||
|
||
if (t_op !== r_op && t_op !== related) {
|
||
console.warn('core-dropdown-overlay: dropdown\'s offsetParent must be the relatedTarget or the relatedTarget\'s offsetParent!');
|
||
}
|
||
|
||
// Don't use CSS to handle halign/valign so we can use
|
||
// dimensions.position to detect custom positioning
|
||
|
||
var dims = this.dimensions;
|
||
var margin = dims.margin;
|
||
var inside = t_op === related;
|
||
|
||
if (!dims.position.h) {
|
||
if (this.halign === 'right') {
|
||
target.style.right = ((inside ? 0 : t_op.offsetWidth - related.offsetLeft - related.offsetWidth) - margin.right) + 'px';
|
||
dims.position.h = 'right';
|
||
} else {
|
||
target.style.left = ((inside ? 0 : related.offsetLeft) - margin.left) + 'px';
|
||
dims.position.h = 'left';
|
||
}
|
||
dims.position.h_by = this.localName;
|
||
}
|
||
|
||
if (!dims.position.v) {
|
||
if (this.valign === 'bottom') {
|
||
target.style.bottom = ((inside ? 0 : t_op.offsetHeight - related.offsetTop - related.offsetHeight) - margin.bottom) + 'px';
|
||
dims.position.v = 'bottom';
|
||
} else {
|
||
target.style.top = ((inside ? 0 : related.offsetTop) - margin.top) + 'px';
|
||
dims.position.v = 'top';
|
||
}
|
||
dims.position.v_by = this.localName;
|
||
}
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="core-dropdown" assetpath="polymer/bower_components/core-dropdown/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
position: absolute;
|
||
overflow: auto;
|
||
background-color: #fff;
|
||
}</style>
|
||
|
||
<core-dropdown-overlay id="overlay" target="{{}}" relatedtarget="{{relatedTarget}}" opened="{{opened}}" halign="{{halign}}" valign="{{valign}}" margin="{{margin}}" transition="{{transition}}" autofocusdisabled="{{autoFocusDisabled}}"></core-dropdown-overlay>
|
||
|
||
<content></content>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('core-dropdown',{
|
||
|
||
publish: {
|
||
|
||
/**
|
||
* The element associated with this dropdown, usually the element that triggers
|
||
* the menu.
|
||
*
|
||
* @attribute relatedTarget
|
||
* @type Node
|
||
*/
|
||
relatedTarget: null,
|
||
|
||
/**
|
||
* If true, the menu is currently visible.
|
||
*
|
||
* @attribute opened
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
opened: false,
|
||
|
||
/**
|
||
* The horizontal alignment of the popup relative to `relatedTarget`. `left`
|
||
* means the left edges are aligned together. `right` means the right edges
|
||
* are aligned together.
|
||
*
|
||
* @attribute halign
|
||
* @type 'left' | 'right'
|
||
* @default 'left'
|
||
*/
|
||
halign: 'left',
|
||
|
||
/**
|
||
* The vertical alignment of the popup relative to `relatedTarget`. `top` means
|
||
* the top edges are aligned together. `bottom` means the bottom edges are
|
||
* aligned together.
|
||
*
|
||
* @attribute valign
|
||
* @type 'top' | 'bottom'
|
||
* @default 'top'
|
||
*/
|
||
valign: 'top',
|
||
|
||
/**
|
||
* By default an overlay will focus its target or an element inside
|
||
* it with the `autoFocus` attribute. Disable this
|
||
* behavior by setting the `autoFocusDisabled` property to true.
|
||
*
|
||
* @attribute autoFocusDisabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
autoFocusDisabled: false,
|
||
|
||
/**
|
||
* The transition property specifies a string which identifies a
|
||
* <a href="../core-transition/">`core-transition`</a> element that
|
||
* will be used to help the overlay open and close. The default
|
||
* `core-transition-fade` will cause the overlay to fade in and out.
|
||
*
|
||
* @attribute transition
|
||
* @type string
|
||
* @default null
|
||
*/
|
||
transition: null
|
||
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`core-menu` is a selector which styles to looks like a menu.
|
||
|
||
<core-menu selected="0">
|
||
<core-item icon="settings" label="Settings"></core-item>
|
||
<core-item icon="dialog" label="Dialog"></core-item>
|
||
<core-item icon="search" label="Search"></core-item>
|
||
</core-menu>
|
||
|
||
When an item is selected the `core-selected` class is added to it. The user can
|
||
use the class to add more stylings to the selected item.
|
||
|
||
core-item.core-selected {
|
||
color: red;
|
||
}
|
||
|
||
The `selectedItem` property references the selected item.
|
||
|
||
<core-menu selected="0" selectedItem="{{item}}">
|
||
<core-item icon="settings" label="Settings"></core-item>
|
||
<core-item icon="dialog" label="Dialog"></core-item>
|
||
<core-item icon="search" label="Search"></core-item>
|
||
</core-menu>
|
||
|
||
<div>selected label: {{item.label}}</div>
|
||
|
||
The `core-select` event signals selection change.
|
||
|
||
<core-menu selected="0" on-core-select="{{selectAction}}">
|
||
<core-item icon="settings" label="Settings"></core-item>
|
||
<core-item icon="dialog" label="Dialog"></core-item>
|
||
<core-item icon="search" label="Search"></core-item>
|
||
</core-menu>
|
||
|
||
...
|
||
|
||
selectAction: function(e, detail) {
|
||
if (detail.isSelected) {
|
||
var selectedItem = detail.item;
|
||
...
|
||
}
|
||
}
|
||
|
||
@group Polymer Core Elements
|
||
@element core-menu
|
||
@extends core-selector
|
||
-->
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
@group Polymer Core Elements
|
||
|
||
`<core-selector>` is used to manage a list of elements that can be selected.
|
||
|
||
The attribute `selected` indicates which item element is being selected.
|
||
The attribute `multi` indicates if multiple items can be selected at once.
|
||
Tapping on the item element would fire `core-activate` event. Use
|
||
`core-select` event to listen for selection changes.
|
||
|
||
Example:
|
||
|
||
<core-selector selected="0">
|
||
<div>Item 1</div>
|
||
<div>Item 2</div>
|
||
<div>Item 3</div>
|
||
</core-selector>
|
||
|
||
`<core-selector>` is not styled. Use the `core-selected` CSS class to style the selected element.
|
||
|
||
<style>
|
||
.item.core-selected {
|
||
background: #eee;
|
||
}
|
||
</style>
|
||
...
|
||
<core-selector>
|
||
<div class="item">Item 1</div>
|
||
<div class="item">Item 2</div>
|
||
<div class="item">Item 3</div>
|
||
</core-selector>
|
||
|
||
@element core-selector
|
||
@status stable
|
||
@homepage github.io
|
||
-->
|
||
|
||
<!--
|
||
Fired when an item's selection state is changed. This event is fired both
|
||
when an item is selected or deselected. The `isSelected` detail property
|
||
contains the selection state.
|
||
|
||
@event core-select
|
||
@param {Object} detail
|
||
@param {boolean} detail.isSelected true for selection and false for deselection
|
||
@param {Object} detail.item the item element
|
||
-->
|
||
<!--
|
||
Fired when an item element is tapped.
|
||
|
||
@event core-activate
|
||
@param {Object} detail
|
||
@param {Object} detail.item the item element
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<!--
|
||
@group Polymer Core Elements
|
||
|
||
The `<core-selection>` element is used to manage selection state. It has no
|
||
visual appearance and is typically used in conjunction with another element.
|
||
For example, [core-selector](#core-selector)
|
||
use a `<core-selection>` to manage selection.
|
||
|
||
To mark an item as selected, call the `select(item)` method on
|
||
`<core-selection>`. The item itself is an argument to this method.
|
||
|
||
The `<core-selection>`element manages selection state for any given set of
|
||
items. When an item is selected, the `core-select` event is fired.
|
||
|
||
The attribute `multi` indicates if multiple items can be selected at once.
|
||
|
||
Example:
|
||
|
||
<polymer-element name="selection-example">
|
||
<template>
|
||
<style>
|
||
polyfill-next-selector { content: ':host > .selected'; }
|
||
::content > .selected {
|
||
font-weight: bold;
|
||
font-style: italic;
|
||
}
|
||
</style>
|
||
<ul on-tap="{{itemTapAction}}">
|
||
<content></content>
|
||
</ul>
|
||
<core-selection id="selection" multi
|
||
on-core-select="{{selectAction}}"></core-selection>
|
||
</template>
|
||
<script>
|
||
Polymer('selection-example', {
|
||
itemTapAction: function(e, detail, sender) {
|
||
this.$.selection.select(e.target);
|
||
},
|
||
selectAction: function(e, detail, sender) {
|
||
detail.item.classList.toggle('selected', detail.isSelected);
|
||
}
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<selection-example>
|
||
<li>Red</li>
|
||
<li>Green</li>
|
||
<li>Blue</li>
|
||
</selection-example>
|
||
|
||
@element core-selection
|
||
-->
|
||
|
||
<!--
|
||
Fired when an item's selection state is changed. This event is fired both
|
||
when an item is selected or deselected. The `isSelected` detail property
|
||
contains the selection state.
|
||
|
||
@event core-select
|
||
@param {Object} detail
|
||
@param {boolean} detail.isSelected true for selection and false for de-selection
|
||
@param {Object} detail.item the item element
|
||
-->
|
||
|
||
|
||
<polymer-element name="core-selection" attributes="multi" hidden assetpath="polymer/bower_components/core-selection/">
|
||
<script>
|
||
Polymer('core-selection', {
|
||
/**
|
||
* If true, multiple selections are allowed.
|
||
*
|
||
* @attribute multi
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
multi: false,
|
||
ready: function() {
|
||
this.clear();
|
||
},
|
||
clear: function() {
|
||
this.selection = [];
|
||
},
|
||
/**
|
||
* Retrieves the selected item(s).
|
||
* @method getSelection
|
||
* @returns Returns the selected item(s). If the multi property is true,
|
||
* getSelection will return an array, otherwise it will return
|
||
* the selected item or undefined if there is no selection.
|
||
*/
|
||
getSelection: function() {
|
||
return this.multi ? this.selection : this.selection[0];
|
||
},
|
||
/**
|
||
* Indicates if a given item is selected.
|
||
* @method isSelected
|
||
* @param {any} item The item whose selection state should be checked.
|
||
* @returns Returns true if `item` is selected.
|
||
*/
|
||
isSelected: function(item) {
|
||
return this.selection.indexOf(item) >= 0;
|
||
},
|
||
setItemSelected: function(item, isSelected) {
|
||
if (item !== undefined && item !== null) {
|
||
if (isSelected) {
|
||
this.selection.push(item);
|
||
} else {
|
||
var i = this.selection.indexOf(item);
|
||
if (i >= 0) {
|
||
this.selection.splice(i, 1);
|
||
}
|
||
}
|
||
this.fire("core-select", {isSelected: isSelected, item: item});
|
||
}
|
||
},
|
||
/**
|
||
* Set the selection state for a given `item`. If the multi property
|
||
* is true, then the selected state of `item` will be toggled; otherwise
|
||
* the `item` will be selected.
|
||
* @method select
|
||
* @param {any} item: The item to select.
|
||
*/
|
||
select: function(item) {
|
||
if (this.multi) {
|
||
this.toggle(item);
|
||
} else if (this.getSelection() !== item) {
|
||
this.setItemSelected(this.getSelection(), false);
|
||
this.setItemSelected(item, true);
|
||
}
|
||
},
|
||
/**
|
||
* Toggles the selection state for `item`.
|
||
* @method toggle
|
||
* @param {any} item: The item to toggle.
|
||
*/
|
||
toggle: function(item) {
|
||
this.setItemSelected(item, !this.isSelected(item));
|
||
}
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="core-selector" attributes="selected multi valueattr selectedClass selectedProperty selectedAttribute selectedItem selectedModel selectedIndex notap excludedLocalNames target itemsSelector activateEvent" assetpath="polymer/bower_components/core-selector/">
|
||
|
||
<template>
|
||
<core-selection id="selection" multi="{{multi}}" on-core-select="{{selectionSelect}}"></core-selection>
|
||
<content id="items" select="*"></content>
|
||
</template>
|
||
|
||
<script>
|
||
|
||
Polymer('core-selector', {
|
||
|
||
/**
|
||
* Gets or sets the selected element. Default to use the index
|
||
* of the item element.
|
||
*
|
||
* If you want a specific attribute value of the element to be
|
||
* used instead of index, set "valueattr" to that attribute name.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-selector valueattr="label" selected="foo">
|
||
* <div label="foo"></div>
|
||
* <div label="bar"></div>
|
||
* <div label="zot"></div>
|
||
* </core-selector>
|
||
*
|
||
* In multi-selection this should be an array of values.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-selector id="selector" valueattr="label" multi>
|
||
* <div label="foo"></div>
|
||
* <div label="bar"></div>
|
||
* <div label="zot"></div>
|
||
* </core-selector>
|
||
*
|
||
* this.$.selector.selected = ['foo', 'zot'];
|
||
*
|
||
* @attribute selected
|
||
* @type Object
|
||
* @default null
|
||
*/
|
||
selected: null,
|
||
|
||
/**
|
||
* If true, multiple selections are allowed.
|
||
*
|
||
* @attribute multi
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
multi: false,
|
||
|
||
/**
|
||
* Specifies the attribute to be used for "selected" attribute.
|
||
*
|
||
* @attribute valueattr
|
||
* @type string
|
||
* @default 'name'
|
||
*/
|
||
valueattr: 'name',
|
||
|
||
/**
|
||
* Specifies the CSS class to be used to add to the selected element.
|
||
*
|
||
* @attribute selectedClass
|
||
* @type string
|
||
* @default 'core-selected'
|
||
*/
|
||
selectedClass: 'core-selected',
|
||
|
||
/**
|
||
* Specifies the property to be used to set on the selected element
|
||
* to indicate its active state.
|
||
*
|
||
* @attribute selectedProperty
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
selectedProperty: '',
|
||
|
||
/**
|
||
* Specifies the attribute to set on the selected element to indicate
|
||
* its active state.
|
||
*
|
||
* @attribute selectedAttribute
|
||
* @type string
|
||
* @default 'active'
|
||
*/
|
||
selectedAttribute: 'active',
|
||
|
||
/**
|
||
* Returns the currently selected element. In multi-selection this returns
|
||
* an array of selected elements.
|
||
* Note that you should not use this to set the selection. Instead use
|
||
* `selected`.
|
||
*
|
||
* @attribute selectedItem
|
||
* @type Object
|
||
* @default null
|
||
*/
|
||
selectedItem: null,
|
||
|
||
/**
|
||
* In single selection, this returns the model associated with the
|
||
* selected element.
|
||
* Note that you should not use this to set the selection. Instead use
|
||
* `selected`.
|
||
*
|
||
* @attribute selectedModel
|
||
* @type Object
|
||
* @default null
|
||
*/
|
||
selectedModel: null,
|
||
|
||
/**
|
||
* In single selection, this returns the selected index.
|
||
* Note that you should not use this to set the selection. Instead use
|
||
* `selected`.
|
||
*
|
||
* @attribute selectedIndex
|
||
* @type number
|
||
* @default -1
|
||
*/
|
||
selectedIndex: -1,
|
||
|
||
/**
|
||
* Nodes with local name that are in the list will not be included
|
||
* in the selection items. In the following example, `items` returns four
|
||
* `core-item`'s and doesn't include `h3` and `hr`.
|
||
*
|
||
* <core-selector excludedLocalNames="h3 hr">
|
||
* <h3>Header</h3>
|
||
* <core-item>Item1</core-item>
|
||
* <core-item>Item2</core-item>
|
||
* <hr>
|
||
* <core-item>Item3</core-item>
|
||
* <core-item>Item4</core-item>
|
||
* </core-selector>
|
||
*
|
||
* @attribute excludedLocalNames
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
excludedLocalNames: '',
|
||
|
||
/**
|
||
* The target element that contains items. If this is not set
|
||
* core-selector is the container.
|
||
*
|
||
* @attribute target
|
||
* @type Object
|
||
* @default null
|
||
*/
|
||
target: null,
|
||
|
||
/**
|
||
* This can be used to query nodes from the target node to be used for
|
||
* selection items. Note this only works if `target` is set
|
||
* and is not `core-selector` itself.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-selector target="{{$.myForm}}" itemsSelector="input[type=radio]"></core-selector>
|
||
* <form id="myForm">
|
||
* <label><input type="radio" name="color" value="red"> Red</label> <br>
|
||
* <label><input type="radio" name="color" value="green"> Green</label> <br>
|
||
* <label><input type="radio" name="color" value="blue"> Blue</label> <br>
|
||
* <p>color = {{color}}</p>
|
||
* </form>
|
||
*
|
||
* @attribute itemsSelector
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
itemsSelector: '',
|
||
|
||
/**
|
||
* The event that would be fired from the item element to indicate
|
||
* it is being selected.
|
||
*
|
||
* @attribute activateEvent
|
||
* @type string
|
||
* @default 'tap'
|
||
*/
|
||
activateEvent: 'tap',
|
||
|
||
/**
|
||
* Set this to true to disallow changing the selection via the
|
||
* `activateEvent`.
|
||
*
|
||
* @attribute notap
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
notap: false,
|
||
|
||
defaultExcludedLocalNames: 'template',
|
||
|
||
ready: function() {
|
||
this.activateListener = this.activateHandler.bind(this);
|
||
this.itemFilter = this.filterItem.bind(this);
|
||
this.excludedLocalNamesChanged();
|
||
this.observer = new MutationObserver(this.updateSelected.bind(this));
|
||
if (!this.target) {
|
||
this.target = this;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Returns an array of all items.
|
||
*
|
||
* @property items
|
||
*/
|
||
get items() {
|
||
if (!this.target) {
|
||
return [];
|
||
}
|
||
var nodes = this.target !== this ? (this.itemsSelector ?
|
||
this.target.querySelectorAll(this.itemsSelector) :
|
||
this.target.children) : this.$.items.getDistributedNodes();
|
||
return Array.prototype.filter.call(nodes, this.itemFilter);
|
||
},
|
||
|
||
filterItem: function(node) {
|
||
return !this._excludedNames[node.localName];
|
||
},
|
||
|
||
excludedLocalNamesChanged: function() {
|
||
this._excludedNames = {};
|
||
var s = this.defaultExcludedLocalNames;
|
||
if (this.excludedLocalNames) {
|
||
s += ' ' + this.excludedLocalNames;
|
||
}
|
||
s.split(/\s+/g).forEach(function(n) {
|
||
this._excludedNames[n] = 1;
|
||
}, this);
|
||
},
|
||
|
||
targetChanged: function(old) {
|
||
if (old) {
|
||
this.removeListener(old);
|
||
this.observer.disconnect();
|
||
this.clearSelection();
|
||
}
|
||
if (this.target) {
|
||
this.addListener(this.target);
|
||
this.observer.observe(this.target, {childList: true});
|
||
this.updateSelected();
|
||
}
|
||
},
|
||
|
||
addListener: function(node) {
|
||
Polymer.addEventListener(node, this.activateEvent, this.activateListener);
|
||
},
|
||
|
||
removeListener: function(node) {
|
||
Polymer.removeEventListener(node, this.activateEvent, this.activateListener);
|
||
},
|
||
|
||
/**
|
||
* Returns the selected item(s). If the `multi` property is true,
|
||
* this will return an array, otherwise it will return
|
||
* the selected item or undefined if there is no selection.
|
||
*/
|
||
get selection() {
|
||
return this.$.selection.getSelection();
|
||
},
|
||
|
||
selectedChanged: function() {
|
||
this.updateSelected();
|
||
},
|
||
|
||
updateSelected: function() {
|
||
this.validateSelected();
|
||
if (this.multi) {
|
||
this.clearSelection();
|
||
this.selected && this.selected.forEach(function(s) {
|
||
this.valueToSelection(s);
|
||
}, this);
|
||
} else {
|
||
this.valueToSelection(this.selected);
|
||
}
|
||
},
|
||
|
||
validateSelected: function() {
|
||
// convert to an array for multi-selection
|
||
if (this.multi && !Array.isArray(this.selected) &&
|
||
this.selected !== null && this.selected !== undefined) {
|
||
this.selected = [this.selected];
|
||
}
|
||
},
|
||
|
||
clearSelection: function() {
|
||
if (this.multi) {
|
||
this.selection.slice().forEach(function(s) {
|
||
this.$.selection.setItemSelected(s, false);
|
||
}, this);
|
||
} else {
|
||
this.$.selection.setItemSelected(this.selection, false);
|
||
}
|
||
this.selectedItem = null;
|
||
this.$.selection.clear();
|
||
},
|
||
|
||
valueToSelection: function(value) {
|
||
var item = (value === null || value === undefined) ?
|
||
null : this.items[this.valueToIndex(value)];
|
||
this.$.selection.select(item);
|
||
},
|
||
|
||
updateSelectedItem: function() {
|
||
this.selectedItem = this.selection;
|
||
},
|
||
|
||
selectedItemChanged: function() {
|
||
if (this.selectedItem) {
|
||
var t = this.selectedItem.templateInstance;
|
||
this.selectedModel = t ? t.model : undefined;
|
||
} else {
|
||
this.selectedModel = null;
|
||
}
|
||
this.selectedIndex = this.selectedItem ?
|
||
parseInt(this.valueToIndex(this.selected)) : -1;
|
||
},
|
||
|
||
valueToIndex: function(value) {
|
||
// find an item with value == value and return it's index
|
||
for (var i=0, items=this.items, c; (c=items[i]); i++) {
|
||
if (this.valueForNode(c) == value) {
|
||
return i;
|
||
}
|
||
}
|
||
// if no item found, the value itself is probably the index
|
||
return value;
|
||
},
|
||
|
||
valueForNode: function(node) {
|
||
return node[this.valueattr] || node.getAttribute(this.valueattr);
|
||
},
|
||
|
||
// events fired from <core-selection> object
|
||
selectionSelect: function(e, detail) {
|
||
this.updateSelectedItem();
|
||
if (detail.item) {
|
||
this.applySelection(detail.item, detail.isSelected);
|
||
}
|
||
},
|
||
|
||
applySelection: function(item, isSelected) {
|
||
if (this.selectedClass) {
|
||
item.classList.toggle(this.selectedClass, isSelected);
|
||
}
|
||
if (this.selectedProperty) {
|
||
item[this.selectedProperty] = isSelected;
|
||
}
|
||
if (this.selectedAttribute && item.setAttribute) {
|
||
if (isSelected) {
|
||
item.setAttribute(this.selectedAttribute, '');
|
||
} else {
|
||
item.removeAttribute(this.selectedAttribute);
|
||
}
|
||
}
|
||
},
|
||
|
||
// event fired from host
|
||
activateHandler: function(e) {
|
||
if (!this.notap) {
|
||
var i = this.findDistributedTarget(e.target, this.items);
|
||
if (i >= 0) {
|
||
var item = this.items[i];
|
||
var s = this.valueForNode(item) || i;
|
||
if (this.multi) {
|
||
if (this.selected) {
|
||
this.addRemoveSelected(s);
|
||
} else {
|
||
this.selected = [s];
|
||
}
|
||
} else {
|
||
this.selected = s;
|
||
}
|
||
this.asyncFire('core-activate', {item: item});
|
||
}
|
||
}
|
||
},
|
||
|
||
addRemoveSelected: function(value) {
|
||
var i = this.selected.indexOf(value);
|
||
if (i >= 0) {
|
||
this.selected.splice(i, 1);
|
||
} else {
|
||
this.selected.push(value);
|
||
}
|
||
this.valueToSelection(value);
|
||
},
|
||
|
||
findDistributedTarget: function(target, nodes) {
|
||
// find first ancestor of target (including itself) that
|
||
// is in nodes, if any
|
||
while (target && target != this) {
|
||
var i = Array.prototype.indexOf.call(nodes, target);
|
||
if (i >= 0) {
|
||
return i;
|
||
}
|
||
target = target.parentNode;
|
||
}
|
||
},
|
||
|
||
selectIndex: function(index) {
|
||
var item = this.items[index];
|
||
if (item) {
|
||
this.selected = this.valueForNode(item) || index;
|
||
return item;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Selects the previous item. This should be used in single selection only.
|
||
*
|
||
* @method selectPrevious
|
||
* @param {boolean} wrap if true and it is already at the first item, wrap to the end
|
||
* @returns the previous item or undefined if there is none
|
||
*/
|
||
selectPrevious: function(wrap) {
|
||
var i = wrap && !this.selectedIndex ? this.items.length - 1 : this.selectedIndex - 1;
|
||
return this.selectIndex(i);
|
||
},
|
||
|
||
/**
|
||
* Selects the next item. This should be used in single selection only.
|
||
*
|
||
* @method selectNext
|
||
* @param {boolean} wrap if true and it is already at the last item, wrap to the front
|
||
* @returns the next item or undefined if there is none
|
||
*/
|
||
selectNext: function(wrap) {
|
||
var i = wrap && this.selectedIndex >= this.items.length - 1 ? 0 : this.selectedIndex + 1;
|
||
return this.selectIndex(i);
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="core-menu" extends="core-selector" assetpath="polymer/bower_components/core-menu/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: block;
|
||
margin: 12px;
|
||
}
|
||
|
||
polyfill-next-selector { content: ':host > core-item'; }
|
||
::content > core-item {
|
||
cursor: default;
|
||
}
|
||
</style>
|
||
|
||
<shadow></shadow>
|
||
|
||
</template>
|
||
<script>Polymer('core-menu');</script></polymer-element>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<!--
|
||
@group Paper Elements
|
||
@class paper-menu-button-transition
|
||
@extends core-transition-css
|
||
-->
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
|
||
`<core-transition-css>` implements CSS transitions as `<core-transition>` objects so they can be
|
||
reused in a pluggable transition system such as in `<core-overlay>`. Currently this class has
|
||
some specific support to animate an element from and to the viewport such as a dialog, but you
|
||
can override it for different effects.
|
||
|
||
Example:
|
||
|
||
my-css-transition.html:
|
||
|
||
<polymer-element name="my-css-transition" extends="core-transition-css">
|
||
<template>
|
||
<style>
|
||
:host(.my-transition) {
|
||
opacity: 0;
|
||
transition: transform 1s ease-out, opacity 1s ease-out;
|
||
}
|
||
:host(.my-transition.my-opened) {
|
||
opacity: 1;
|
||
transform: none;
|
||
}
|
||
:host(.my-transition-top) {
|
||
transform: translateY(-100vh);
|
||
}
|
||
:host(.my-transition-bottom) {
|
||
transform: translateY(100vh);
|
||
}
|
||
</style>
|
||
</template>
|
||
<script>
|
||
Polymer({
|
||
baseClass: 'my-transition',
|
||
openedClass: 'my-opened'
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<my-css-transition id="my-transition-top" transitionType="top"></my-css-transition>
|
||
<my-css-transition id="my-transition-bottom" transitionType="bottom"></my-css-transition>
|
||
|
||
my-css-transition-demo.html
|
||
|
||
<link href="components/core-meta/core-meta.html" rel="import">
|
||
<link href="my-css-transition.html">
|
||
|
||
<div id="animate-me"></div>
|
||
|
||
<script>
|
||
// Get the core-transition
|
||
var meta = document.createElement('core-meta');
|
||
meta.type = 'transition';
|
||
var transition1 = meta.byId('my-transition-top');
|
||
|
||
// Set up the animation
|
||
var animated = document.getElementById('animate-me');
|
||
transition1.setup(animated);
|
||
transition1.go(animated, {opened: true});
|
||
</script>
|
||
|
||
The first element in the template of a `<core-transition-css>` object should be a stylesheet. It
|
||
will be injected to the scope of the animated node in the `setup` function. The node is initially
|
||
invisible with `opacity: 0`, and you can transition it to an "opened" state by passing
|
||
`{opened: true}` to the `go` function.
|
||
|
||
All nodes being animated will get the class `my-transition` added in the `setup` function.
|
||
Additionally, the class `my-transition-<transitionType>` will be applied. You can use the
|
||
`transitionType` attribute to implement several different behaviors with the same
|
||
`<core-transition-css>` object. In the above example, `<my-css-transition>` implements both
|
||
sliding the node from the top of the viewport and from the bottom of the viewport.
|
||
|
||
Available transitions
|
||
---------------------
|
||
|
||
`<core-transition-css>` includes several commonly used transitions.
|
||
|
||
`core-transition-fade`: Animates from `opacity: 0` to `opacity: 1` when it opens.
|
||
|
||
`core-transition-center`: Zooms the node into the final size.
|
||
|
||
`core-transition-top`: Slides the node into the final position from the top.
|
||
|
||
`core-transition-bottom`: Slides the node into the final position from the bottom.
|
||
|
||
`core-transition-left`: Slides the node into the final position from the left.
|
||
|
||
`core-transition-right`: Slides the node into the final position from the right.
|
||
|
||
@group Polymer Core Elements
|
||
@element core-transition-css
|
||
@extends core-transition
|
||
@status beta
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-transition-css" extends="core-transition" attributes="transitionType" assetpath="polymer/bower_components/core-transition/">
|
||
<template>
|
||
<style no-shim="">/* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */
|
||
|
||
:host(.core-transition) {
|
||
outline: none;
|
||
overflow: auto;
|
||
opacity: 0;
|
||
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in;
|
||
-webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in;
|
||
}
|
||
|
||
|
||
:host(.core-transition.core-opened) {
|
||
opacity: 1;
|
||
transform: translateZ(0);
|
||
-webkit-transform: translateZ(0);
|
||
}
|
||
|
||
:host(.core-transition-center) {
|
||
transform: scale(0.5);
|
||
-webkit-transform: scale(0.5);
|
||
}
|
||
|
||
:host(.core-transition-top) {
|
||
transform: translateY(-200%);
|
||
-webkit-transform: translateY(-200%);
|
||
}
|
||
|
||
:host(.core-transition-bottom) {
|
||
transform: translateY(200%);
|
||
-webkit-transform: translateY(200%);
|
||
}
|
||
|
||
:host(.core-transition-left) {
|
||
transform: translateX(-200%);
|
||
-webkit-transform: translateX(-200%);
|
||
}
|
||
|
||
:host(.core-transition-right) {
|
||
transform: translateX(200%);
|
||
-webkit-transform: translateX(200%);
|
||
}</style>
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('core-transition-css', {
|
||
|
||
/**
|
||
* The class that will be applied to all animated nodes.
|
||
*
|
||
* @attribute baseClass
|
||
* @type string
|
||
* @default "core-transition"
|
||
*/
|
||
baseClass: 'core-transition',
|
||
|
||
/**
|
||
* The class that will be applied to nodes in the opened state.
|
||
*
|
||
* @attribute openedClass
|
||
* @type string
|
||
* @default "core-opened"
|
||
*/
|
||
openedClass: 'core-opened',
|
||
|
||
/**
|
||
* The class that will be applied to nodes in the closed state.
|
||
*
|
||
* @attribute closedClass
|
||
* @type string
|
||
* @default "core-closed"
|
||
*/
|
||
closedClass: 'core-closed',
|
||
|
||
/**
|
||
* Event to listen to for animation completion.
|
||
*
|
||
* @attribute completeEventName
|
||
* @type string
|
||
* @default "transitionEnd"
|
||
*/
|
||
completeEventName: 'transitionend',
|
||
|
||
publish: {
|
||
/**
|
||
* A secondary configuration attribute for the animation. The class
|
||
* `<baseClass>-<transitionType` is applied to the animated node during
|
||
* `setup`.
|
||
*
|
||
* @attribute transitionType
|
||
* @type string
|
||
*/
|
||
transitionType: null
|
||
},
|
||
|
||
registerCallback: function(element) {
|
||
this.transitionStyle = element.templateContent().firstElementChild;
|
||
},
|
||
|
||
// template is just for loading styles, we don't need a shadowRoot
|
||
fetchTemplate: function() {
|
||
return null;
|
||
},
|
||
|
||
go: function(node, state) {
|
||
if (state.opened !== undefined) {
|
||
this.transitionOpened(node, state.opened);
|
||
}
|
||
},
|
||
|
||
setup: function(node) {
|
||
if (!node._hasTransitionStyle) {
|
||
if (!node.shadowRoot) {
|
||
node.createShadowRoot().innerHTML = '<content></content>';
|
||
}
|
||
this.installScopeStyle(this.transitionStyle, 'transition',
|
||
node.shadowRoot);
|
||
node._hasTransitionStyle = true;
|
||
}
|
||
node.classList.add(this.baseClass);
|
||
if (this.transitionType) {
|
||
node.classList.add(this.baseClass + '-' + this.transitionType);
|
||
}
|
||
},
|
||
|
||
teardown: function(node) {
|
||
node.classList.remove(this.baseClass);
|
||
if (this.transitionType) {
|
||
node.classList.remove(this.baseClass + '-' + this.transitionType);
|
||
}
|
||
},
|
||
|
||
transitionOpened: function(node, opened) {
|
||
this.listenOnce(node, this.completeEventName, function() {
|
||
node.classList.toggle(this.revealedClass, opened);
|
||
if (!opened) {
|
||
node.classList.remove(this.closedClass);
|
||
}
|
||
this.complete(node);
|
||
});
|
||
node.classList.toggle(this.openedClass, opened);
|
||
node.classList.toggle(this.closedClass, !opened);
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<core-transition-css id="core-transition-fade"></core-transition-css>
|
||
<core-transition-css id="core-transition-center" transitiontype="center"></core-transition-css>
|
||
<core-transition-css id="core-transition-top" transitiontype="top"></core-transition-css>
|
||
<core-transition-css id="core-transition-bottom" transitiontype="bottom"></core-transition-css>
|
||
<core-transition-css id="core-transition-left" transitiontype="left"></core-transition-css>
|
||
<core-transition-css id="core-transition-right" transitiontype="right"></core-transition-css>
|
||
|
||
<!--
|
||
@license
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<script>/**
|
||
* Copyright 2012 Google Inc. All Rights Reserved.
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
(function() {
|
||
'use strict';
|
||
|
||
var ASSERT_ENABLED = false;
|
||
var SVG_NS = 'http://www.w3.org/2000/svg';
|
||
|
||
function assert(check, message) {
|
||
console.assert(ASSERT_ENABLED,
|
||
'assert should not be called when ASSERT_ENABLED is false');
|
||
console.assert(check, message);
|
||
// Some implementations of console.assert don't actually throw
|
||
if (!check) { throw message; }
|
||
}
|
||
|
||
function detectFeatures() {
|
||
var el = createDummyElement();
|
||
el.style.cssText = 'width: calc(0px);' +
|
||
'width: -webkit-calc(0px);';
|
||
var calcFunction = el.style.width.split('(')[0];
|
||
function detectProperty(candidateProperties) {
|
||
return [].filter.call(candidateProperties, function(property) {
|
||
return property in el.style;
|
||
})[0];
|
||
}
|
||
var transformProperty = detectProperty([
|
||
'transform',
|
||
'webkitTransform',
|
||
'msTransform']);
|
||
var perspectiveProperty = detectProperty([
|
||
'perspective',
|
||
'webkitPerspective',
|
||
'msPerspective']);
|
||
return {
|
||
calcFunction: calcFunction,
|
||
transformProperty: transformProperty,
|
||
transformOriginProperty: transformProperty + 'Origin',
|
||
perspectiveProperty: perspectiveProperty,
|
||
perspectiveOriginProperty: perspectiveProperty + 'Origin'
|
||
};
|
||
}
|
||
var features = detectFeatures();
|
||
|
||
function prefixProperty(property) {
|
||
switch (property) {
|
||
case 'transform':
|
||
return features.transformProperty;
|
||
case 'transformOrigin':
|
||
return features.transformOriginProperty;
|
||
case 'perspective':
|
||
return features.perspectiveProperty;
|
||
case 'perspectiveOrigin':
|
||
return features.perspectiveOriginProperty;
|
||
default:
|
||
return property;
|
||
}
|
||
}
|
||
|
||
function createDummyElement() {
|
||
return document.documentElement.namespaceURI == SVG_NS ?
|
||
document.createElementNS(SVG_NS, 'g') :
|
||
document.createElement('div');
|
||
}
|
||
|
||
var constructorToken = {};
|
||
var deprecationsSilenced = {};
|
||
|
||
var createObject = function(proto, obj) {
|
||
var newObject = Object.create(proto);
|
||
Object.getOwnPropertyNames(obj).forEach(function(name) {
|
||
Object.defineProperty(
|
||
newObject, name, Object.getOwnPropertyDescriptor(obj, name));
|
||
});
|
||
return newObject;
|
||
};
|
||
|
||
var abstractMethod = function() {
|
||
throw 'Abstract method not implemented.';
|
||
};
|
||
|
||
var deprecated = function(name, deprecationDate, advice, plural) {
|
||
if (deprecationsSilenced[name]) {
|
||
return;
|
||
}
|
||
var auxVerb = plural ? 'are' : 'is';
|
||
var today = new Date();
|
||
var cutoffDate = new Date(deprecationDate);
|
||
cutoffDate.setMonth(cutoffDate.getMonth() + 3); // 3 months grace period
|
||
|
||
if (today < cutoffDate) {
|
||
console.warn('Web Animations: ' + name +
|
||
' ' + auxVerb + ' deprecated and will stop working on ' +
|
||
cutoffDate.toDateString() + '. ' + advice);
|
||
deprecationsSilenced[name] = true;
|
||
} else {
|
||
throw new Error(name + ' ' + auxVerb + ' no longer supported. ' + advice);
|
||
}
|
||
};
|
||
|
||
var defineDeprecatedProperty = function(object, property, getFunc, setFunc) {
|
||
var descriptor = {
|
||
get: getFunc,
|
||
configurable: true
|
||
};
|
||
if (setFunc) {
|
||
descriptor.set = setFunc;
|
||
}
|
||
Object.defineProperty(object, property, descriptor);
|
||
};
|
||
|
||
var IndexSizeError = function(message) {
|
||
Error.call(this);
|
||
this.name = 'IndexSizeError';
|
||
this.message = message;
|
||
};
|
||
|
||
IndexSizeError.prototype = Object.create(Error.prototype);
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var TimingDict = function(timingInput) {
|
||
if (typeof timingInput === 'object') {
|
||
for (var k in timingInput) {
|
||
if (k in TimingDict.prototype) {
|
||
this[k] = timingInput[k];
|
||
}
|
||
}
|
||
} else if (isDefinedAndNotNull(timingInput)) {
|
||
this.duration = Number(timingInput);
|
||
}
|
||
};
|
||
|
||
TimingDict.prototype = {
|
||
delay: 0,
|
||
endDelay: 0,
|
||
fill: 'auto',
|
||
iterationStart: 0,
|
||
iterations: 1,
|
||
duration: 'auto',
|
||
playbackRate: 1,
|
||
direction: 'normal',
|
||
easing: 'linear'
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var Timing = function(token, timingInput, changeHandler) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
this._dict = new TimingDict(timingInput);
|
||
this._changeHandler = changeHandler;
|
||
};
|
||
|
||
Timing.prototype = {
|
||
_timingFunction: function(timedItem) {
|
||
var timingFunction = TimingFunction.createFromString(
|
||
this.easing, timedItem);
|
||
this._timingFunction = function() {
|
||
return timingFunction;
|
||
};
|
||
return timingFunction;
|
||
},
|
||
_invalidateTimingFunction: function() {
|
||
delete this._timingFunction;
|
||
},
|
||
_iterations: function() {
|
||
var value = this._dict.iterations;
|
||
return value < 0 ? 1 : value;
|
||
},
|
||
_duration: function() {
|
||
var value = this._dict.duration;
|
||
return typeof value === 'number' ? value : 'auto';
|
||
},
|
||
_clone: function() {
|
||
return new Timing(
|
||
constructorToken, this._dict, this._updateInternalState.bind(this));
|
||
}
|
||
};
|
||
|
||
// Configures an accessor descriptor for use with Object.defineProperty() to
|
||
// allow the property to be changed and enumerated, to match __defineGetter__()
|
||
// and __defineSetter__().
|
||
var configureDescriptor = function(descriptor) {
|
||
descriptor.configurable = true;
|
||
descriptor.enumerable = true;
|
||
return descriptor;
|
||
};
|
||
|
||
Timing._defineProperty = function(prop) {
|
||
Object.defineProperty(Timing.prototype, prop, configureDescriptor({
|
||
get: function() {
|
||
return this._dict[prop];
|
||
},
|
||
set: function(value) {
|
||
if (isDefinedAndNotNull(value)) {
|
||
if (prop == 'duration' && value == 'auto') {
|
||
// duration is not always a number
|
||
} else if (['delay', 'endDelay', 'iterationStart', 'iterations',
|
||
'duration', 'playbackRate'].indexOf(prop) >= 0) {
|
||
value = Number(value);
|
||
}
|
||
this._dict[prop] = value;
|
||
} else {
|
||
delete this._dict[prop];
|
||
}
|
||
// FIXME: probably need to implement specialized handling parsing
|
||
// for each property
|
||
if (prop === 'easing') {
|
||
// Cached timing function may be invalid now.
|
||
this._invalidateTimingFunction();
|
||
}
|
||
this._changeHandler();
|
||
}
|
||
}));
|
||
};
|
||
|
||
for (var prop in TimingDict.prototype) {
|
||
Timing._defineProperty(prop);
|
||
}
|
||
|
||
var isDefined = function(val) {
|
||
return typeof val !== 'undefined';
|
||
};
|
||
|
||
var isDefinedAndNotNull = function(val) {
|
||
return isDefined(val) && (val !== null);
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AnimationTimeline = function(token) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
// TODO: This will probably need to change.
|
||
this._startTime = documentTimeZeroAsClockTime;
|
||
};
|
||
|
||
AnimationTimeline.prototype = {
|
||
get currentTime() {
|
||
if (this._startTime === undefined) {
|
||
this._startTime = documentTimeZeroAsClockTime;
|
||
if (this._startTime === undefined) {
|
||
return null;
|
||
}
|
||
}
|
||
return relativeTime(cachedClockTime(), this._startTime);
|
||
},
|
||
get effectiveCurrentTime() {
|
||
return this.currentTime || 0;
|
||
},
|
||
play: function(source) {
|
||
return new AnimationPlayer(constructorToken, source, this);
|
||
},
|
||
getCurrentPlayers: function() {
|
||
return PLAYERS.filter(function(player) {
|
||
return !player._isPastEndOfActiveInterval();
|
||
});
|
||
},
|
||
toTimelineTime: function(otherTime, other) {
|
||
if ((this.currentTime === null) || (other.currentTime === null)) {
|
||
return null;
|
||
} else {
|
||
return otherTime + other._startTime - this._startTime;
|
||
}
|
||
},
|
||
_pauseAnimationsForTesting: function(pauseAt) {
|
||
PLAYERS.forEach(function(player) {
|
||
player.pause();
|
||
player.currentTime = pauseAt;
|
||
});
|
||
}
|
||
};
|
||
|
||
// TODO: Remove dead players from here?
|
||
var PLAYERS = [];
|
||
var playersAreSorted = false;
|
||
var playerSequenceNumber = 0;
|
||
|
||
// Methods for event target objects.
|
||
var initializeEventTarget = function(eventTarget) {
|
||
eventTarget._handlers = {};
|
||
eventTarget._onHandlers = {};
|
||
};
|
||
var setOnEventHandler = function(eventTarget, type, handler) {
|
||
if (typeof handler === 'function') {
|
||
eventTarget._onHandlers[type] = {
|
||
callback: handler,
|
||
index: (eventTarget._handlers[type] || []).length
|
||
};
|
||
} else {
|
||
eventTarget._onHandlers[type] = null;
|
||
}
|
||
};
|
||
var getOnEventHandler = function(eventTarget, type) {
|
||
if (isDefinedAndNotNull(eventTarget._onHandlers[type])) {
|
||
return eventTarget._onHandlers[type].callback;
|
||
}
|
||
return null;
|
||
};
|
||
var addEventHandler = function(eventTarget, type, handler) {
|
||
if (typeof handler !== 'function') {
|
||
return;
|
||
}
|
||
if (!isDefinedAndNotNull(eventTarget._handlers[type])) {
|
||
eventTarget._handlers[type] = [];
|
||
} else if (eventTarget._handlers[type].indexOf(handler) !== -1) {
|
||
return;
|
||
}
|
||
eventTarget._handlers[type].push(handler);
|
||
};
|
||
var removeEventHandler = function(eventTarget, type, handler) {
|
||
if (!eventTarget._handlers[type]) {
|
||
return;
|
||
}
|
||
var index = eventTarget._handlers[type].indexOf(handler);
|
||
if (index === -1) {
|
||
return;
|
||
}
|
||
eventTarget._handlers[type].splice(index, 1);
|
||
if (isDefinedAndNotNull(eventTarget._onHandlers[type]) &&
|
||
(index < eventTarget._onHandlers[type].index)) {
|
||
eventTarget._onHandlers[type].index -= 1;
|
||
}
|
||
};
|
||
var hasEventHandlersForEvent = function(eventTarget, type) {
|
||
return (isDefinedAndNotNull(eventTarget._handlers[type]) &&
|
||
eventTarget._handlers[type].length > 0) ||
|
||
isDefinedAndNotNull(eventTarget._onHandlers[type]);
|
||
};
|
||
var callEventHandlers = function(eventTarget, type, event) {
|
||
var callbackList;
|
||
if (isDefinedAndNotNull(eventTarget._handlers[type])) {
|
||
callbackList = eventTarget._handlers[type].slice();
|
||
} else {
|
||
callbackList = [];
|
||
}
|
||
if (isDefinedAndNotNull(eventTarget._onHandlers[type])) {
|
||
callbackList.splice(eventTarget._onHandlers[type].index, 0,
|
||
eventTarget._onHandlers[type].callback);
|
||
}
|
||
setTimeout(function() {
|
||
for (var i = 0; i < callbackList.length; i++) {
|
||
callbackList[i].call(eventTarget, event);
|
||
}
|
||
}, 0);
|
||
};
|
||
var createEventPrototype = function() {
|
||
var prototype = Object.create(window.Event.prototype, {
|
||
type: { get: function() { return this._type; } },
|
||
target: { get: function() { return this._target; } },
|
||
currentTarget: { get: function() { return this._target; } },
|
||
eventPhase: { get: function() { return this._eventPhase; } },
|
||
bubbles: { get: function() { return false; } },
|
||
cancelable: { get: function() { return false; } },
|
||
timeStamp: { get: function() { return this._timeStamp; } },
|
||
defaultPrevented: { get: function() { return false; } }
|
||
});
|
||
prototype._type = '';
|
||
prototype._target = null;
|
||
prototype._eventPhase = Event.NONE;
|
||
prototype._timeStamp = 0;
|
||
prototype._initialize = function(target) {
|
||
this._target = target;
|
||
this._eventPhase = Event.AT_TARGET;
|
||
this._timeStamp = cachedClockTime();
|
||
};
|
||
return prototype;
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AnimationPlayer = function(token, source, timeline) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
this._registeredOnTimeline = false;
|
||
this._sequenceNumber = playerSequenceNumber++;
|
||
this._timeline = timeline;
|
||
this._startTime =
|
||
this.timeline.currentTime === null ? 0 : this.timeline.currentTime;
|
||
this._storedTimeLag = 0.0;
|
||
this._pausedState = false;
|
||
this._holdTime = null;
|
||
this._previousCurrentTime = null;
|
||
this._playbackRate = 1.0;
|
||
this._hasTicked = false;
|
||
|
||
this.source = source;
|
||
this._lastCurrentTime = undefined;
|
||
this._finishedFlag = false;
|
||
initializeEventTarget(this);
|
||
|
||
playersAreSorted = false;
|
||
maybeRestartAnimation();
|
||
} finally {
|
||
exitModifyCurrentAnimationState(ensureRetickBeforeGetComputedStyle);
|
||
}
|
||
};
|
||
|
||
AnimationPlayer.prototype = {
|
||
set source(source) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
if (isDefinedAndNotNull(this.source)) {
|
||
// To prevent infinite recursion.
|
||
var oldTimedItem = this.source;
|
||
this._source = null;
|
||
oldTimedItem._attach(null);
|
||
}
|
||
this._source = source;
|
||
if (isDefinedAndNotNull(this.source)) {
|
||
this.source._attach(this);
|
||
this._update();
|
||
maybeRestartAnimation();
|
||
}
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get source() {
|
||
return this._source;
|
||
},
|
||
// This is the effective current time.
|
||
set currentTime(currentTime) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
this._currentTime = currentTime;
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get currentTime() {
|
||
return this._currentTime;
|
||
},
|
||
set _currentTime(seekTime) {
|
||
// If we are paused or seeking to a time where limiting applies (i.e. beyond
|
||
// the end in the current direction), update the hold time.
|
||
var sourceContentEnd = this.source ? this.source.endTime : 0;
|
||
if (this.paused ||
|
||
(this.playbackRate > 0 && seekTime >= sourceContentEnd) ||
|
||
(this.playbackRate < 0 && seekTime <= 0)) {
|
||
this._holdTime = seekTime;
|
||
// Otherwise, clear the hold time (it may been set by previously seeking to
|
||
// a limited time) and update the time lag.
|
||
} else {
|
||
this._holdTime = null;
|
||
this._storedTimeLag = (this.timeline.effectiveCurrentTime -
|
||
this.startTime) * this.playbackRate - seekTime;
|
||
}
|
||
this._update();
|
||
maybeRestartAnimation();
|
||
},
|
||
get _currentTime() {
|
||
this._previousCurrentTime = (this.timeline.effectiveCurrentTime -
|
||
this.startTime) * this.playbackRate - this.timeLag;
|
||
return this._previousCurrentTime;
|
||
},
|
||
get _unlimitedCurrentTime() {
|
||
return (this.timeline.effectiveCurrentTime - this.startTime) *
|
||
this.playbackRate - this._storedTimeLag;
|
||
},
|
||
get timeLag() {
|
||
if (this.paused) {
|
||
return this._pauseTimeLag;
|
||
}
|
||
|
||
// Apply limiting at start of interval when playing in reverse
|
||
if (this.playbackRate < 0 && this._unlimitedCurrentTime <= 0) {
|
||
if (this._holdTime === null) {
|
||
this._holdTime = Math.min(this._previousCurrentTime, 0);
|
||
}
|
||
return this._pauseTimeLag;
|
||
}
|
||
|
||
// Apply limiting at end of interval when playing forwards
|
||
var sourceContentEnd = this.source ? this.source.endTime : 0;
|
||
if (this.playbackRate > 0 &&
|
||
this._unlimitedCurrentTime >= sourceContentEnd) {
|
||
if (this._holdTime === null) {
|
||
this._holdTime = Math.max(this._previousCurrentTime, sourceContentEnd);
|
||
}
|
||
return this._pauseTimeLag;
|
||
}
|
||
|
||
// Finished limiting so store pause time lag
|
||
if (this._holdTime !== null) {
|
||
this._storedTimeLag = this._pauseTimeLag;
|
||
this._holdTime = null;
|
||
}
|
||
|
||
return this._storedTimeLag;
|
||
},
|
||
get _pauseTimeLag() {
|
||
return ((this.timeline.currentTime || 0) - this.startTime) *
|
||
this.playbackRate - this._holdTime;
|
||
},
|
||
set startTime(startTime) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
// This seeks by updating _startTime and hence the currentTime. It does
|
||
// not affect _storedTimeLag.
|
||
this._startTime = startTime;
|
||
this._holdTime = null;
|
||
playersAreSorted = false;
|
||
this._update();
|
||
maybeRestartAnimation();
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get startTime() {
|
||
return this._startTime;
|
||
},
|
||
set _paused(isPaused) {
|
||
if (isPaused === this._pausedState) {
|
||
return;
|
||
}
|
||
if (this._pausedState) {
|
||
this._storedTimeLag = this.timeLag;
|
||
this._holdTime = null;
|
||
maybeRestartAnimation();
|
||
} else {
|
||
this._holdTime = this.currentTime;
|
||
}
|
||
this._pausedState = isPaused;
|
||
},
|
||
get paused() {
|
||
return this._pausedState;
|
||
},
|
||
get timeline() {
|
||
return this._timeline;
|
||
},
|
||
set playbackRate(playbackRate) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
var cachedCurrentTime = this.currentTime;
|
||
// This will impact currentTime, so perform a compensatory seek.
|
||
this._playbackRate = playbackRate;
|
||
this.currentTime = cachedCurrentTime;
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get playbackRate() {
|
||
return this._playbackRate;
|
||
},
|
||
get finished() {
|
||
return this._isLimited;
|
||
},
|
||
get _isLimited() {
|
||
var sourceEnd = this.source ? this.source.endTime : 0;
|
||
return ((this.playbackRate > 0 && this.currentTime >= sourceEnd) ||
|
||
(this.playbackRate < 0 && this.currentTime <= 0));
|
||
},
|
||
cancel: function() {
|
||
this.source = null;
|
||
},
|
||
finish: function() {
|
||
if (this.playbackRate < 0) {
|
||
this.currentTime = 0;
|
||
} else if (this.playbackRate > 0) {
|
||
var sourceEndTime = this.source ? this.source.endTime : 0;
|
||
if (sourceEndTime === Infinity) {
|
||
throw new Error('InvalidStateError');
|
||
}
|
||
this.currentTime = sourceEndTime;
|
||
}
|
||
},
|
||
play: function() {
|
||
this._paused = false;
|
||
if (!this.source) {
|
||
return;
|
||
}
|
||
if (this.playbackRate > 0 &&
|
||
(this.currentTime < 0 ||
|
||
this.currentTime >= this.source.endTime)) {
|
||
this.currentTime = 0;
|
||
} else if (this.playbackRate < 0 &&
|
||
(this.currentTime <= 0 ||
|
||
this.currentTime > this.source.endTime)) {
|
||
this.currentTime = this.source.endTime;
|
||
}
|
||
},
|
||
pause: function() {
|
||
this._paused = true;
|
||
},
|
||
reverse: function() {
|
||
if (this.playbackRate === 0) {
|
||
return;
|
||
}
|
||
if (this.source) {
|
||
if (this.playbackRate > 0 && this.currentTime >= this.source.endTime) {
|
||
this.currentTime = this.source.endTime;
|
||
} else if (this.playbackRate < 0 && this.currentTime < 0) {
|
||
this.currentTime = 0;
|
||
}
|
||
}
|
||
this.playbackRate = -this.playbackRate;
|
||
this._paused = false;
|
||
},
|
||
_update: function() {
|
||
if (this.source !== null) {
|
||
this.source._updateInheritedTime(
|
||
this.timeline.currentTime === null ? null : this._currentTime);
|
||
this._registerOnTimeline();
|
||
}
|
||
},
|
||
_hasFutureAnimation: function() {
|
||
return this.source === null || this.playbackRate === 0 ||
|
||
this.source._hasFutureAnimation(this.playbackRate > 0);
|
||
},
|
||
_isPastEndOfActiveInterval: function() {
|
||
return this.source === null ||
|
||
this.source._isPastEndOfActiveInterval();
|
||
},
|
||
_isCurrent: function() {
|
||
return this.source && this.source._isCurrent();
|
||
},
|
||
_hasFutureEffect: function() {
|
||
return this.source && this.source._hasFutureEffect();
|
||
},
|
||
_getLeafItemsInEffect: function(items) {
|
||
if (this.source) {
|
||
this.source._getLeafItemsInEffect(items);
|
||
}
|
||
},
|
||
_isTargetingElement: function(element) {
|
||
return this.source && this.source._isTargetingElement(element);
|
||
},
|
||
_getAnimationsTargetingElement: function(element, animations) {
|
||
if (this.source) {
|
||
this.source._getAnimationsTargetingElement(element, animations);
|
||
}
|
||
},
|
||
set onfinish(handler) {
|
||
return setOnEventHandler(this, 'finish', handler);
|
||
},
|
||
get onfinish() {
|
||
return getOnEventHandler(this, 'finish');
|
||
},
|
||
addEventListener: function(type, handler) {
|
||
if (type === 'finish') {
|
||
addEventHandler(this, type, handler);
|
||
}
|
||
},
|
||
removeEventListener: function(type, handler) {
|
||
if (type === 'finish') {
|
||
removeEventHandler(this, type, handler);
|
||
}
|
||
},
|
||
_generateEvents: function() {
|
||
if (!this._finishedFlag && this.finished &&
|
||
hasEventHandlersForEvent(this, 'finish')) {
|
||
var event = new AnimationPlayerEvent('finish', {
|
||
currentTime: this.currentTime,
|
||
timelineTime: this.timeline.currentTime
|
||
});
|
||
event._initialize(this);
|
||
callEventHandlers(this, 'finish', event);
|
||
}
|
||
this._finishedFlag = this.finished;
|
||
|
||
// The following code is for deprecated TimedItem event handling and should
|
||
// be removed once we stop supporting it.
|
||
if (!isDefinedAndNotNull(this._lastCurrentTime)) {
|
||
this._lastCurrentTime = 0;
|
||
}
|
||
|
||
this._lastCurrentTime = this._unlimitedCurrentTime;
|
||
},
|
||
_registerOnTimeline: function() {
|
||
if (!this._registeredOnTimeline) {
|
||
PLAYERS.push(this);
|
||
this._registeredOnTimeline = true;
|
||
}
|
||
},
|
||
_deregisterFromTimeline: function() {
|
||
PLAYERS.splice(PLAYERS.indexOf(this), 1);
|
||
this._registeredOnTimeline = false;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AnimationPlayerEvent = function(type, eventInit) {
|
||
this._type = type;
|
||
this.currentTime = eventInit.currentTime;
|
||
this.timelineTime = eventInit.timelineTime;
|
||
};
|
||
|
||
AnimationPlayerEvent.prototype = createEventPrototype();
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var TimedItem = function(token, timingInput) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
this.timing = new Timing(
|
||
constructorToken, timingInput,
|
||
this._specifiedTimingModified.bind(this));
|
||
this._inheritedTime = null;
|
||
this.currentIteration = null;
|
||
this._iterationTime = null;
|
||
this._animationTime = null;
|
||
this._startTime = 0.0;
|
||
this._player = null;
|
||
this._parent = null;
|
||
this._updateInternalState();
|
||
this._fill = this._resolveFillMode(this.timing.fill);
|
||
initializeEventTarget(this);
|
||
};
|
||
|
||
TimedItem.prototype = {
|
||
// TODO: It would be good to avoid the need for this. We would need to modify
|
||
// call sites to instead rely on a call from the parent.
|
||
get _effectiveParentTime() {
|
||
return this.parent !== null && this.parent._iterationTime !== null ?
|
||
this.parent._iterationTime : 0;
|
||
},
|
||
get localTime() {
|
||
return this._inheritedTime === null ?
|
||
null : this._inheritedTime - this._startTime;
|
||
},
|
||
get startTime() {
|
||
return this._startTime;
|
||
},
|
||
get duration() {
|
||
var result = this.timing._duration();
|
||
if (result === 'auto') {
|
||
result = this._intrinsicDuration();
|
||
}
|
||
return result;
|
||
},
|
||
get activeDuration() {
|
||
var repeatedDuration = this.duration * this.timing._iterations();
|
||
return repeatedDuration / Math.abs(this.timing.playbackRate);
|
||
},
|
||
get endTime() {
|
||
return this._startTime + this.activeDuration + this.timing.delay +
|
||
this.timing.endDelay;
|
||
},
|
||
get parent() {
|
||
return this._parent;
|
||
},
|
||
get previousSibling() {
|
||
if (!this.parent) {
|
||
return null;
|
||
}
|
||
var siblingIndex = this.parent.indexOf(this) - 1;
|
||
if (siblingIndex < 0) {
|
||
return null;
|
||
}
|
||
return this.parent.children[siblingIndex];
|
||
},
|
||
get nextSibling() {
|
||
if (!this.parent) {
|
||
return null;
|
||
}
|
||
var siblingIndex = this.parent.indexOf(this) + 1;
|
||
if (siblingIndex >= this.parent.children.length) {
|
||
return null;
|
||
}
|
||
return this.parent.children[siblingIndex];
|
||
},
|
||
_attach: function(player) {
|
||
// Remove ourselves from our parent, if we have one. This also removes any
|
||
// exsisting player.
|
||
this._reparent(null);
|
||
this._player = player;
|
||
},
|
||
// Takes care of updating the outgoing parent. This is called with a non-null
|
||
// parent only from TimingGroup.splice(), which takes care of calling
|
||
// TimingGroup._childrenStateModified() for the new parent.
|
||
_reparent: function(parent) {
|
||
if (parent === this) {
|
||
throw new Error('parent can not be set to self!');
|
||
}
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
if (this._player !== null) {
|
||
this._player.source = null;
|
||
this._player = null;
|
||
}
|
||
if (this.parent !== null) {
|
||
this.remove();
|
||
}
|
||
this._parent = parent;
|
||
// In the case of a AnimationSequence parent, _startTime will be updated
|
||
// by TimingGroup.splice().
|
||
if (this.parent === null || this.parent.type !== 'seq') {
|
||
this._startTime =
|
||
this._stashedStartTime === undefined ? 0.0 : this._stashedStartTime;
|
||
this._stashedStartTime = undefined;
|
||
}
|
||
// In the case of the parent being non-null, _childrenStateModified() will
|
||
// call this via _updateChildInheritedTimes().
|
||
// TODO: Consider optimising this case by skipping this call.
|
||
this._updateTimeMarkers();
|
||
} finally {
|
||
exitModifyCurrentAnimationState(
|
||
Boolean(this.player) ? repeatLastTick : null);
|
||
}
|
||
},
|
||
_intrinsicDuration: function() {
|
||
return 0.0;
|
||
},
|
||
_resolveFillMode: abstractMethod,
|
||
_updateInternalState: function() {
|
||
this._fill = this._resolveFillMode(this.timing.fill);
|
||
if (this.parent) {
|
||
this.parent._childrenStateModified();
|
||
} else if (this._player) {
|
||
this._player._registerOnTimeline();
|
||
}
|
||
this._updateTimeMarkers();
|
||
},
|
||
_specifiedTimingModified: function() {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
this._updateInternalState();
|
||
} finally {
|
||
exitModifyCurrentAnimationState(
|
||
Boolean(this.player) ? repeatLastTick : null);
|
||
}
|
||
},
|
||
// We push time down to children. We could instead have children pull from
|
||
// above, but this is tricky because a TimedItem may use either a parent
|
||
// TimedItem or an AnimationPlayer. This requires either logic in
|
||
// TimedItem, or for TimedItem and AnimationPlayer to implement Timeline
|
||
// (or an equivalent), both of which are ugly.
|
||
_updateInheritedTime: function(inheritedTime) {
|
||
this._inheritedTime = inheritedTime;
|
||
this._updateTimeMarkers();
|
||
},
|
||
_updateAnimationTime: function() {
|
||
if (this.localTime < this.timing.delay) {
|
||
if (this._fill === 'backwards' ||
|
||
this._fill === 'both') {
|
||
this._animationTime = 0;
|
||
} else {
|
||
this._animationTime = null;
|
||
}
|
||
} else if (this.localTime <
|
||
this.timing.delay + this.activeDuration) {
|
||
this._animationTime = this.localTime - this.timing.delay;
|
||
} else {
|
||
if (this._fill === 'forwards' ||
|
||
this._fill === 'both') {
|
||
this._animationTime = this.activeDuration;
|
||
} else {
|
||
this._animationTime = null;
|
||
}
|
||
}
|
||
},
|
||
_updateIterationParamsZeroDuration: function() {
|
||
this._iterationTime = 0;
|
||
var isAtEndOfIterations = this.timing._iterations() !== 0 &&
|
||
this.localTime >= this.timing.delay;
|
||
this.currentIteration = (
|
||
isAtEndOfIterations ?
|
||
this._floorWithOpenClosedRange(
|
||
this.timing.iterationStart + this.timing._iterations(),
|
||
1.0) :
|
||
this._floorWithClosedOpenRange(this.timing.iterationStart, 1.0));
|
||
// Equivalent to unscaledIterationTime below.
|
||
var unscaledFraction = (
|
||
isAtEndOfIterations ?
|
||
this._modulusWithOpenClosedRange(
|
||
this.timing.iterationStart + this.timing._iterations(),
|
||
1.0) :
|
||
this._modulusWithClosedOpenRange(this.timing.iterationStart, 1.0));
|
||
var timingFunction = this.timing._timingFunction(this);
|
||
this._timeFraction = (
|
||
this._isCurrentDirectionForwards() ?
|
||
unscaledFraction :
|
||
1.0 - unscaledFraction);
|
||
ASSERT_ENABLED && assert(
|
||
this._timeFraction >= 0.0 && this._timeFraction <= 1.0,
|
||
'Time fraction should be in the range [0, 1]');
|
||
if (timingFunction) {
|
||
this._timeFraction = timingFunction.scaleTime(this._timeFraction);
|
||
}
|
||
},
|
||
_getAdjustedAnimationTime: function(animationTime) {
|
||
var startOffset =
|
||
multiplyZeroGivesZero(this.timing.iterationStart, this.duration);
|
||
return (this.timing.playbackRate < 0 ?
|
||
(animationTime - this.activeDuration) : animationTime) *
|
||
this.timing.playbackRate + startOffset;
|
||
},
|
||
_scaleIterationTime: function(unscaledIterationTime) {
|
||
return this._isCurrentDirectionForwards() ?
|
||
unscaledIterationTime :
|
||
this.duration - unscaledIterationTime;
|
||
},
|
||
_updateIterationParams: function() {
|
||
var adjustedAnimationTime =
|
||
this._getAdjustedAnimationTime(this._animationTime);
|
||
var repeatedDuration = this.duration * this.timing._iterations();
|
||
var startOffset = this.timing.iterationStart * this.duration;
|
||
var isAtEndOfIterations = (this.timing._iterations() !== 0) &&
|
||
(adjustedAnimationTime - startOffset === repeatedDuration);
|
||
this.currentIteration = isAtEndOfIterations ?
|
||
this._floorWithOpenClosedRange(
|
||
adjustedAnimationTime, this.duration) :
|
||
this._floorWithClosedOpenRange(
|
||
adjustedAnimationTime, this.duration);
|
||
var unscaledIterationTime = isAtEndOfIterations ?
|
||
this._modulusWithOpenClosedRange(
|
||
adjustedAnimationTime, this.duration) :
|
||
this._modulusWithClosedOpenRange(
|
||
adjustedAnimationTime, this.duration);
|
||
this._iterationTime = this._scaleIterationTime(unscaledIterationTime);
|
||
if (this.duration == Infinity) {
|
||
this._timeFraction = 0;
|
||
return;
|
||
}
|
||
this._timeFraction = this._iterationTime / this.duration;
|
||
ASSERT_ENABLED && assert(
|
||
this._timeFraction >= 0.0 && this._timeFraction <= 1.0,
|
||
'Time fraction should be in the range [0, 1], got ' +
|
||
this._timeFraction + ' ' + this._iterationTime + ' ' +
|
||
this.duration + ' ' + isAtEndOfIterations + ' ' +
|
||
unscaledIterationTime);
|
||
var timingFunction = this.timing._timingFunction(this);
|
||
if (timingFunction) {
|
||
this._timeFraction = timingFunction.scaleTime(this._timeFraction);
|
||
}
|
||
this._iterationTime = this._timeFraction * this.duration;
|
||
},
|
||
_updateTimeMarkers: function() {
|
||
if (this.localTime === null) {
|
||
this._animationTime = null;
|
||
this._iterationTime = null;
|
||
this.currentIteration = null;
|
||
this._timeFraction = null;
|
||
return false;
|
||
}
|
||
this._updateAnimationTime();
|
||
if (this._animationTime === null) {
|
||
this._iterationTime = null;
|
||
this.currentIteration = null;
|
||
this._timeFraction = null;
|
||
} else if (this.duration === 0) {
|
||
this._updateIterationParamsZeroDuration();
|
||
} else {
|
||
this._updateIterationParams();
|
||
}
|
||
maybeRestartAnimation();
|
||
},
|
||
_floorWithClosedOpenRange: function(x, range) {
|
||
return Math.floor(x / range);
|
||
},
|
||
_floorWithOpenClosedRange: function(x, range) {
|
||
return Math.ceil(x / range) - 1;
|
||
},
|
||
_modulusWithClosedOpenRange: function(x, range) {
|
||
ASSERT_ENABLED && assert(
|
||
range > 0, 'Range must be strictly positive');
|
||
var modulus = x % range;
|
||
var result = modulus < 0 ? modulus + range : modulus;
|
||
ASSERT_ENABLED && assert(
|
||
result >= 0.0 && result < range,
|
||
'Result should be in the range [0, range)');
|
||
return result;
|
||
},
|
||
_modulusWithOpenClosedRange: function(x, range) {
|
||
var modulus = this._modulusWithClosedOpenRange(x, range);
|
||
var result = modulus === 0 ? range : modulus;
|
||
ASSERT_ENABLED && assert(
|
||
result > 0.0 && result <= range,
|
||
'Result should be in the range (0, range]');
|
||
return result;
|
||
},
|
||
_isCurrentDirectionForwards: function() {
|
||
if (this.timing.direction === 'normal') {
|
||
return true;
|
||
}
|
||
if (this.timing.direction === 'reverse') {
|
||
return false;
|
||
}
|
||
var d = this.currentIteration;
|
||
if (this.timing.direction === 'alternate-reverse') {
|
||
d += 1;
|
||
}
|
||
// TODO: 6.13.3 step 3. wtf?
|
||
return d % 2 === 0;
|
||
},
|
||
clone: abstractMethod,
|
||
before: function() {
|
||
var newItems = [];
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
newItems.push(arguments[i]);
|
||
}
|
||
this.parent._splice(this.parent.indexOf(this), 0, newItems);
|
||
},
|
||
after: function() {
|
||
var newItems = [];
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
newItems.push(arguments[i]);
|
||
}
|
||
this.parent._splice(this.parent.indexOf(this) + 1, 0, newItems);
|
||
},
|
||
replace: function() {
|
||
var newItems = [];
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
newItems.push(arguments[i]);
|
||
}
|
||
this.parent._splice(this.parent.indexOf(this), 1, newItems);
|
||
},
|
||
remove: function() {
|
||
this.parent._splice(this.parent.indexOf(this), 1);
|
||
},
|
||
// Gets the leaf TimedItems currently in effect. Note that this is a superset
|
||
// of the leaf TimedItems in their active interval, as a TimedItem can have an
|
||
// effect outside its active interval due to fill.
|
||
_getLeafItemsInEffect: function(items) {
|
||
if (this._timeFraction !== null) {
|
||
this._getLeafItemsInEffectImpl(items);
|
||
}
|
||
},
|
||
_getLeafItemsInEffectImpl: abstractMethod,
|
||
_hasFutureAnimation: function(timeDirectionForwards) {
|
||
return timeDirectionForwards ? this._inheritedTime < this.endTime :
|
||
this._inheritedTime > this.startTime;
|
||
},
|
||
_isPastEndOfActiveInterval: function() {
|
||
return this._inheritedTime >= this.endTime;
|
||
},
|
||
get player() {
|
||
return this.parent === null ?
|
||
this._player : this.parent.player;
|
||
},
|
||
_isCurrent: function() {
|
||
return !this._isPastEndOfActiveInterval() ||
|
||
(this.parent !== null && this.parent._isCurrent());
|
||
},
|
||
_isTargetingElement: abstractMethod,
|
||
_getAnimationsTargetingElement: abstractMethod,
|
||
_netEffectivePlaybackRate: function() {
|
||
var effectivePlaybackRate = this._isCurrentDirectionForwards() ?
|
||
this.timing.playbackRate : -this.timing.playbackRate;
|
||
return this.parent === null ? effectivePlaybackRate :
|
||
effectivePlaybackRate * this.parent._netEffectivePlaybackRate();
|
||
},
|
||
// Note that this restriction is currently incomplete - for example,
|
||
// Animations which are playing forwards and have a fill of backwards
|
||
// are not in effect unless current.
|
||
// TODO: Complete this restriction.
|
||
_hasFutureEffect: function() {
|
||
return this._isCurrent() || this._fill !== 'none';
|
||
},
|
||
_toSubRanges: function(fromTime, toTime, iterationTimes) {
|
||
if (fromTime > toTime) {
|
||
var revRanges = this._toSubRanges(toTime, fromTime, iterationTimes);
|
||
revRanges.ranges.forEach(function(a) { a.reverse(); });
|
||
revRanges.ranges.reverse();
|
||
revRanges.start = iterationTimes.length - revRanges.start - 1;
|
||
revRanges.delta = -1;
|
||
return revRanges;
|
||
}
|
||
var skipped = 0;
|
||
// TODO: this should be calculatable. This would be more efficient
|
||
// than searching through the list.
|
||
while (iterationTimes[skipped] < fromTime) {
|
||
skipped++;
|
||
}
|
||
var currentStart = fromTime;
|
||
var ranges = [];
|
||
for (var i = skipped; i < iterationTimes.length; i++) {
|
||
if (iterationTimes[i] < toTime) {
|
||
ranges.push([currentStart, iterationTimes[i]]);
|
||
currentStart = iterationTimes[i];
|
||
} else {
|
||
ranges.push([currentStart, toTime]);
|
||
return {start: skipped, delta: 1, ranges: ranges};
|
||
}
|
||
}
|
||
ranges.push([currentStart, toTime]);
|
||
return {start: skipped, delta: 1, ranges: ranges};
|
||
}
|
||
};
|
||
|
||
var TimingEvent = function(
|
||
token, target, type, localTime, timelineTime, iterationIndex, seeked) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
this._initialize(target);
|
||
this._type = type;
|
||
this.localTime = localTime;
|
||
this.timelineTime = timelineTime;
|
||
this.iterationIndex = iterationIndex;
|
||
this.seeked = seeked ? true : false;
|
||
};
|
||
|
||
TimingEvent.prototype = createEventPrototype();
|
||
|
||
var isEffectCallback = function(animationEffect) {
|
||
return typeof animationEffect === 'function';
|
||
};
|
||
|
||
var interpretAnimationEffect = function(animationEffect) {
|
||
if (animationEffect instanceof AnimationEffect ||
|
||
isEffectCallback(animationEffect)) {
|
||
return animationEffect;
|
||
} else if (isDefinedAndNotNull(animationEffect) &&
|
||
typeof animationEffect === 'object') {
|
||
// The spec requires animationEffect to be an instance of
|
||
// OneOrMoreKeyframes, but this type is just a dictionary or a list of
|
||
// dictionaries, so the best we can do is test for an object.
|
||
return new KeyframeEffect(animationEffect);
|
||
}
|
||
return null;
|
||
};
|
||
|
||
var cloneAnimationEffect = function(animationEffect) {
|
||
if (animationEffect instanceof AnimationEffect) {
|
||
return animationEffect.clone();
|
||
} else if (isEffectCallback(animationEffect)) {
|
||
return animationEffect;
|
||
} else {
|
||
return null;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var Animation = function(target, animationEffect, timingInput) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
TimedItem.call(this, constructorToken, timingInput);
|
||
this.effect = interpretAnimationEffect(animationEffect);
|
||
this._target = target;
|
||
} finally {
|
||
exitModifyCurrentAnimationState(null);
|
||
}
|
||
};
|
||
|
||
Animation.prototype = createObject(TimedItem.prototype, {
|
||
_resolveFillMode: function(fillMode) {
|
||
return fillMode === 'auto' ? 'none' : fillMode;
|
||
},
|
||
_sample: function() {
|
||
if (isDefinedAndNotNull(this.effect) &&
|
||
!(this.target instanceof PseudoElementReference)) {
|
||
if (isEffectCallback(this.effect)) {
|
||
this.effect(this._timeFraction, this.target, this);
|
||
} else {
|
||
this.effect._sample(this._timeFraction, this.currentIteration,
|
||
this.target, this.underlyingValue);
|
||
}
|
||
}
|
||
},
|
||
_getLeafItemsInEffectImpl: function(items) {
|
||
items.push(this);
|
||
},
|
||
_isTargetingElement: function(element) {
|
||
return element === this.target;
|
||
},
|
||
_getAnimationsTargetingElement: function(element, animations) {
|
||
if (this._isTargetingElement(element)) {
|
||
animations.push(this);
|
||
}
|
||
},
|
||
get target() {
|
||
return this._target;
|
||
},
|
||
set effect(effect) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
this._effect = effect;
|
||
this.timing._invalidateTimingFunction();
|
||
} finally {
|
||
exitModifyCurrentAnimationState(
|
||
Boolean(this.player) ? repeatLastTick : null);
|
||
}
|
||
},
|
||
get effect() {
|
||
return this._effect;
|
||
},
|
||
clone: function() {
|
||
return new Animation(this.target,
|
||
cloneAnimationEffect(this.effect), this.timing._dict);
|
||
},
|
||
toString: function() {
|
||
var effectString = '<none>';
|
||
if (this.effect instanceof AnimationEffect) {
|
||
effectString = this.effect.toString();
|
||
} else if (isEffectCallback(this.effect)) {
|
||
effectString = 'Effect callback';
|
||
}
|
||
return 'Animation ' + this.startTime + '-' + this.endTime + ' (' +
|
||
this.localTime + ') ' + effectString;
|
||
}
|
||
});
|
||
|
||
function throwNewHierarchyRequestError() {
|
||
var element = document.createElement('span');
|
||
element.appendChild(element);
|
||
}
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var TimedItemList = function(token, children) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
this._children = children;
|
||
this._getters = 0;
|
||
this._ensureGetters();
|
||
};
|
||
|
||
TimedItemList.prototype = {
|
||
get length() {
|
||
return this._children.length;
|
||
},
|
||
_ensureGetters: function() {
|
||
while (this._getters < this._children.length) {
|
||
this._ensureGetter(this._getters++);
|
||
}
|
||
},
|
||
_ensureGetter: function(i) {
|
||
Object.defineProperty(this, i, {
|
||
get: function() {
|
||
return this._children[i];
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var TimingGroup = function(token, type, children, timing) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
// Take a copy of the children array, as it could be modified as a side-effect
|
||
// of creating this object. See
|
||
// https://github.com/web-animations/web-animations-js/issues/65 for details.
|
||
var childrenCopy = (children && Array.isArray(children)) ?
|
||
children.slice() : [];
|
||
// used by TimedItem via _intrinsicDuration(), so needs to be set before
|
||
// initializing super.
|
||
this.type = type || 'par';
|
||
this._children = [];
|
||
this._cachedTimedItemList = null;
|
||
this._cachedIntrinsicDuration = null;
|
||
TimedItem.call(this, constructorToken, timing);
|
||
// We add children after setting the parent. This means that if an ancestor
|
||
// (including the parent) is specified as a child, it will be removed from our
|
||
// ancestors and used as a child,
|
||
this.append.apply(this, childrenCopy);
|
||
};
|
||
|
||
TimingGroup.prototype = createObject(TimedItem.prototype, {
|
||
_resolveFillMode: function(fillMode) {
|
||
return fillMode === 'auto' ? 'both' : fillMode;
|
||
},
|
||
_childrenStateModified: function() {
|
||
// See _updateChildStartTimes().
|
||
this._isInChildrenStateModified = true;
|
||
if (this._cachedTimedItemList) {
|
||
this._cachedTimedItemList._ensureGetters();
|
||
}
|
||
this._cachedIntrinsicDuration = null;
|
||
|
||
// We need to walk up and down the tree to re-layout. endTime and the
|
||
// various durations (which are all calculated lazily) are the only
|
||
// properties of a TimedItem which can affect the layout of its ancestors.
|
||
// So it should be sufficient to simply update start times and time markers
|
||
// on the way down.
|
||
|
||
// This calls up to our parent, then calls _updateTimeMarkers().
|
||
this._updateInternalState();
|
||
this._updateChildInheritedTimes();
|
||
|
||
// Update child start times before walking down.
|
||
this._updateChildStartTimes();
|
||
|
||
this._isInChildrenStateModified = false;
|
||
},
|
||
_updateInheritedTime: function(inheritedTime) {
|
||
this._inheritedTime = inheritedTime;
|
||
this._updateTimeMarkers();
|
||
this._updateChildInheritedTimes();
|
||
},
|
||
_updateChildInheritedTimes: function() {
|
||
for (var i = 0; i < this._children.length; i++) {
|
||
var child = this._children[i];
|
||
child._updateInheritedTime(this._iterationTime);
|
||
}
|
||
},
|
||
_updateChildStartTimes: function() {
|
||
if (this.type === 'seq') {
|
||
var cumulativeStartTime = 0;
|
||
for (var i = 0; i < this._children.length; i++) {
|
||
var child = this._children[i];
|
||
if (child._stashedStartTime === undefined) {
|
||
child._stashedStartTime = child._startTime;
|
||
}
|
||
child._startTime = cumulativeStartTime;
|
||
// Avoid updating the child's inherited time and time markers if this is
|
||
// about to be done in the down phase of _childrenStateModified().
|
||
if (!child._isInChildrenStateModified) {
|
||
// This calls _updateTimeMarkers() on the child.
|
||
child._updateInheritedTime(this._iterationTime);
|
||
}
|
||
cumulativeStartTime += Math.max(0, child.timing.delay +
|
||
child.activeDuration + child.timing.endDelay);
|
||
}
|
||
}
|
||
},
|
||
get children() {
|
||
if (!this._cachedTimedItemList) {
|
||
this._cachedTimedItemList = new TimedItemList(
|
||
constructorToken, this._children);
|
||
}
|
||
return this._cachedTimedItemList;
|
||
},
|
||
get firstChild() {
|
||
return this._children[0];
|
||
},
|
||
get lastChild() {
|
||
return this._children[this.children.length - 1];
|
||
},
|
||
_intrinsicDuration: function() {
|
||
if (!isDefinedAndNotNull(this._cachedIntrinsicDuration)) {
|
||
if (this.type === 'par') {
|
||
var dur = Math.max.apply(undefined, this._children.map(function(a) {
|
||
return a.endTime;
|
||
}));
|
||
this._cachedIntrinsicDuration = Math.max(0, dur);
|
||
} else if (this.type === 'seq') {
|
||
var result = 0;
|
||
this._children.forEach(function(a) {
|
||
result += a.activeDuration + a.timing.delay + a.timing.endDelay;
|
||
});
|
||
this._cachedIntrinsicDuration = result;
|
||
} else {
|
||
throw 'Unsupported type ' + this.type;
|
||
}
|
||
}
|
||
return this._cachedIntrinsicDuration;
|
||
},
|
||
_getLeafItemsInEffectImpl: function(items) {
|
||
for (var i = 0; i < this._children.length; i++) {
|
||
this._children[i]._getLeafItemsInEffect(items);
|
||
}
|
||
},
|
||
clone: function() {
|
||
var children = [];
|
||
this._children.forEach(function(child) {
|
||
children.push(child.clone());
|
||
});
|
||
return this.type === 'par' ?
|
||
new AnimationGroup(children, this.timing._dict) :
|
||
new AnimationSequence(children, this.timing._dict);
|
||
},
|
||
clear: function() {
|
||
this._splice(0, this._children.length);
|
||
},
|
||
append: function() {
|
||
var newItems = [];
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
newItems.push(arguments[i]);
|
||
}
|
||
this._splice(this._children.length, 0, newItems);
|
||
},
|
||
prepend: function() {
|
||
var newItems = [];
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
newItems.push(arguments[i]);
|
||
}
|
||
this._splice(0, 0, newItems);
|
||
},
|
||
_addInternal: function(child) {
|
||
this._children.push(child);
|
||
this._childrenStateModified();
|
||
},
|
||
indexOf: function(item) {
|
||
return this._children.indexOf(item);
|
||
},
|
||
_splice: function(start, deleteCount, newItems) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
var args = arguments;
|
||
if (args.length === 3) {
|
||
args = [start, deleteCount].concat(newItems);
|
||
}
|
||
for (var i = 2; i < args.length; i++) {
|
||
var newChild = args[i];
|
||
if (this._isInclusiveAncestor(newChild)) {
|
||
throwNewHierarchyRequestError();
|
||
}
|
||
newChild._reparent(this);
|
||
}
|
||
var result = Array.prototype.splice.apply(this._children, args);
|
||
for (var i = 0; i < result.length; i++) {
|
||
result[i]._parent = null;
|
||
}
|
||
this._childrenStateModified();
|
||
return result;
|
||
} finally {
|
||
exitModifyCurrentAnimationState(
|
||
Boolean(this.player) ? repeatLastTick : null);
|
||
}
|
||
},
|
||
_isInclusiveAncestor: function(item) {
|
||
for (var ancestor = this; ancestor !== null; ancestor = ancestor.parent) {
|
||
if (ancestor === item) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
},
|
||
_isTargetingElement: function(element) {
|
||
return this._children.some(function(child) {
|
||
return child._isTargetingElement(element);
|
||
});
|
||
},
|
||
_getAnimationsTargetingElement: function(element, animations) {
|
||
this._children.map(function(child) {
|
||
return child._getAnimationsTargetingElement(element, animations);
|
||
});
|
||
},
|
||
toString: function() {
|
||
return this.type + ' ' + this.startTime + '-' + this.endTime + ' (' +
|
||
this.localTime + ') ' + ' [' +
|
||
this._children.map(function(a) { return a.toString(); }) + ']';
|
||
}
|
||
});
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AnimationGroup = function(children, timing, parent) {
|
||
TimingGroup.call(this, constructorToken, 'par', children, timing, parent);
|
||
};
|
||
|
||
AnimationGroup.prototype = Object.create(TimingGroup.prototype);
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AnimationSequence = function(children, timing, parent) {
|
||
TimingGroup.call(this, constructorToken, 'seq', children, timing, parent);
|
||
};
|
||
|
||
AnimationSequence.prototype = Object.create(TimingGroup.prototype);
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var PseudoElementReference = function(element, pseudoElement) {
|
||
this.element = element;
|
||
this.pseudoElement = pseudoElement;
|
||
console.warn('PseudoElementReference is not supported.');
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var MediaReference = function(mediaElement, timing, parent, delta) {
|
||
TimedItem.call(this, constructorToken, timing, parent);
|
||
this._media = mediaElement;
|
||
|
||
// We can never be sure when _updateInheritedTime() is going to be called
|
||
// next, due to skipped frames or the player being seeked. Plus the media
|
||
// element's currentTime may drift from our iterationTime. So if a media
|
||
// element has loop set, we can't be sure that we'll stop it before it wraps.
|
||
// For this reason, we simply disable looping.
|
||
// TODO: Maybe we should let it loop if our duration exceeds it's
|
||
// length?
|
||
this._media.loop = false;
|
||
|
||
// If the media element has a media controller, we detach it. This mirrors the
|
||
// behaviour when re-parenting a TimedItem, or attaching one to an
|
||
// AnimationPlayer.
|
||
// TODO: It would be neater to assign to MediaElement.controller, but this was
|
||
// broken in Chrome until recently. See crbug.com/226270.
|
||
this._media.mediaGroup = '';
|
||
|
||
this._delta = delta;
|
||
};
|
||
|
||
MediaReference.prototype = createObject(TimedItem.prototype, {
|
||
_resolveFillMode: function(fillMode) {
|
||
// TODO: Fill modes for MediaReferences are still undecided. The spec is not
|
||
// clear what 'auto' should mean for TimedItems other than Animations and
|
||
// groups.
|
||
return fillMode === 'auto' ? 'none' : fillMode;
|
||
},
|
||
_intrinsicDuration: function() {
|
||
// TODO: This should probably default to zero. But doing so means that as
|
||
// soon as our inheritedTime is zero, the polyfill deems the animation to be
|
||
// done and stops ticking, so we don't get any further calls to
|
||
// _updateInheritedTime(). One way around this would be to modify
|
||
// TimedItem._isPastEndOfActiveInterval() to recurse down the tree, then we
|
||
// could override it here.
|
||
return isNaN(this._media.duration) ?
|
||
Infinity : this._media.duration / this._media.defaultPlaybackRate;
|
||
},
|
||
_unscaledMediaCurrentTime: function() {
|
||
return this._media.currentTime / this._media.defaultPlaybackRate;
|
||
},
|
||
_getLeafItemsInEffectImpl: function(items) {
|
||
items.push(this);
|
||
},
|
||
_ensurePlaying: function() {
|
||
// The media element is paused when created.
|
||
if (this._media.paused) {
|
||
this._media.play();
|
||
}
|
||
},
|
||
_ensurePaused: function() {
|
||
if (!this._media.paused) {
|
||
this._media.pause();
|
||
}
|
||
},
|
||
_isSeekableUnscaledTime: function(time) {
|
||
var seekTime = time * this._media.defaultPlaybackRate;
|
||
var ranges = this._media.seekable;
|
||
for (var i = 0; i < ranges.length; i++) {
|
||
if (seekTime >= ranges.start(i) && seekTime <= ranges.end(i)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
},
|
||
// Note that a media element's timeline may not start at zero, although its
|
||
// duration is always the timeline time at the end point. This means that an
|
||
// element's duration isn't always it's length and not all values of the
|
||
// timline are seekable. Furthermore, some types of media further limit the
|
||
// range of seekable timeline times. For this reason, we always map an
|
||
// iteration to the range [0, duration] and simply seek to the nearest
|
||
// seekable time.
|
||
_ensureIsAtUnscaledTime: function(time) {
|
||
if (this._unscaledMediaCurrentTime() !== time) {
|
||
this._media.currentTime = time * this._media.defaultPlaybackRate;
|
||
}
|
||
},
|
||
// This is called by the polyfill on each tick when our AnimationPlayer's tree
|
||
// is active.
|
||
_updateInheritedTime: function(inheritedTime) {
|
||
this._inheritedTime = inheritedTime;
|
||
this._updateTimeMarkers();
|
||
|
||
// The polyfill uses a sampling model whereby time values are propagated
|
||
// down the tree at each sample. However, for the media item, we need to use
|
||
// play() and pause().
|
||
|
||
// Handle the case of being outside our effect interval.
|
||
if (this._iterationTime === null) {
|
||
this._ensureIsAtUnscaledTime(0);
|
||
this._ensurePaused();
|
||
return;
|
||
}
|
||
|
||
if (this._iterationTime >= this._intrinsicDuration()) {
|
||
// Our iteration time exceeds the media element's duration, so just make
|
||
// sure the media element is at the end. It will stop automatically, but
|
||
// that could take some time if the seek below is significant, so force
|
||
// it.
|
||
this._ensureIsAtUnscaledTime(this._intrinsicDuration());
|
||
this._ensurePaused();
|
||
return;
|
||
}
|
||
|
||
var finalIteration = this._floorWithOpenClosedRange(
|
||
this.timing.iterationStart + this.timing._iterations(), 1.0);
|
||
var endTimeFraction = this._modulusWithOpenClosedRange(
|
||
this.timing.iterationStart + this.timing._iterations(), 1.0);
|
||
if (this.currentIteration === finalIteration &&
|
||
this._timeFraction === endTimeFraction &&
|
||
this._intrinsicDuration() >= this.duration) {
|
||
// We have reached the end of our final iteration, but the media element
|
||
// is not done.
|
||
this._ensureIsAtUnscaledTime(this.duration * endTimeFraction);
|
||
this._ensurePaused();
|
||
return;
|
||
}
|
||
|
||
// Set the appropriate playback rate.
|
||
var playbackRate =
|
||
this._media.defaultPlaybackRate * this._netEffectivePlaybackRate();
|
||
if (this._media.playbackRate !== playbackRate) {
|
||
this._media.playbackRate = playbackRate;
|
||
}
|
||
|
||
// Set the appropriate play/pause state. Note that we may not be able to
|
||
// seek to the desired time. In this case, the media element's seek
|
||
// algorithm repositions the seek to the nearest seekable time. This is OK,
|
||
// but in this case, we don't want to play the media element, as it prevents
|
||
// us from synchronising properly.
|
||
if (this.player.paused ||
|
||
!this._isSeekableUnscaledTime(this._iterationTime)) {
|
||
this._ensurePaused();
|
||
} else {
|
||
this._ensurePlaying();
|
||
}
|
||
|
||
// Seek if required. This could be due to our AnimationPlayer being seeked,
|
||
// or video slippage. We need to handle the fact that the video may not play
|
||
// at exactly the right speed. There's also a variable delay when the video
|
||
// is first played.
|
||
// TODO: What's the right value for this delta?
|
||
var delta = isDefinedAndNotNull(this._delta) ? this._delta :
|
||
0.2 * Math.abs(this._media.playbackRate);
|
||
if (Math.abs(this._iterationTime - this._unscaledMediaCurrentTime()) >
|
||
delta) {
|
||
this._ensureIsAtUnscaledTime(this._iterationTime);
|
||
}
|
||
},
|
||
_isTargetingElement: function(element) {
|
||
return this._media === element;
|
||
},
|
||
_getAnimationsTargetingElement: function() { },
|
||
_attach: function(player) {
|
||
this._ensurePaused();
|
||
TimedItem.prototype._attach.call(this, player);
|
||
}
|
||
});
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AnimationEffect = function(token) {
|
||
if (token !== constructorToken) {
|
||
throw new TypeError('Illegal constructor');
|
||
}
|
||
};
|
||
|
||
AnimationEffect.prototype = {
|
||
_sample: abstractMethod,
|
||
clone: abstractMethod,
|
||
toString: abstractMethod
|
||
};
|
||
|
||
var clamp = function(x, min, max) {
|
||
return Math.max(Math.min(x, max), min);
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var MotionPathEffect = function(path, autoRotate, angle, composite) {
|
||
var iterationComposite = undefined;
|
||
var options = autoRotate;
|
||
if (typeof options == 'string' || options instanceof String ||
|
||
angle || composite) {
|
||
// FIXME: add deprecation warning - please pass an options dictionary to
|
||
// MotionPathEffect constructor
|
||
} else if (options) {
|
||
autoRotate = options.autoRotate;
|
||
angle = options.angle;
|
||
composite = options.composite;
|
||
iterationComposite = options.iterationComposite;
|
||
}
|
||
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
AnimationEffect.call(this, constructorToken);
|
||
|
||
this.composite = composite;
|
||
this.iterationComposite = iterationComposite;
|
||
|
||
// TODO: path argument is not in the spec -- seems useful since
|
||
// SVGPathSegList doesn't have a constructor.
|
||
this.autoRotate = isDefined(autoRotate) ? autoRotate : 'none';
|
||
this.angle = isDefined(angle) ? angle : 0;
|
||
this._path = document.createElementNS(SVG_NS, 'path');
|
||
if (path instanceof SVGPathSegList) {
|
||
this.segments = path;
|
||
} else {
|
||
var tempPath = document.createElementNS(SVG_NS, 'path');
|
||
tempPath.setAttribute('d', String(path));
|
||
this.segments = tempPath.pathSegList;
|
||
}
|
||
} finally {
|
||
exitModifyCurrentAnimationState(null);
|
||
}
|
||
};
|
||
|
||
MotionPathEffect.prototype = createObject(AnimationEffect.prototype, {
|
||
get composite() {
|
||
return this._composite;
|
||
},
|
||
set composite(value) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
// Use the default value if an invalid string is specified.
|
||
this._composite = value === 'add' ? 'add' : 'replace';
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get iterationComposite() {
|
||
return this._iterationComposite;
|
||
},
|
||
set iterationComposite(value) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
// Use the default value if an invalid string is specified.
|
||
this._iterationComposite =
|
||
value === 'accumulate' ? 'accumulate' : 'replace';
|
||
this._updateOffsetPerIteration();
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
_sample: function(timeFraction, currentIteration, target) {
|
||
// TODO: Handle accumulation.
|
||
var lengthAtTimeFraction = this._lengthAtTimeFraction(timeFraction);
|
||
var point = this._path.getPointAtLength(lengthAtTimeFraction);
|
||
var x = point.x - target.offsetWidth / 2;
|
||
var y = point.y - target.offsetHeight / 2;
|
||
if (currentIteration !== 0 && this._offsetPerIteration) {
|
||
x += this._offsetPerIteration.x * currentIteration;
|
||
y += this._offsetPerIteration.y * currentIteration;
|
||
}
|
||
// TODO: calc(point.x - 50%) doesn't work?
|
||
var value = [{t: 'translate', d: [{px: x}, {px: y}]}];
|
||
var angle = this.angle;
|
||
if (this._autoRotate === 'auto-rotate') {
|
||
// Super hacks
|
||
var lastPoint = this._path.getPointAtLength(lengthAtTimeFraction - 0.01);
|
||
var dx = point.x - lastPoint.x;
|
||
var dy = point.y - lastPoint.y;
|
||
var rotation = Math.atan2(dy, dx);
|
||
angle += rotation / 2 / Math.PI * 360;
|
||
}
|
||
value.push({t: 'rotate', d: [angle]});
|
||
compositor.setAnimatedValue(target, 'transform',
|
||
new AddReplaceCompositableValue(value, this.composite));
|
||
},
|
||
_lengthAtTimeFraction: function(timeFraction) {
|
||
var segmentCount = this._cumulativeLengths.length - 1;
|
||
if (!segmentCount) {
|
||
return 0;
|
||
}
|
||
var scaledFraction = timeFraction * segmentCount;
|
||
var index = clamp(Math.floor(scaledFraction), 0, segmentCount);
|
||
return this._cumulativeLengths[index] + ((scaledFraction % 1) * (
|
||
this._cumulativeLengths[index + 1] - this._cumulativeLengths[index]));
|
||
},
|
||
_updateOffsetPerIteration: function() {
|
||
if (this.iterationComposite === 'accumulate' &&
|
||
this._cumulativeLengths &&
|
||
this._cumulativeLengths.length > 0) {
|
||
this._offsetPerIteration = this._path.getPointAtLength(
|
||
this._cumulativeLengths[this._cumulativeLengths.length - 1]);
|
||
} else {
|
||
this._offsetPerIteration = null;
|
||
}
|
||
},
|
||
clone: function() {
|
||
return new MotionPathEffect(this._path.getAttribute('d'));
|
||
},
|
||
toString: function() {
|
||
return '<MotionPathEffect>';
|
||
},
|
||
set autoRotate(autoRotate) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
this._autoRotate = String(autoRotate);
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get autoRotate() {
|
||
return this._autoRotate;
|
||
},
|
||
set angle(angle) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
// TODO: This should probably be a string with a unit, but the spec
|
||
// says it's a double.
|
||
this._angle = Number(angle);
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get angle() {
|
||
return this._angle;
|
||
},
|
||
set segments(segments) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
var targetSegments = this.segments;
|
||
targetSegments.clear();
|
||
var cumulativeLengths = [0];
|
||
// TODO: *moving* the path segments is not correct, but pathSegList
|
||
// is read only
|
||
var items = segments.numberOfItems;
|
||
while (targetSegments.numberOfItems < items) {
|
||
var segment = segments.removeItem(0);
|
||
targetSegments.appendItem(segment);
|
||
if (segment.pathSegType !== SVGPathSeg.PATHSEG_MOVETO_REL &&
|
||
segment.pathSegType !== SVGPathSeg.PATHSEG_MOVETO_ABS) {
|
||
cumulativeLengths.push(this._path.getTotalLength());
|
||
}
|
||
}
|
||
this._cumulativeLengths = cumulativeLengths;
|
||
this._updateOffsetPerIteration();
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
get segments() {
|
||
return this._path.pathSegList;
|
||
}
|
||
});
|
||
|
||
var shorthandToLonghand = {
|
||
background: [
|
||
'backgroundImage',
|
||
'backgroundPosition',
|
||
'backgroundSize',
|
||
'backgroundRepeat',
|
||
'backgroundAttachment',
|
||
'backgroundOrigin',
|
||
'backgroundClip',
|
||
'backgroundColor'
|
||
],
|
||
border: [
|
||
'borderTopColor',
|
||
'borderTopStyle',
|
||
'borderTopWidth',
|
||
'borderRightColor',
|
||
'borderRightStyle',
|
||
'borderRightWidth',
|
||
'borderBottomColor',
|
||
'borderBottomStyle',
|
||
'borderBottomWidth',
|
||
'borderLeftColor',
|
||
'borderLeftStyle',
|
||
'borderLeftWidth'
|
||
],
|
||
borderBottom: [
|
||
'borderBottomWidth',
|
||
'borderBottomStyle',
|
||
'borderBottomColor'
|
||
],
|
||
borderColor: [
|
||
'borderTopColor',
|
||
'borderRightColor',
|
||
'borderBottomColor',
|
||
'borderLeftColor'
|
||
],
|
||
borderLeft: [
|
||
'borderLeftWidth',
|
||
'borderLeftStyle',
|
||
'borderLeftColor'
|
||
],
|
||
borderRadius: [
|
||
'borderTopLeftRadius',
|
||
'borderTopRightRadius',
|
||
'borderBottomRightRadius',
|
||
'borderBottomLeftRadius'
|
||
],
|
||
borderRight: [
|
||
'borderRightWidth',
|
||
'borderRightStyle',
|
||
'borderRightColor'
|
||
],
|
||
borderTop: [
|
||
'borderTopWidth',
|
||
'borderTopStyle',
|
||
'borderTopColor'
|
||
],
|
||
borderWidth: [
|
||
'borderTopWidth',
|
||
'borderRightWidth',
|
||
'borderBottomWidth',
|
||
'borderLeftWidth'
|
||
],
|
||
font: [
|
||
'fontFamily',
|
||
'fontSize',
|
||
'fontStyle',
|
||
'fontVariant',
|
||
'fontWeight',
|
||
'lineHeight'
|
||
],
|
||
margin: [
|
||
'marginTop',
|
||
'marginRight',
|
||
'marginBottom',
|
||
'marginLeft'
|
||
],
|
||
outline: [
|
||
'outlineColor',
|
||
'outlineStyle',
|
||
'outlineWidth'
|
||
],
|
||
padding: [
|
||
'paddingTop',
|
||
'paddingRight',
|
||
'paddingBottom',
|
||
'paddingLeft'
|
||
]
|
||
};
|
||
|
||
// This delegates parsing shorthand value syntax to the browser.
|
||
var shorthandExpanderElem = createDummyElement();
|
||
var expandShorthand = function(property, value, result) {
|
||
shorthandExpanderElem.style[property] = value;
|
||
var longProperties = shorthandToLonghand[property];
|
||
for (var i in longProperties) {
|
||
var longProperty = longProperties[i];
|
||
var longhandValue = shorthandExpanderElem.style[longProperty];
|
||
result[longProperty] = longhandValue;
|
||
}
|
||
};
|
||
|
||
var normalizeKeyframeDictionary = function(properties) {
|
||
var result = {
|
||
offset: null,
|
||
composite: null,
|
||
easing: presetTimingFunctions.linear
|
||
};
|
||
var animationProperties = [];
|
||
for (var property in properties) {
|
||
// TODO: Apply the CSS property to IDL attribute algorithm.
|
||
if (property === 'offset') {
|
||
if (typeof properties.offset === 'number') {
|
||
result.offset = properties.offset;
|
||
}
|
||
} else if (property === 'composite') {
|
||
if (properties.composite === 'add' ||
|
||
properties.composite === 'replace') {
|
||
result.composite = properties.composite;
|
||
}
|
||
} else if (property === 'easing') {
|
||
result.easing = TimingFunction.createFromString(properties.easing);
|
||
} else {
|
||
// TODO: Check whether this is a supported property.
|
||
animationProperties.push(property);
|
||
}
|
||
}
|
||
// TODO: Remove prefixed properties if the unprefixed version is also
|
||
// supported and present.
|
||
animationProperties = animationProperties.sort(playerSortFunction);
|
||
for (var i = 0; i < animationProperties.length; i++) {
|
||
// TODO: Apply the IDL attribute to CSS property algorithm.
|
||
var property = animationProperties[i];
|
||
// TODO: The spec does not specify how to handle null values.
|
||
// See https://www.w3.org/Bugs/Public/show_bug.cgi?id=22572
|
||
var value = isDefinedAndNotNull(properties[property]) ?
|
||
properties[property].toString() : '';
|
||
if (property in shorthandToLonghand) {
|
||
expandShorthand(property, value, result);
|
||
} else {
|
||
result[property] = value;
|
||
}
|
||
}
|
||
return result;
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var KeyframeEffect = function(oneOrMoreKeyframeDictionaries,
|
||
composite) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
AnimationEffect.call(this, constructorToken);
|
||
|
||
this.composite = composite;
|
||
|
||
this.setFrames(oneOrMoreKeyframeDictionaries);
|
||
} finally {
|
||
exitModifyCurrentAnimationState(null);
|
||
}
|
||
};
|
||
|
||
KeyframeEffect.prototype = createObject(AnimationEffect.prototype, {
|
||
get composite() {
|
||
return this._composite;
|
||
},
|
||
set composite(value) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
// Use the default value if an invalid string is specified.
|
||
this._composite = value === 'add' ? 'add' : 'replace';
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
getFrames: function() {
|
||
return this._keyframeDictionaries.slice(0);
|
||
},
|
||
setFrames: function(oneOrMoreKeyframeDictionaries) {
|
||
enterModifyCurrentAnimationState();
|
||
try {
|
||
if (!Array.isArray(oneOrMoreKeyframeDictionaries)) {
|
||
oneOrMoreKeyframeDictionaries = [oneOrMoreKeyframeDictionaries];
|
||
}
|
||
this._keyframeDictionaries =
|
||
oneOrMoreKeyframeDictionaries.map(normalizeKeyframeDictionary);
|
||
// Set lazily
|
||
this._cachedPropertySpecificKeyframes = null;
|
||
} finally {
|
||
exitModifyCurrentAnimationState(repeatLastTick);
|
||
}
|
||
},
|
||
_sample: function(timeFraction, currentIteration, target) {
|
||
var frames = this._propertySpecificKeyframes();
|
||
for (var property in frames) {
|
||
compositor.setAnimatedValue(target, property,
|
||
this._sampleForProperty(
|
||
frames[property], timeFraction, currentIteration));
|
||
}
|
||
},
|
||
_sampleForProperty: function(frames, timeFraction, currentIteration) {
|
||
ASSERT_ENABLED && assert(
|
||
frames.length >= 2,
|
||
'Interpolation requires at least two keyframes');
|
||
|
||
var startKeyframeIndex;
|
||
var length = frames.length;
|
||
// We extrapolate differently depending on whether or not there are multiple
|
||
// keyframes at offsets of 0 and 1.
|
||
if (timeFraction < 0.0) {
|
||
if (frames[1].offset === 0.0) {
|
||
return new AddReplaceCompositableValue(frames[0].rawValue(),
|
||
this._compositeForKeyframe(frames[0]));
|
||
} else {
|
||
startKeyframeIndex = 0;
|
||
}
|
||
} else if (timeFraction >= 1.0) {
|
||
if (frames[length - 2].offset === 1.0) {
|
||
return new AddReplaceCompositableValue(frames[length - 1].rawValue(),
|
||
this._compositeForKeyframe(frames[length - 1]));
|
||
} else {
|
||
startKeyframeIndex = length - 2;
|
||
}
|
||
} else {
|
||
for (var i = length - 1; i >= 0; i--) {
|
||
if (frames[i].offset <= timeFraction) {
|
||
ASSERT_ENABLED && assert(frames[i].offset !== 1.0);
|
||
startKeyframeIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
var startKeyframe = frames[startKeyframeIndex];
|
||
var endKeyframe = frames[startKeyframeIndex + 1];
|
||
if (startKeyframe.offset === timeFraction) {
|
||
return new AddReplaceCompositableValue(startKeyframe.rawValue(),
|
||
this._compositeForKeyframe(startKeyframe));
|
||
}
|
||
if (endKeyframe.offset === timeFraction) {
|
||
return new AddReplaceCompositableValue(endKeyframe.rawValue(),
|
||
this._compositeForKeyframe(endKeyframe));
|
||
}
|
||
var intervalDistance = (timeFraction - startKeyframe.offset) /
|
||
(endKeyframe.offset - startKeyframe.offset);
|
||
if (startKeyframe.easing) {
|
||
intervalDistance = startKeyframe.easing.scaleTime(intervalDistance);
|
||
}
|
||
return new BlendedCompositableValue(
|
||
new AddReplaceCompositableValue(startKeyframe.rawValue(),
|
||
this._compositeForKeyframe(startKeyframe)),
|
||
new AddReplaceCompositableValue(endKeyframe.rawValue(),
|
||
this._compositeForKeyframe(endKeyframe)),
|
||
intervalDistance);
|
||
},
|
||
_propertySpecificKeyframes: function() {
|
||
if (isDefinedAndNotNull(this._cachedPropertySpecificKeyframes)) {
|
||
return this._cachedPropertySpecificKeyframes;
|
||
}
|
||
|
||
this._cachedPropertySpecificKeyframes = {};
|
||
var distributedFrames = this._getDistributedKeyframes();
|
||
for (var i = 0; i < distributedFrames.length; i++) {
|
||
for (var property in distributedFrames[i].cssValues) {
|
||
if (!(property in this._cachedPropertySpecificKeyframes)) {
|
||
this._cachedPropertySpecificKeyframes[property] = [];
|
||
}
|
||
var frame = distributedFrames[i];
|
||
this._cachedPropertySpecificKeyframes[property].push(
|
||
new PropertySpecificKeyframe(frame.offset, frame.composite,
|
||
frame.easing, property, frame.cssValues[property]));
|
||
}
|
||
}
|
||
|
||
for (var property in this._cachedPropertySpecificKeyframes) {
|
||
var frames = this._cachedPropertySpecificKeyframes[property];
|
||
ASSERT_ENABLED && assert(
|
||
frames.length > 0,
|
||
'There should always be keyframes for each property');
|
||
|
||
// Add synthetic keyframes at offsets of 0 and 1 if required.
|
||
if (frames[0].offset !== 0.0) {
|
||
var keyframe = new PropertySpecificKeyframe(0.0, 'add',
|
||
presetTimingFunctions.linear, property, cssNeutralValue);
|
||
frames.unshift(keyframe);
|
||
}
|
||
if (frames[frames.length - 1].offset !== 1.0) {
|
||
var keyframe = new PropertySpecificKeyframe(1.0, 'add',
|
||
presetTimingFunctions.linear, property, cssNeutralValue);
|
||
frames.push(keyframe);
|
||
}
|
||
ASSERT_ENABLED && assert(
|
||
frames.length >= 2,
|
||
'There should be at least two keyframes including' +
|
||
' synthetic keyframes');
|
||
}
|
||
|
||
return this._cachedPropertySpecificKeyframes;
|
||
},
|
||
clone: function() {
|
||
var result = new KeyframeEffect([], this.composite);
|
||
result._keyframeDictionaries = this._keyframeDictionaries.slice(0);
|
||
return result;
|
||
},
|
||
toString: function() {
|
||
return '<KeyframeEffect>';
|
||
},
|
||
_compositeForKeyframe: function(keyframe) {
|
||
return isDefinedAndNotNull(keyframe.composite) ?
|
||
keyframe.composite : this.composite;
|
||
},
|
||
_allKeyframesUseSameCompositeOperation: function(keyframes) {
|
||
ASSERT_ENABLED && assert(
|
||
keyframes.length >= 1, 'This requires at least one keyframe');
|
||
var composite = this._compositeForKeyframe(keyframes[0]);
|
||
for (var i = 1; i < keyframes.length; i++) {
|
||
if (this._compositeForKeyframe(keyframes[i]) !== composite) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
_areKeyframeDictionariesLooselySorted: function() {
|
||
var previousOffset = -Infinity;
|
||
for (var i = 0; i < this._keyframeDictionaries.length; i++) {
|
||
if (isDefinedAndNotNull(this._keyframeDictionaries[i].offset)) {
|
||
if (this._keyframeDictionaries[i].offset < previousOffset) {
|
||
return false;
|
||
}
|
||
previousOffset = this._keyframeDictionaries[i].offset;
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
// The spec describes both this process and the process for interpretting the
|
||
// properties of a keyframe dictionary as 'normalizing'. Here we use the term
|
||
// 'distributing' to avoid confusion with normalizeKeyframeDictionary().
|
||
_getDistributedKeyframes: function() {
|
||
if (!this._areKeyframeDictionariesLooselySorted()) {
|
||
return [];
|
||
}
|
||
|
||
var distributedKeyframes = this._keyframeDictionaries.map(
|
||
KeyframeInternal.createFromNormalizedProperties);
|
||
|
||
// Remove keyframes with offsets out of bounds.
|
||
var length = distributedKeyframes.length;
|
||
var count = 0;
|
||
for (var i = 0; i < length; i++) {
|
||
var offset = distributedKeyframes[i].offset;
|
||
if (isDefinedAndNotNull(offset)) {
|
||
if (offset >= 0) {
|
||
break;
|
||
} else {
|
||
count = i;
|
||
}
|
||
}
|
||
}
|
||
distributedKeyframes.splice(0, count);
|
||
|
||
length = distributedKeyframes.length;
|
||
count = 0;
|
||
for (var i = length - 1; i >= 0; i--) {
|
||
var offset = distributedKeyframes[i].offset;
|
||
if (isDefinedAndNotNull(offset)) {
|
||
if (offset <= 1) {
|
||
break;
|
||
} else {
|
||
count = length - i;
|
||
}
|
||
}
|
||
}
|
||
distributedKeyframes.splice(length - count, count);
|
||
|
||
// Distribute offsets.
|
||
length = distributedKeyframes.length;
|
||
if (length > 1 && !isDefinedAndNotNull(distributedKeyframes[0].offset)) {
|
||
distributedKeyframes[0].offset = 0;
|
||
}
|
||
if (length > 0 &&
|
||
!isDefinedAndNotNull(distributedKeyframes[length - 1].offset)) {
|
||
distributedKeyframes[length - 1].offset = 1;
|
||
}
|
||
var lastOffsetIndex = 0;
|
||
var nextOffsetIndex = 0;
|
||
for (var i = 1; i < distributedKeyframes.length - 1; i++) {
|
||
var keyframe = distributedKeyframes[i];
|
||
if (isDefinedAndNotNull(keyframe.offset)) {
|
||
lastOffsetIndex = i;
|
||
continue;
|
||
}
|
||
if (i > nextOffsetIndex) {
|
||
nextOffsetIndex = i;
|
||
while (!isDefinedAndNotNull(
|
||
distributedKeyframes[nextOffsetIndex].offset)) {
|
||
nextOffsetIndex++;
|
||
}
|
||
}
|
||
var lastOffset = distributedKeyframes[lastOffsetIndex].offset;
|
||
var nextOffset = distributedKeyframes[nextOffsetIndex].offset;
|
||
var unspecifiedKeyframes = nextOffsetIndex - lastOffsetIndex - 1;
|
||
ASSERT_ENABLED && assert(unspecifiedKeyframes > 0);
|
||
var localIndex = i - lastOffsetIndex;
|
||
ASSERT_ENABLED && assert(localIndex > 0);
|
||
distributedKeyframes[i].offset = lastOffset +
|
||
(nextOffset - lastOffset) * localIndex / (unspecifiedKeyframes + 1);
|
||
}
|
||
|
||
// Remove invalid property values.
|
||
for (var i = distributedKeyframes.length - 1; i >= 0; i--) {
|
||
var keyframe = distributedKeyframes[i];
|
||
for (var property in keyframe.cssValues) {
|
||
if (!KeyframeInternal.isSupportedPropertyValue(
|
||
keyframe.cssValues[property])) {
|
||
delete(keyframe.cssValues[property]);
|
||
}
|
||
}
|
||
if (Object.keys(keyframe).length === 0) {
|
||
distributedKeyframes.splice(i, 1);
|
||
}
|
||
}
|
||
|
||
return distributedKeyframes;
|
||
}
|
||
});
|
||
|
||
|
||
|
||
/**
|
||
* An internal representation of a keyframe. The Keyframe type from the spec is
|
||
* just a dictionary and is not exposed.
|
||
*
|
||
* @constructor
|
||
*/
|
||
var KeyframeInternal = function(offset, composite, easing) {
|
||
ASSERT_ENABLED && assert(
|
||
typeof offset === 'number' || offset === null,
|
||
'Invalid offset value');
|
||
ASSERT_ENABLED && assert(
|
||
composite === 'add' || composite === 'replace' || composite === null,
|
||
'Invalid composite value');
|
||
this.offset = offset;
|
||
this.composite = composite;
|
||
this.easing = easing;
|
||
this.cssValues = {};
|
||
};
|
||
|
||
KeyframeInternal.prototype = {
|
||
addPropertyValuePair: function(property, value) {
|
||
ASSERT_ENABLED && assert(!this.cssValues.hasOwnProperty(property));
|
||
this.cssValues[property] = value;
|
||
},
|
||
hasValueForProperty: function(property) {
|
||
return property in this.cssValues;
|
||
}
|
||
};
|
||
|
||
KeyframeInternal.isSupportedPropertyValue = function(value) {
|
||
ASSERT_ENABLED && assert(
|
||
typeof value === 'string' || value === cssNeutralValue);
|
||
// TODO: Check this properly!
|
||
return value !== '';
|
||
};
|
||
|
||
KeyframeInternal.createFromNormalizedProperties = function(properties) {
|
||
ASSERT_ENABLED && assert(
|
||
isDefinedAndNotNull(properties) && typeof properties === 'object',
|
||
'Properties must be an object');
|
||
var keyframe = new KeyframeInternal(properties.offset, properties.composite,
|
||
properties.easing);
|
||
for (var candidate in properties) {
|
||
if (candidate !== 'offset' &&
|
||
candidate !== 'composite' &&
|
||
candidate !== 'easing') {
|
||
keyframe.addPropertyValuePair(candidate, properties[candidate]);
|
||
}
|
||
}
|
||
return keyframe;
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var PropertySpecificKeyframe = function(offset, composite, easing, property,
|
||
cssValue) {
|
||
this.offset = offset;
|
||
this.composite = composite;
|
||
this.easing = easing;
|
||
this.property = property;
|
||
this.cssValue = cssValue;
|
||
// Calculated lazily
|
||
this.cachedRawValue = null;
|
||
};
|
||
|
||
PropertySpecificKeyframe.prototype = {
|
||
rawValue: function() {
|
||
if (!isDefinedAndNotNull(this.cachedRawValue)) {
|
||
this.cachedRawValue = fromCssValue(this.property, this.cssValue);
|
||
}
|
||
return this.cachedRawValue;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var TimingFunction = function() {
|
||
throw new TypeError('Illegal constructor');
|
||
};
|
||
|
||
TimingFunction.prototype.scaleTime = abstractMethod;
|
||
|
||
TimingFunction.createFromString = function(spec, timedItem) {
|
||
var preset = presetTimingFunctions[spec];
|
||
if (preset) {
|
||
return preset;
|
||
}
|
||
if (spec === 'paced') {
|
||
if (timedItem instanceof Animation &&
|
||
timedItem.effect instanceof MotionPathEffect) {
|
||
return new PacedTimingFunction(timedItem.effect);
|
||
}
|
||
return presetTimingFunctions.linear;
|
||
}
|
||
var stepMatch = /steps\(\s*(\d+)\s*,\s*(start|end|middle)\s*\)/.exec(spec);
|
||
if (stepMatch) {
|
||
return new StepTimingFunction(Number(stepMatch[1]), stepMatch[2]);
|
||
}
|
||
var bezierMatch =
|
||
/cubic-bezier\(([^,]*),([^,]*),([^,]*),([^)]*)\)/.exec(spec);
|
||
if (bezierMatch) {
|
||
return new CubicBezierTimingFunction([
|
||
Number(bezierMatch[1]),
|
||
Number(bezierMatch[2]),
|
||
Number(bezierMatch[3]),
|
||
Number(bezierMatch[4])
|
||
]);
|
||
}
|
||
return presetTimingFunctions.linear;
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var CubicBezierTimingFunction = function(spec) {
|
||
this.params = spec;
|
||
this.map = [];
|
||
for (var ii = 0; ii <= 100; ii += 1) {
|
||
var i = ii / 100;
|
||
this.map.push([
|
||
3 * i * (1 - i) * (1 - i) * this.params[0] +
|
||
3 * i * i * (1 - i) * this.params[2] + i * i * i,
|
||
3 * i * (1 - i) * (1 - i) * this.params[1] +
|
||
3 * i * i * (1 - i) * this.params[3] + i * i * i
|
||
]);
|
||
}
|
||
};
|
||
|
||
CubicBezierTimingFunction.prototype = createObject(TimingFunction.prototype, {
|
||
scaleTime: function(fraction) {
|
||
var fst = 0;
|
||
while (fst !== 100 && fraction > this.map[fst][0]) {
|
||
fst += 1;
|
||
}
|
||
if (fraction === this.map[fst][0] || fst === 0) {
|
||
return this.map[fst][1];
|
||
}
|
||
var yDiff = this.map[fst][1] - this.map[fst - 1][1];
|
||
var xDiff = this.map[fst][0] - this.map[fst - 1][0];
|
||
var p = (fraction - this.map[fst - 1][0]) / xDiff;
|
||
return this.map[fst - 1][1] + p * yDiff;
|
||
}
|
||
});
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var StepTimingFunction = function(numSteps, position) {
|
||
this.numSteps = numSteps;
|
||
this.position = position || 'end';
|
||
};
|
||
|
||
StepTimingFunction.prototype = createObject(TimingFunction.prototype, {
|
||
scaleTime: function(fraction) {
|
||
if (fraction >= 1) {
|
||
return 1;
|
||
}
|
||
var stepSize = 1 / this.numSteps;
|
||
if (this.position === 'start') {
|
||
fraction += stepSize;
|
||
} else if (this.position === 'middle') {
|
||
fraction += stepSize / 2;
|
||
}
|
||
return fraction - fraction % stepSize;
|
||
}
|
||
});
|
||
|
||
var presetTimingFunctions = {
|
||
'linear': null,
|
||
'ease': new CubicBezierTimingFunction([0.25, 0.1, 0.25, 1.0]),
|
||
'ease-in': new CubicBezierTimingFunction([0.42, 0, 1.0, 1.0]),
|
||
'ease-out': new CubicBezierTimingFunction([0, 0, 0.58, 1.0]),
|
||
'ease-in-out': new CubicBezierTimingFunction([0.42, 0, 0.58, 1.0]),
|
||
'step-start': new StepTimingFunction(1, 'start'),
|
||
'step-middle': new StepTimingFunction(1, 'middle'),
|
||
'step-end': new StepTimingFunction(1, 'end')
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var PacedTimingFunction = function(pathEffect) {
|
||
ASSERT_ENABLED && assert(pathEffect instanceof MotionPathEffect);
|
||
this._pathEffect = pathEffect;
|
||
// Range is the portion of the effect over which we pace, normalized to
|
||
// [0, 1].
|
||
this._range = {min: 0, max: 1};
|
||
};
|
||
|
||
PacedTimingFunction.prototype = createObject(TimingFunction.prototype, {
|
||
setRange: function(range) {
|
||
ASSERT_ENABLED && assert(range.min >= 0 && range.min <= 1);
|
||
ASSERT_ENABLED && assert(range.max >= 0 && range.max <= 1);
|
||
ASSERT_ENABLED && assert(range.min < range.max);
|
||
this._range = range;
|
||
},
|
||
scaleTime: function(fraction) {
|
||
var cumulativeLengths = this._pathEffect._cumulativeLengths;
|
||
var numSegments = cumulativeLengths.length - 1;
|
||
if (!cumulativeLengths[numSegments] || fraction <= 0) {
|
||
return this._range.min;
|
||
}
|
||
if (fraction >= 1) {
|
||
return this._range.max;
|
||
}
|
||
var minLength = this.lengthAtIndex(this._range.min * numSegments);
|
||
var maxLength = this.lengthAtIndex(this._range.max * numSegments);
|
||
var length = interp(minLength, maxLength, fraction);
|
||
var leftIndex = this.findLeftIndex(cumulativeLengths, length);
|
||
var leftLength = cumulativeLengths[leftIndex];
|
||
var segmentLength = cumulativeLengths[leftIndex + 1] - leftLength;
|
||
if (segmentLength > 0) {
|
||
return (leftIndex + (length - leftLength) / segmentLength) / numSegments;
|
||
}
|
||
return leftLength / cumulativeLengths.length;
|
||
},
|
||
findLeftIndex: function(array, value) {
|
||
var leftIndex = 0;
|
||
var rightIndex = array.length;
|
||
while (rightIndex - leftIndex > 1) {
|
||
var midIndex = (leftIndex + rightIndex) >> 1;
|
||
if (array[midIndex] <= value) {
|
||
leftIndex = midIndex;
|
||
} else {
|
||
rightIndex = midIndex;
|
||
}
|
||
}
|
||
return leftIndex;
|
||
},
|
||
lengthAtIndex: function(i) {
|
||
ASSERT_ENABLED &&
|
||
console.assert(i >= 0 && i <= cumulativeLengths.length - 1);
|
||
var leftIndex = Math.floor(i);
|
||
var startLength = this._pathEffect._cumulativeLengths[leftIndex];
|
||
var endLength = this._pathEffect._cumulativeLengths[leftIndex + 1];
|
||
var indexFraction = i % 1;
|
||
return interp(startLength, endLength, indexFraction);
|
||
}
|
||
});
|
||
|
||
var interp = function(from, to, f, type) {
|
||
if (Array.isArray(from) || Array.isArray(to)) {
|
||
return interpArray(from, to, f, type);
|
||
}
|
||
var zero = (type && type.indexOf('scale') === 0) ? 1 : 0;
|
||
to = isDefinedAndNotNull(to) ? to : zero;
|
||
from = isDefinedAndNotNull(from) ? from : zero;
|
||
|
||
return to * f + from * (1 - f);
|
||
};
|
||
|
||
var interpArray = function(from, to, f, type) {
|
||
ASSERT_ENABLED && assert(
|
||
Array.isArray(from) || from === null,
|
||
'From is not an array or null');
|
||
ASSERT_ENABLED && assert(
|
||
Array.isArray(to) || to === null,
|
||
'To is not an array or null');
|
||
ASSERT_ENABLED && assert(
|
||
from === null || to === null || from.length === to.length,
|
||
'Arrays differ in length ' + from + ' : ' + to);
|
||
var length = from ? from.length : to.length;
|
||
|
||
var result = [];
|
||
for (var i = 0; i < length; i++) {
|
||
result[i] = interp(from ? from[i] : null, to ? to[i] : null, f, type);
|
||
}
|
||
return result;
|
||
};
|
||
|
||
var typeWithKeywords = function(keywords, type) {
|
||
var isKeyword;
|
||
if (keywords.length === 1) {
|
||
var keyword = keywords[0];
|
||
isKeyword = function(value) {
|
||
return value === keyword;
|
||
};
|
||
} else {
|
||
isKeyword = function(value) {
|
||
return keywords.indexOf(value) >= 0;
|
||
};
|
||
}
|
||
return createObject(type, {
|
||
add: function(base, delta) {
|
||
if (isKeyword(base) || isKeyword(delta)) {
|
||
return delta;
|
||
}
|
||
return type.add(base, delta);
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
if (isKeyword(from) || isKeyword(to)) {
|
||
return nonNumericType.interpolate(from, to, f);
|
||
}
|
||
return type.interpolate(from, to, f);
|
||
},
|
||
toCssValue: function(value, svgMode) {
|
||
return isKeyword(value) ? value : type.toCssValue(value, svgMode);
|
||
},
|
||
fromCssValue: function(value) {
|
||
return isKeyword(value) ? value : type.fromCssValue(value);
|
||
}
|
||
});
|
||
};
|
||
|
||
var numberType = {
|
||
add: function(base, delta) {
|
||
// If base or delta are 'auto', we fall back to replacement.
|
||
if (base === 'auto' || delta === 'auto') {
|
||
return nonNumericType.add(base, delta);
|
||
}
|
||
return base + delta;
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
// If from or to are 'auto', we fall back to step interpolation.
|
||
if (from === 'auto' || to === 'auto') {
|
||
return nonNumericType.interpolate(from, to);
|
||
}
|
||
return interp(from, to, f);
|
||
},
|
||
toCssValue: function(value) { return value + ''; },
|
||
fromCssValue: function(value) {
|
||
if (value === 'auto') {
|
||
return 'auto';
|
||
}
|
||
var result = Number(value);
|
||
return isNaN(result) ? undefined : result;
|
||
}
|
||
};
|
||
|
||
var integerType = createObject(numberType, {
|
||
interpolate: function(from, to, f) {
|
||
// If from or to are 'auto', we fall back to step interpolation.
|
||
if (from === 'auto' || to === 'auto') {
|
||
return nonNumericType.interpolate(from, to);
|
||
}
|
||
return Math.floor(interp(from, to, f));
|
||
}
|
||
});
|
||
|
||
var fontWeightType = {
|
||
add: function(base, delta) { return base + delta; },
|
||
interpolate: function(from, to, f) {
|
||
return interp(from, to, f);
|
||
},
|
||
toCssValue: function(value) {
|
||
value = Math.round(value / 100) * 100;
|
||
value = clamp(value, 100, 900);
|
||
if (value === 400) {
|
||
return 'normal';
|
||
}
|
||
if (value === 700) {
|
||
return 'bold';
|
||
}
|
||
return String(value);
|
||
},
|
||
fromCssValue: function(value) {
|
||
// TODO: support lighter / darker ?
|
||
var out = Number(value);
|
||
if (isNaN(out) || out < 100 || out > 900 || out % 100 !== 0) {
|
||
return undefined;
|
||
}
|
||
return out;
|
||
}
|
||
};
|
||
|
||
// This regular expression is intentionally permissive, so that
|
||
// platform-prefixed versions of calc will still be accepted as
|
||
// input. While we are restrictive with the transform property
|
||
// name, we need to be able to read underlying calc values from
|
||
// computedStyle so can't easily restrict the input here.
|
||
var outerCalcRE = /^\s*(-webkit-)?calc\s*\(\s*([^)]*)\)/;
|
||
var valueRE = /^\s*(-?[0-9]+(\.[0-9])?[0-9]*)([a-zA-Z%]*)/;
|
||
var operatorRE = /^\s*([+-])/;
|
||
var autoRE = /^\s*auto/i;
|
||
var percentLengthType = {
|
||
zero: function() { return {}; },
|
||
add: function(base, delta) {
|
||
var out = {};
|
||
for (var value in base) {
|
||
out[value] = base[value] + (delta[value] || 0);
|
||
}
|
||
for (value in delta) {
|
||
if (value in base) {
|
||
continue;
|
||
}
|
||
out[value] = delta[value];
|
||
}
|
||
return out;
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
var out = {};
|
||
for (var value in from) {
|
||
out[value] = interp(from[value], to[value], f);
|
||
}
|
||
for (var value in to) {
|
||
if (value in out) {
|
||
continue;
|
||
}
|
||
out[value] = interp(0, to[value], f);
|
||
}
|
||
return out;
|
||
},
|
||
toCssValue: function(value) {
|
||
var s = '';
|
||
var singleValue = true;
|
||
for (var item in value) {
|
||
if (s === '') {
|
||
s = value[item] + item;
|
||
} else if (singleValue) {
|
||
if (value[item] !== 0) {
|
||
s = features.calcFunction +
|
||
'(' + s + ' + ' + value[item] + item + ')';
|
||
singleValue = false;
|
||
}
|
||
} else if (value[item] !== 0) {
|
||
s = s.substring(0, s.length - 1) + ' + ' + value[item] + item + ')';
|
||
}
|
||
}
|
||
return s;
|
||
},
|
||
fromCssValue: function(value) {
|
||
var result = percentLengthType.consumeValueFromString(value);
|
||
if (result) {
|
||
return result.value;
|
||
}
|
||
return undefined;
|
||
},
|
||
consumeValueFromString: function(value) {
|
||
if (!isDefinedAndNotNull(value)) {
|
||
return undefined;
|
||
}
|
||
var autoMatch = autoRE.exec(value);
|
||
if (autoMatch) {
|
||
return {
|
||
value: { auto: true },
|
||
remaining: value.substring(autoMatch[0].length)
|
||
};
|
||
}
|
||
var out = {};
|
||
var calcMatch = outerCalcRE.exec(value);
|
||
if (!calcMatch) {
|
||
var singleValue = valueRE.exec(value);
|
||
if (singleValue && (singleValue.length === 4)) {
|
||
out[singleValue[3]] = Number(singleValue[1]);
|
||
return {
|
||
value: out,
|
||
remaining: value.substring(singleValue[0].length)
|
||
};
|
||
}
|
||
return undefined;
|
||
}
|
||
var remaining = value.substring(calcMatch[0].length);
|
||
var calcInnards = calcMatch[2];
|
||
var firstTime = true;
|
||
while (true) {
|
||
var reversed = false;
|
||
if (firstTime) {
|
||
firstTime = false;
|
||
} else {
|
||
var op = operatorRE.exec(calcInnards);
|
||
if (!op) {
|
||
return undefined;
|
||
}
|
||
if (op[1] === '-') {
|
||
reversed = true;
|
||
}
|
||
calcInnards = calcInnards.substring(op[0].length);
|
||
}
|
||
value = valueRE.exec(calcInnards);
|
||
if (!value) {
|
||
return undefined;
|
||
}
|
||
var valueUnit = value[3];
|
||
var valueNumber = Number(value[1]);
|
||
if (!isDefinedAndNotNull(out[valueUnit])) {
|
||
out[valueUnit] = 0;
|
||
}
|
||
if (reversed) {
|
||
out[valueUnit] -= valueNumber;
|
||
} else {
|
||
out[valueUnit] += valueNumber;
|
||
}
|
||
calcInnards = calcInnards.substring(value[0].length);
|
||
if (/\s*/.exec(calcInnards)[0].length === calcInnards.length) {
|
||
return {
|
||
value: out,
|
||
remaining: remaining
|
||
};
|
||
}
|
||
}
|
||
},
|
||
negate: function(value) {
|
||
var out = {};
|
||
for (var unit in value) {
|
||
out[unit] = -value[unit];
|
||
}
|
||
return out;
|
||
}
|
||
};
|
||
|
||
var percentLengthAutoType = typeWithKeywords(['auto'], percentLengthType);
|
||
|
||
var positionKeywordRE = /^\s*left|^\s*center|^\s*right|^\s*top|^\s*bottom/i;
|
||
var positionType = {
|
||
zero: function() { return [{ px: 0 }, { px: 0 }]; },
|
||
add: function(base, delta) {
|
||
return [
|
||
percentLengthType.add(base[0], delta[0]),
|
||
percentLengthType.add(base[1], delta[1])
|
||
];
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
return [
|
||
percentLengthType.interpolate(from[0], to[0], f),
|
||
percentLengthType.interpolate(from[1], to[1], f)
|
||
];
|
||
},
|
||
toCssValue: function(value) {
|
||
return value.map(percentLengthType.toCssValue).join(' ');
|
||
},
|
||
fromCssValue: function(value) {
|
||
var tokens = positionType.consumeAllTokensFromString(value);
|
||
if (!tokens || tokens.length > 4) {
|
||
return undefined;
|
||
}
|
||
|
||
if (tokens.length === 1) {
|
||
var token = tokens[0];
|
||
return (positionType.isHorizontalToken(token) ?
|
||
[token, 'center'] : ['center', token]).map(positionType.resolveToken);
|
||
}
|
||
|
||
if (tokens.length === 2 &&
|
||
positionType.isHorizontalToken(tokens[0]) &&
|
||
positionType.isVerticalToken(tokens[1])) {
|
||
return tokens.map(positionType.resolveToken);
|
||
}
|
||
|
||
if (tokens.filter(positionType.isKeyword).length !== 2) {
|
||
return undefined;
|
||
}
|
||
|
||
var out = [undefined, undefined];
|
||
var center = false;
|
||
for (var i = 0; i < tokens.length; i++) {
|
||
var token = tokens[i];
|
||
if (!positionType.isKeyword(token)) {
|
||
return undefined;
|
||
}
|
||
if (token === 'center') {
|
||
if (center) {
|
||
return undefined;
|
||
}
|
||
center = true;
|
||
continue;
|
||
}
|
||
var axis = Number(positionType.isVerticalToken(token));
|
||
if (out[axis]) {
|
||
return undefined;
|
||
}
|
||
if (i === tokens.length - 1 || positionType.isKeyword(tokens[i + 1])) {
|
||
out[axis] = positionType.resolveToken(token);
|
||
continue;
|
||
}
|
||
var percentLength = tokens[++i];
|
||
if (token === 'bottom' || token === 'right') {
|
||
percentLength = percentLengthType.negate(percentLength);
|
||
percentLength['%'] = (percentLength['%'] || 0) + 100;
|
||
}
|
||
out[axis] = percentLength;
|
||
}
|
||
if (center) {
|
||
if (!out[0]) {
|
||
out[0] = positionType.resolveToken('center');
|
||
} else if (!out[1]) {
|
||
out[1] = positionType.resolveToken('center');
|
||
} else {
|
||
return undefined;
|
||
}
|
||
}
|
||
return out.every(isDefinedAndNotNull) ? out : undefined;
|
||
},
|
||
consumeAllTokensFromString: function(remaining) {
|
||
var tokens = [];
|
||
while (remaining.trim()) {
|
||
var result = positionType.consumeTokenFromString(remaining);
|
||
if (!result) {
|
||
return undefined;
|
||
}
|
||
tokens.push(result.value);
|
||
remaining = result.remaining;
|
||
}
|
||
return tokens;
|
||
},
|
||
consumeTokenFromString: function(value) {
|
||
var keywordMatch = positionKeywordRE.exec(value);
|
||
if (keywordMatch) {
|
||
return {
|
||
value: keywordMatch[0].trim().toLowerCase(),
|
||
remaining: value.substring(keywordMatch[0].length)
|
||
};
|
||
}
|
||
return percentLengthType.consumeValueFromString(value);
|
||
},
|
||
resolveToken: function(token) {
|
||
if (typeof token === 'string') {
|
||
return percentLengthType.fromCssValue({
|
||
left: '0%',
|
||
center: '50%',
|
||
right: '100%',
|
||
top: '0%',
|
||
bottom: '100%'
|
||
}[token]);
|
||
}
|
||
return token;
|
||
},
|
||
isHorizontalToken: function(token) {
|
||
if (typeof token === 'string') {
|
||
return token in { left: true, center: true, right: true };
|
||
}
|
||
return true;
|
||
},
|
||
isVerticalToken: function(token) {
|
||
if (typeof token === 'string') {
|
||
return token in { top: true, center: true, bottom: true };
|
||
}
|
||
return true;
|
||
},
|
||
isKeyword: function(token) {
|
||
return typeof token === 'string';
|
||
}
|
||
};
|
||
|
||
// Spec: http://dev.w3.org/csswg/css-backgrounds/#background-position
|
||
var positionListType = {
|
||
zero: function() { return [positionType.zero()]; },
|
||
add: function(base, delta) {
|
||
var out = [];
|
||
var maxLength = Math.max(base.length, delta.length);
|
||
for (var i = 0; i < maxLength; i++) {
|
||
var basePosition = base[i] ? base[i] : positionType.zero();
|
||
var deltaPosition = delta[i] ? delta[i] : positionType.zero();
|
||
out.push(positionType.add(basePosition, deltaPosition));
|
||
}
|
||
return out;
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
var out = [];
|
||
var maxLength = Math.max(from.length, to.length);
|
||
for (var i = 0; i < maxLength; i++) {
|
||
var fromPosition = from[i] ? from[i] : positionType.zero();
|
||
var toPosition = to[i] ? to[i] : positionType.zero();
|
||
out.push(positionType.interpolate(fromPosition, toPosition, f));
|
||
}
|
||
return out;
|
||
},
|
||
toCssValue: function(value) {
|
||
return value.map(positionType.toCssValue).join(', ');
|
||
},
|
||
fromCssValue: function(value) {
|
||
if (!isDefinedAndNotNull(value)) {
|
||
return undefined;
|
||
}
|
||
if (!value.trim()) {
|
||
return [positionType.fromCssValue('0% 0%')];
|
||
}
|
||
var positionValues = value.split(',');
|
||
var out = positionValues.map(positionType.fromCssValue);
|
||
return out.every(isDefinedAndNotNull) ? out : undefined;
|
||
}
|
||
};
|
||
|
||
var rectangleRE = /rect\(([^,]+),([^,]+),([^,]+),([^)]+)\)/;
|
||
var rectangleType = {
|
||
add: function(base, delta) {
|
||
return {
|
||
top: percentLengthType.add(base.top, delta.top),
|
||
right: percentLengthType.add(base.right, delta.right),
|
||
bottom: percentLengthType.add(base.bottom, delta.bottom),
|
||
left: percentLengthType.add(base.left, delta.left)
|
||
};
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
return {
|
||
top: percentLengthType.interpolate(from.top, to.top, f),
|
||
right: percentLengthType.interpolate(from.right, to.right, f),
|
||
bottom: percentLengthType.interpolate(from.bottom, to.bottom, f),
|
||
left: percentLengthType.interpolate(from.left, to.left, f)
|
||
};
|
||
},
|
||
toCssValue: function(value) {
|
||
return 'rect(' +
|
||
percentLengthType.toCssValue(value.top) + ',' +
|
||
percentLengthType.toCssValue(value.right) + ',' +
|
||
percentLengthType.toCssValue(value.bottom) + ',' +
|
||
percentLengthType.toCssValue(value.left) + ')';
|
||
},
|
||
fromCssValue: function(value) {
|
||
var match = rectangleRE.exec(value);
|
||
if (!match) {
|
||
return undefined;
|
||
}
|
||
var out = {
|
||
top: percentLengthType.fromCssValue(match[1]),
|
||
right: percentLengthType.fromCssValue(match[2]),
|
||
bottom: percentLengthType.fromCssValue(match[3]),
|
||
left: percentLengthType.fromCssValue(match[4])
|
||
};
|
||
if (out.top && out.right && out.bottom && out.left) {
|
||
return out;
|
||
}
|
||
return undefined;
|
||
}
|
||
};
|
||
|
||
var originType = {
|
||
zero: function() { return [{'%': 0}, {'%': 0}, {px: 0}]; },
|
||
add: function(base, delta) {
|
||
return [
|
||
percentLengthType.add(base[0], delta[0]),
|
||
percentLengthType.add(base[1], delta[1]),
|
||
percentLengthType.add(base[2], delta[2])
|
||
];
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
return [
|
||
percentLengthType.interpolate(from[0], to[0], f),
|
||
percentLengthType.interpolate(from[1], to[1], f),
|
||
percentLengthType.interpolate(from[2], to[2], f)
|
||
];
|
||
},
|
||
toCssValue: function(value) {
|
||
var result = percentLengthType.toCssValue(value[0]) + ' ' +
|
||
percentLengthType.toCssValue(value[1]);
|
||
// Return the third value if it is non-zero.
|
||
for (var unit in value[2]) {
|
||
if (value[2][unit] !== 0) {
|
||
return result + ' ' + percentLengthType.toCssValue(value[2]);
|
||
}
|
||
}
|
||
return result;
|
||
},
|
||
fromCssValue: function(value) {
|
||
var tokens = positionType.consumeAllTokensFromString(value);
|
||
if (!tokens) {
|
||
return undefined;
|
||
}
|
||
var out = ['center', 'center', {px: 0}];
|
||
switch (tokens.length) {
|
||
case 0:
|
||
return originType.zero();
|
||
case 1:
|
||
if (positionType.isHorizontalToken(tokens[0])) {
|
||
out[0] = tokens[0];
|
||
} else if (positionType.isVerticalToken(tokens[0])) {
|
||
out[1] = tokens[0];
|
||
} else {
|
||
return undefined;
|
||
}
|
||
return out.map(positionType.resolveToken);
|
||
case 3:
|
||
if (positionType.isKeyword(tokens[2])) {
|
||
return undefined;
|
||
}
|
||
out[2] = tokens[2];
|
||
case 2:
|
||
if (positionType.isHorizontalToken(tokens[0]) &&
|
||
positionType.isVerticalToken(tokens[1])) {
|
||
out[0] = tokens[0];
|
||
out[1] = tokens[1];
|
||
} else if (positionType.isVerticalToken(tokens[0]) &&
|
||
positionType.isHorizontalToken(tokens[1])) {
|
||
out[0] = tokens[1];
|
||
out[1] = tokens[0];
|
||
} else {
|
||
return undefined;
|
||
}
|
||
return out.map(positionType.resolveToken);
|
||
default:
|
||
return undefined;
|
||
}
|
||
}
|
||
};
|
||
|
||
var shadowType = {
|
||
zero: function() {
|
||
return {
|
||
hOffset: lengthType.zero(),
|
||
vOffset: lengthType.zero()
|
||
};
|
||
},
|
||
_addSingle: function(base, delta) {
|
||
if (base && delta && base.inset !== delta.inset) {
|
||
return delta;
|
||
}
|
||
var result = {
|
||
inset: base ? base.inset : delta.inset,
|
||
hOffset: lengthType.add(
|
||
base ? base.hOffset : lengthType.zero(),
|
||
delta ? delta.hOffset : lengthType.zero()),
|
||
vOffset: lengthType.add(
|
||
base ? base.vOffset : lengthType.zero(),
|
||
delta ? delta.vOffset : lengthType.zero()),
|
||
blur: lengthType.add(
|
||
base && base.blur || lengthType.zero(),
|
||
delta && delta.blur || lengthType.zero())
|
||
};
|
||
if (base && base.spread || delta && delta.spread) {
|
||
result.spread = lengthType.add(
|
||
base && base.spread || lengthType.zero(),
|
||
delta && delta.spread || lengthType.zero());
|
||
}
|
||
if (base && base.color || delta && delta.color) {
|
||
result.color = colorType.add(
|
||
base && base.color || colorType.zero(),
|
||
delta && delta.color || colorType.zero());
|
||
}
|
||
return result;
|
||
},
|
||
add: function(base, delta) {
|
||
var result = [];
|
||
for (var i = 0; i < base.length || i < delta.length; i++) {
|
||
result.push(this._addSingle(base[i], delta[i]));
|
||
}
|
||
return result;
|
||
},
|
||
_interpolateSingle: function(from, to, f) {
|
||
if (from && to && from.inset !== to.inset) {
|
||
return f < 0.5 ? from : to;
|
||
}
|
||
var result = {
|
||
inset: from ? from.inset : to.inset,
|
||
hOffset: lengthType.interpolate(
|
||
from ? from.hOffset : lengthType.zero(),
|
||
to ? to.hOffset : lengthType.zero(), f),
|
||
vOffset: lengthType.interpolate(
|
||
from ? from.vOffset : lengthType.zero(),
|
||
to ? to.vOffset : lengthType.zero(), f),
|
||
blur: lengthType.interpolate(
|
||
from && from.blur || lengthType.zero(),
|
||
to && to.blur || lengthType.zero(), f)
|
||
};
|
||
if (from && from.spread || to && to.spread) {
|
||
result.spread = lengthType.interpolate(
|
||
from && from.spread || lengthType.zero(),
|
||
to && to.spread || lengthType.zero(), f);
|
||
}
|
||
if (from && from.color || to && to.color) {
|
||
result.color = colorType.interpolate(
|
||
from && from.color || colorType.zero(),
|
||
to && to.color || colorType.zero(), f);
|
||
}
|
||
return result;
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
var result = [];
|
||
for (var i = 0; i < from.length || i < to.length; i++) {
|
||
result.push(this._interpolateSingle(from[i], to[i], f));
|
||
}
|
||
return result;
|
||
},
|
||
_toCssValueSingle: function(value) {
|
||
return (value.inset ? 'inset ' : '') +
|
||
lengthType.toCssValue(value.hOffset) + ' ' +
|
||
lengthType.toCssValue(value.vOffset) + ' ' +
|
||
lengthType.toCssValue(value.blur) +
|
||
(value.spread ? ' ' + lengthType.toCssValue(value.spread) : '') +
|
||
(value.color ? ' ' + colorType.toCssValue(value.color) : '');
|
||
},
|
||
toCssValue: function(value) {
|
||
return value.map(this._toCssValueSingle).join(', ');
|
||
},
|
||
fromCssValue: function(value) {
|
||
var shadowRE = /(([^(,]+(\([^)]*\))?)+)/g;
|
||
var match;
|
||
var shadows = [];
|
||
while ((match = shadowRE.exec(value)) !== null) {
|
||
shadows.push(match[0]);
|
||
}
|
||
|
||
var result = shadows.map(function(value) {
|
||
if (value === 'none') {
|
||
return shadowType.zero();
|
||
}
|
||
value = value.replace(/^\s+|\s+$/g, '');
|
||
|
||
var partsRE = /([^ (]+(\([^)]*\))?)/g;
|
||
var parts = [];
|
||
while ((match = partsRE.exec(value)) !== null) {
|
||
parts.push(match[0]);
|
||
}
|
||
|
||
if (parts.length < 2 || parts.length > 7) {
|
||
return undefined;
|
||
}
|
||
var result = {
|
||
inset: false
|
||
};
|
||
|
||
var lengths = [];
|
||
while (parts.length) {
|
||
var part = parts.shift();
|
||
|
||
var length = lengthType.fromCssValue(part);
|
||
if (length) {
|
||
lengths.push(length);
|
||
continue;
|
||
}
|
||
|
||
var color = colorType.fromCssValue(part);
|
||
if (color) {
|
||
result.color = color;
|
||
}
|
||
|
||
if (part === 'inset') {
|
||
result.inset = true;
|
||
}
|
||
}
|
||
|
||
if (lengths.length < 2 || lengths.length > 4) {
|
||
return undefined;
|
||
}
|
||
result.hOffset = lengths[0];
|
||
result.vOffset = lengths[1];
|
||
if (lengths.length > 2) {
|
||
result.blur = lengths[2];
|
||
}
|
||
if (lengths.length > 3) {
|
||
result.spread = lengths[3];
|
||
}
|
||
return result;
|
||
});
|
||
|
||
return result.every(isDefined) ? result : undefined;
|
||
}
|
||
};
|
||
|
||
var nonNumericType = {
|
||
add: function(base, delta) {
|
||
return isDefined(delta) ? delta : base;
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
return f < 0.5 ? from : to;
|
||
},
|
||
toCssValue: function(value) {
|
||
return value;
|
||
},
|
||
fromCssValue: function(value) {
|
||
return value;
|
||
}
|
||
};
|
||
|
||
var visibilityType = createObject(nonNumericType, {
|
||
interpolate: function(from, to, f) {
|
||
if (from !== 'visible' && to !== 'visible') {
|
||
return nonNumericType.interpolate(from, to, f);
|
||
}
|
||
if (f <= 0) {
|
||
return from;
|
||
}
|
||
if (f >= 1) {
|
||
return to;
|
||
}
|
||
return 'visible';
|
||
},
|
||
fromCssValue: function(value) {
|
||
if (['visible', 'hidden', 'collapse'].indexOf(value) !== -1) {
|
||
return value;
|
||
}
|
||
return undefined;
|
||
}
|
||
});
|
||
|
||
var lengthType = percentLengthType;
|
||
var lengthAutoType = typeWithKeywords(['auto'], lengthType);
|
||
|
||
var colorRE = new RegExp(
|
||
'(hsla?|rgba?)\\(' +
|
||
'([\\-0-9]+%?),?\\s*' +
|
||
'([\\-0-9]+%?),?\\s*' +
|
||
'([\\-0-9]+%?)(?:,?\\s*([\\-0-9\\.]+%?))?' +
|
||
'\\)');
|
||
var colorHashRE = new RegExp(
|
||
'#([0-9A-Fa-f][0-9A-Fa-f]?)' +
|
||
'([0-9A-Fa-f][0-9A-Fa-f]?)' +
|
||
'([0-9A-Fa-f][0-9A-Fa-f]?)');
|
||
|
||
function hsl2rgb(h, s, l) {
|
||
// Cribbed from http://dev.w3.org/csswg/css-color/#hsl-color
|
||
// Wrap to 0->360 degrees (IE -10 === 350) then normalize
|
||
h = (((h % 360) + 360) % 360) / 360;
|
||
s = s / 100;
|
||
l = l / 100;
|
||
function hue2rgb(m1, m2, h) {
|
||
if (h < 0) {
|
||
h += 1;
|
||
}
|
||
if (h > 1) {
|
||
h -= 1;
|
||
}
|
||
if (h * 6 < 1) {
|
||
return m1 + (m2 - m1) * h * 6;
|
||
}
|
||
if (h * 2 < 1) {
|
||
return m2;
|
||
}
|
||
if (h * 3 < 2) {
|
||
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
|
||
}
|
||
return m1;
|
||
}
|
||
var m2;
|
||
if (l <= 0.5) {
|
||
m2 = l * (s + 1);
|
||
} else {
|
||
m2 = l + s - l * s;
|
||
}
|
||
|
||
var m1 = l * 2 - m2;
|
||
var r = Math.ceil(hue2rgb(m1, m2, h + 1 / 3) * 255);
|
||
var g = Math.ceil(hue2rgb(m1, m2, h) * 255);
|
||
var b = Math.ceil(hue2rgb(m1, m2, h - 1 / 3) * 255);
|
||
return [r, g, b];
|
||
}
|
||
|
||
var namedColors = {
|
||
aliceblue: [240, 248, 255, 1],
|
||
antiquewhite: [250, 235, 215, 1],
|
||
aqua: [0, 255, 255, 1],
|
||
aquamarine: [127, 255, 212, 1],
|
||
azure: [240, 255, 255, 1],
|
||
beige: [245, 245, 220, 1],
|
||
bisque: [255, 228, 196, 1],
|
||
black: [0, 0, 0, 1],
|
||
blanchedalmond: [255, 235, 205, 1],
|
||
blue: [0, 0, 255, 1],
|
||
blueviolet: [138, 43, 226, 1],
|
||
brown: [165, 42, 42, 1],
|
||
burlywood: [222, 184, 135, 1],
|
||
cadetblue: [95, 158, 160, 1],
|
||
chartreuse: [127, 255, 0, 1],
|
||
chocolate: [210, 105, 30, 1],
|
||
coral: [255, 127, 80, 1],
|
||
cornflowerblue: [100, 149, 237, 1],
|
||
cornsilk: [255, 248, 220, 1],
|
||
crimson: [220, 20, 60, 1],
|
||
cyan: [0, 255, 255, 1],
|
||
darkblue: [0, 0, 139, 1],
|
||
darkcyan: [0, 139, 139, 1],
|
||
darkgoldenrod: [184, 134, 11, 1],
|
||
darkgray: [169, 169, 169, 1],
|
||
darkgreen: [0, 100, 0, 1],
|
||
darkgrey: [169, 169, 169, 1],
|
||
darkkhaki: [189, 183, 107, 1],
|
||
darkmagenta: [139, 0, 139, 1],
|
||
darkolivegreen: [85, 107, 47, 1],
|
||
darkorange: [255, 140, 0, 1],
|
||
darkorchid: [153, 50, 204, 1],
|
||
darkred: [139, 0, 0, 1],
|
||
darksalmon: [233, 150, 122, 1],
|
||
darkseagreen: [143, 188, 143, 1],
|
||
darkslateblue: [72, 61, 139, 1],
|
||
darkslategray: [47, 79, 79, 1],
|
||
darkslategrey: [47, 79, 79, 1],
|
||
darkturquoise: [0, 206, 209, 1],
|
||
darkviolet: [148, 0, 211, 1],
|
||
deeppink: [255, 20, 147, 1],
|
||
deepskyblue: [0, 191, 255, 1],
|
||
dimgray: [105, 105, 105, 1],
|
||
dimgrey: [105, 105, 105, 1],
|
||
dodgerblue: [30, 144, 255, 1],
|
||
firebrick: [178, 34, 34, 1],
|
||
floralwhite: [255, 250, 240, 1],
|
||
forestgreen: [34, 139, 34, 1],
|
||
fuchsia: [255, 0, 255, 1],
|
||
gainsboro: [220, 220, 220, 1],
|
||
ghostwhite: [248, 248, 255, 1],
|
||
gold: [255, 215, 0, 1],
|
||
goldenrod: [218, 165, 32, 1],
|
||
gray: [128, 128, 128, 1],
|
||
green: [0, 128, 0, 1],
|
||
greenyellow: [173, 255, 47, 1],
|
||
grey: [128, 128, 128, 1],
|
||
honeydew: [240, 255, 240, 1],
|
||
hotpink: [255, 105, 180, 1],
|
||
indianred: [205, 92, 92, 1],
|
||
indigo: [75, 0, 130, 1],
|
||
ivory: [255, 255, 240, 1],
|
||
khaki: [240, 230, 140, 1],
|
||
lavender: [230, 230, 250, 1],
|
||
lavenderblush: [255, 240, 245, 1],
|
||
lawngreen: [124, 252, 0, 1],
|
||
lemonchiffon: [255, 250, 205, 1],
|
||
lightblue: [173, 216, 230, 1],
|
||
lightcoral: [240, 128, 128, 1],
|
||
lightcyan: [224, 255, 255, 1],
|
||
lightgoldenrodyellow: [250, 250, 210, 1],
|
||
lightgray: [211, 211, 211, 1],
|
||
lightgreen: [144, 238, 144, 1],
|
||
lightgrey: [211, 211, 211, 1],
|
||
lightpink: [255, 182, 193, 1],
|
||
lightsalmon: [255, 160, 122, 1],
|
||
lightseagreen: [32, 178, 170, 1],
|
||
lightskyblue: [135, 206, 250, 1],
|
||
lightslategray: [119, 136, 153, 1],
|
||
lightslategrey: [119, 136, 153, 1],
|
||
lightsteelblue: [176, 196, 222, 1],
|
||
lightyellow: [255, 255, 224, 1],
|
||
lime: [0, 255, 0, 1],
|
||
limegreen: [50, 205, 50, 1],
|
||
linen: [250, 240, 230, 1],
|
||
magenta: [255, 0, 255, 1],
|
||
maroon: [128, 0, 0, 1],
|
||
mediumaquamarine: [102, 205, 170, 1],
|
||
mediumblue: [0, 0, 205, 1],
|
||
mediumorchid: [186, 85, 211, 1],
|
||
mediumpurple: [147, 112, 219, 1],
|
||
mediumseagreen: [60, 179, 113, 1],
|
||
mediumslateblue: [123, 104, 238, 1],
|
||
mediumspringgreen: [0, 250, 154, 1],
|
||
mediumturquoise: [72, 209, 204, 1],
|
||
mediumvioletred: [199, 21, 133, 1],
|
||
midnightblue: [25, 25, 112, 1],
|
||
mintcream: [245, 255, 250, 1],
|
||
mistyrose: [255, 228, 225, 1],
|
||
moccasin: [255, 228, 181, 1],
|
||
navajowhite: [255, 222, 173, 1],
|
||
navy: [0, 0, 128, 1],
|
||
oldlace: [253, 245, 230, 1],
|
||
olive: [128, 128, 0, 1],
|
||
olivedrab: [107, 142, 35, 1],
|
||
orange: [255, 165, 0, 1],
|
||
orangered: [255, 69, 0, 1],
|
||
orchid: [218, 112, 214, 1],
|
||
palegoldenrod: [238, 232, 170, 1],
|
||
palegreen: [152, 251, 152, 1],
|
||
paleturquoise: [175, 238, 238, 1],
|
||
palevioletred: [219, 112, 147, 1],
|
||
papayawhip: [255, 239, 213, 1],
|
||
peachpuff: [255, 218, 185, 1],
|
||
peru: [205, 133, 63, 1],
|
||
pink: [255, 192, 203, 1],
|
||
plum: [221, 160, 221, 1],
|
||
powderblue: [176, 224, 230, 1],
|
||
purple: [128, 0, 128, 1],
|
||
red: [255, 0, 0, 1],
|
||
rosybrown: [188, 143, 143, 1],
|
||
royalblue: [65, 105, 225, 1],
|
||
saddlebrown: [139, 69, 19, 1],
|
||
salmon: [250, 128, 114, 1],
|
||
sandybrown: [244, 164, 96, 1],
|
||
seagreen: [46, 139, 87, 1],
|
||
seashell: [255, 245, 238, 1],
|
||
sienna: [160, 82, 45, 1],
|
||
silver: [192, 192, 192, 1],
|
||
skyblue: [135, 206, 235, 1],
|
||
slateblue: [106, 90, 205, 1],
|
||
slategray: [112, 128, 144, 1],
|
||
slategrey: [112, 128, 144, 1],
|
||
snow: [255, 250, 250, 1],
|
||
springgreen: [0, 255, 127, 1],
|
||
steelblue: [70, 130, 180, 1],
|
||
tan: [210, 180, 140, 1],
|
||
teal: [0, 128, 128, 1],
|
||
thistle: [216, 191, 216, 1],
|
||
tomato: [255, 99, 71, 1],
|
||
transparent: [0, 0, 0, 0],
|
||
turquoise: [64, 224, 208, 1],
|
||
violet: [238, 130, 238, 1],
|
||
wheat: [245, 222, 179, 1],
|
||
white: [255, 255, 255, 1],
|
||
whitesmoke: [245, 245, 245, 1],
|
||
yellow: [255, 255, 0, 1],
|
||
yellowgreen: [154, 205, 50, 1]
|
||
};
|
||
|
||
var colorType = typeWithKeywords(['currentColor'], {
|
||
zero: function() { return [0, 0, 0, 0]; },
|
||
_premultiply: function(value) {
|
||
var alpha = value[3];
|
||
return [value[0] * alpha, value[1] * alpha, value[2] * alpha];
|
||
},
|
||
add: function(base, delta) {
|
||
var alpha = Math.min(base[3] + delta[3], 1);
|
||
if (alpha === 0) {
|
||
return [0, 0, 0, 0];
|
||
}
|
||
base = this._premultiply(base);
|
||
delta = this._premultiply(delta);
|
||
return [(base[0] + delta[0]) / alpha, (base[1] + delta[1]) / alpha,
|
||
(base[2] + delta[2]) / alpha, alpha];
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
var alpha = clamp(interp(from[3], to[3], f), 0, 1);
|
||
if (alpha === 0) {
|
||
return [0, 0, 0, 0];
|
||
}
|
||
from = this._premultiply(from);
|
||
to = this._premultiply(to);
|
||
return [interp(from[0], to[0], f) / alpha,
|
||
interp(from[1], to[1], f) / alpha,
|
||
interp(from[2], to[2], f) / alpha, alpha];
|
||
},
|
||
toCssValue: function(value) {
|
||
return 'rgba(' + Math.round(value[0]) + ', ' + Math.round(value[1]) +
|
||
', ' + Math.round(value[2]) + ', ' + value[3] + ')';
|
||
},
|
||
fromCssValue: function(value) {
|
||
// http://dev.w3.org/csswg/css-color/#color
|
||
var out = [];
|
||
|
||
var regexResult = colorHashRE.exec(value);
|
||
if (regexResult) {
|
||
if (value.length !== 4 && value.length !== 7) {
|
||
return undefined;
|
||
}
|
||
|
||
var out = [];
|
||
regexResult.shift();
|
||
for (var i = 0; i < 3; i++) {
|
||
if (regexResult[i].length === 1) {
|
||
regexResult[i] = regexResult[i] + regexResult[i];
|
||
}
|
||
var v = Math.max(Math.min(parseInt(regexResult[i], 16), 255), 0);
|
||
out[i] = v;
|
||
}
|
||
out.push(1.0);
|
||
}
|
||
|
||
var regexResult = colorRE.exec(value);
|
||
if (regexResult) {
|
||
regexResult.shift();
|
||
var type = regexResult.shift().substr(0, 3);
|
||
for (var i = 0; i < 3; i++) {
|
||
var m = 1;
|
||
if (regexResult[i][regexResult[i].length - 1] === '%') {
|
||
regexResult[i] = regexResult[i].substr(0, regexResult[i].length - 1);
|
||
m = 255.0 / 100.0;
|
||
}
|
||
if (type === 'rgb') {
|
||
out[i] = clamp(Math.round(parseInt(regexResult[i], 10) * m), 0, 255);
|
||
} else {
|
||
out[i] = parseInt(regexResult[i], 10);
|
||
}
|
||
}
|
||
|
||
// Convert hsl values to rgb value
|
||
if (type === 'hsl') {
|
||
out = hsl2rgb.apply(null, out);
|
||
}
|
||
|
||
if (typeof regexResult[3] !== 'undefined') {
|
||
out[3] = Math.max(Math.min(parseFloat(regexResult[3]), 1.0), 0.0);
|
||
} else {
|
||
out.push(1.0);
|
||
}
|
||
}
|
||
|
||
if (out.some(isNaN)) {
|
||
return undefined;
|
||
}
|
||
if (out.length > 0) {
|
||
return out;
|
||
}
|
||
return namedColors[value];
|
||
}
|
||
});
|
||
|
||
var convertToDeg = function(num, type) {
|
||
switch (type) {
|
||
case 'grad':
|
||
return num / 400 * 360;
|
||
case 'rad':
|
||
return num / 2 / Math.PI * 360;
|
||
case 'turn':
|
||
return num * 360;
|
||
default:
|
||
return num;
|
||
}
|
||
};
|
||
|
||
var extractValue = function(values, pos, hasUnits) {
|
||
var value = Number(values[pos]);
|
||
if (!hasUnits) {
|
||
return value;
|
||
}
|
||
var type = values[pos + 1];
|
||
if (type === '') { type = 'px'; }
|
||
var result = {};
|
||
result[type] = value;
|
||
return result;
|
||
};
|
||
|
||
var extractValues = function(values, numValues, hasOptionalValue,
|
||
hasUnits) {
|
||
var result = [];
|
||
for (var i = 0; i < numValues; i++) {
|
||
result.push(extractValue(values, 1 + 2 * i, hasUnits));
|
||
}
|
||
if (hasOptionalValue && values[1 + 2 * numValues]) {
|
||
result.push(extractValue(values, 1 + 2 * numValues, hasUnits));
|
||
}
|
||
return result;
|
||
};
|
||
|
||
var SPACES = '\\s*';
|
||
var NUMBER = '[+-]?(?:\\d+|\\d*\\.\\d+)';
|
||
var RAW_OPEN_BRACKET = '\\(';
|
||
var RAW_CLOSE_BRACKET = '\\)';
|
||
var RAW_COMMA = ',';
|
||
var UNIT = '[a-zA-Z%]*';
|
||
var START = '^';
|
||
|
||
function capture(x) { return '(' + x + ')'; }
|
||
function optional(x) { return '(?:' + x + ')?'; }
|
||
|
||
var OPEN_BRACKET = [SPACES, RAW_OPEN_BRACKET, SPACES].join('');
|
||
var CLOSE_BRACKET = [SPACES, RAW_CLOSE_BRACKET, SPACES].join('');
|
||
var COMMA = [SPACES, RAW_COMMA, SPACES].join('');
|
||
var UNIT_NUMBER = [capture(NUMBER), capture(UNIT)].join('');
|
||
|
||
function transformRE(name, numParms, hasOptionalParm) {
|
||
var tokenList = [START, SPACES, name, OPEN_BRACKET];
|
||
for (var i = 0; i < numParms - 1; i++) {
|
||
tokenList.push(UNIT_NUMBER);
|
||
tokenList.push(COMMA);
|
||
}
|
||
tokenList.push(UNIT_NUMBER);
|
||
if (hasOptionalParm) {
|
||
tokenList.push(optional([COMMA, UNIT_NUMBER].join('')));
|
||
}
|
||
tokenList.push(CLOSE_BRACKET);
|
||
return new RegExp(tokenList.join(''));
|
||
}
|
||
|
||
function buildMatcher(name, numValues, hasOptionalValue, hasUnits,
|
||
baseValue) {
|
||
var baseName = name;
|
||
if (baseValue) {
|
||
if (name[name.length - 1] === 'X' || name[name.length - 1] === 'Y') {
|
||
baseName = name.substring(0, name.length - 1);
|
||
} else if (name[name.length - 1] === 'Z') {
|
||
baseName = name.substring(0, name.length - 1) + '3d';
|
||
}
|
||
}
|
||
|
||
var f = function(x) {
|
||
var r = extractValues(x, numValues, hasOptionalValue, hasUnits);
|
||
if (baseValue !== undefined) {
|
||
if (name[name.length - 1] === 'X') {
|
||
r.push(baseValue);
|
||
} else if (name[name.length - 1] === 'Y') {
|
||
r = [baseValue].concat(r);
|
||
} else if (name[name.length - 1] === 'Z') {
|
||
r = [baseValue, baseValue].concat(r);
|
||
} else if (hasOptionalValue) {
|
||
while (r.length < 2) {
|
||
if (baseValue === 'copy') {
|
||
r.push(r[0]);
|
||
} else {
|
||
r.push(baseValue);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return r;
|
||
};
|
||
return [transformRE(name, numValues, hasOptionalValue), f, baseName];
|
||
}
|
||
|
||
function buildRotationMatcher(name, numValues, hasOptionalValue,
|
||
baseValue) {
|
||
var m = buildMatcher(name, numValues, hasOptionalValue, true, baseValue);
|
||
|
||
var f = function(x) {
|
||
var r = m[1](x);
|
||
return r.map(function(v) {
|
||
var result = 0;
|
||
for (var type in v) {
|
||
result += convertToDeg(v[type], type);
|
||
}
|
||
return result;
|
||
});
|
||
};
|
||
return [m[0], f, m[2]];
|
||
}
|
||
|
||
function build3DRotationMatcher() {
|
||
var m = buildMatcher('rotate3d', 4, false, true);
|
||
var f = function(x) {
|
||
var r = m[1](x);
|
||
var out = [];
|
||
for (var i = 0; i < 3; i++) {
|
||
out.push(r[i].px);
|
||
}
|
||
var angle = 0;
|
||
for (var unit in r[3]) {
|
||
angle += convertToDeg(r[3][unit], unit);
|
||
}
|
||
out.push(angle);
|
||
return out;
|
||
};
|
||
return [m[0], f, m[2]];
|
||
}
|
||
|
||
var transformREs = [
|
||
buildRotationMatcher('rotate', 1, false),
|
||
buildRotationMatcher('rotateX', 1, false),
|
||
buildRotationMatcher('rotateY', 1, false),
|
||
buildRotationMatcher('rotateZ', 1, false),
|
||
build3DRotationMatcher(),
|
||
buildRotationMatcher('skew', 1, true, 0),
|
||
buildRotationMatcher('skewX', 1, false),
|
||
buildRotationMatcher('skewY', 1, false),
|
||
buildMatcher('translateX', 1, false, true, {px: 0}),
|
||
buildMatcher('translateY', 1, false, true, {px: 0}),
|
||
buildMatcher('translateZ', 1, false, true, {px: 0}),
|
||
buildMatcher('translate', 1, true, true, {px: 0}),
|
||
buildMatcher('translate3d', 3, false, true),
|
||
buildMatcher('scale', 1, true, false, 'copy'),
|
||
buildMatcher('scaleX', 1, false, false, 1),
|
||
buildMatcher('scaleY', 1, false, false, 1),
|
||
buildMatcher('scaleZ', 1, false, false, 1),
|
||
buildMatcher('scale3d', 3, false, false),
|
||
buildMatcher('perspective', 1, false, true),
|
||
buildMatcher('matrix', 6, false, false),
|
||
buildMatcher('matrix3d', 16, false, false)
|
||
];
|
||
|
||
var decomposeMatrix = (function() {
|
||
// this is only ever used on the perspective matrix, which has 0, 0, 0, 1 as
|
||
// last column
|
||
function determinant(m) {
|
||
return m[0][0] * m[1][1] * m[2][2] +
|
||
m[1][0] * m[2][1] * m[0][2] +
|
||
m[2][0] * m[0][1] * m[1][2] -
|
||
m[0][2] * m[1][1] * m[2][0] -
|
||
m[1][2] * m[2][1] * m[0][0] -
|
||
m[2][2] * m[0][1] * m[1][0];
|
||
}
|
||
|
||
// from Wikipedia:
|
||
//
|
||
// [A B]^-1 = [A^-1 + A^-1B(D - CA^-1B)^-1CA^-1 -A^-1B(D - CA^-1B)^-1]
|
||
// [C D] [-(D - CA^-1B)^-1CA^-1 (D - CA^-1B)^-1 ]
|
||
//
|
||
// Therefore
|
||
//
|
||
// [A [0]]^-1 = [A^-1 [0]]
|
||
// [C 1 ] [ -CA^-1 1 ]
|
||
function inverse(m) {
|
||
var iDet = 1 / determinant(m);
|
||
var a = m[0][0], b = m[0][1], c = m[0][2];
|
||
var d = m[1][0], e = m[1][1], f = m[1][2];
|
||
var g = m[2][0], h = m[2][1], k = m[2][2];
|
||
var Ainv = [
|
||
[(e * k - f * h) * iDet, (c * h - b * k) * iDet,
|
||
(b * f - c * e) * iDet, 0],
|
||
[(f * g - d * k) * iDet, (a * k - c * g) * iDet,
|
||
(c * d - a * f) * iDet, 0],
|
||
[(d * h - e * g) * iDet, (g * b - a * h) * iDet,
|
||
(a * e - b * d) * iDet, 0]
|
||
];
|
||
var lastRow = [];
|
||
for (var i = 0; i < 3; i++) {
|
||
var val = 0;
|
||
for (var j = 0; j < 3; j++) {
|
||
val += m[3][j] * Ainv[j][i];
|
||
}
|
||
lastRow.push(val);
|
||
}
|
||
lastRow.push(1);
|
||
Ainv.push(lastRow);
|
||
return Ainv;
|
||
}
|
||
|
||
function transposeMatrix4(m) {
|
||
return [[m[0][0], m[1][0], m[2][0], m[3][0]],
|
||
[m[0][1], m[1][1], m[2][1], m[3][1]],
|
||
[m[0][2], m[1][2], m[2][2], m[3][2]],
|
||
[m[0][3], m[1][3], m[2][3], m[3][3]]];
|
||
}
|
||
|
||
function multVecMatrix(v, m) {
|
||
var result = [];
|
||
for (var i = 0; i < 4; i++) {
|
||
var val = 0;
|
||
for (var j = 0; j < 4; j++) {
|
||
val += v[j] * m[j][i];
|
||
}
|
||
result.push(val);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
function normalize(v) {
|
||
var len = length(v);
|
||
return [v[0] / len, v[1] / len, v[2] / len];
|
||
}
|
||
|
||
function length(v) {
|
||
return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||
}
|
||
|
||
function combine(v1, v2, v1s, v2s) {
|
||
return [v1s * v1[0] + v2s * v2[0], v1s * v1[1] + v2s * v2[1],
|
||
v1s * v1[2] + v2s * v2[2]];
|
||
}
|
||
|
||
function cross(v1, v2) {
|
||
return [v1[1] * v2[2] - v1[2] * v2[1],
|
||
v1[2] * v2[0] - v1[0] * v2[2],
|
||
v1[0] * v2[1] - v1[1] * v2[0]];
|
||
}
|
||
|
||
// TODO: Implement 2D matrix decomposition.
|
||
// http://dev.w3.org/csswg/css-transforms/#decomposing-a-2d-matrix
|
||
function decomposeMatrix(matrix) {
|
||
var m3d = [
|
||
matrix.slice(0, 4),
|
||
matrix.slice(4, 8),
|
||
matrix.slice(8, 12),
|
||
matrix.slice(12, 16)
|
||
];
|
||
|
||
// skip normalization step as m3d[3][3] should always be 1
|
||
if (m3d[3][3] !== 1) {
|
||
throw 'attempt to decompose non-normalized matrix';
|
||
}
|
||
|
||
var perspectiveMatrix = m3d.concat(); // copy m3d
|
||
for (var i = 0; i < 3; i++) {
|
||
perspectiveMatrix[i][3] = 0;
|
||
}
|
||
|
||
if (determinant(perspectiveMatrix) === 0) {
|
||
return false;
|
||
}
|
||
|
||
var rhs = [];
|
||
|
||
var perspective;
|
||
if (m3d[0][3] !== 0 || m3d[1][3] !== 0 || m3d[2][3] !== 0) {
|
||
rhs.push(m3d[0][3]);
|
||
rhs.push(m3d[1][3]);
|
||
rhs.push(m3d[2][3]);
|
||
rhs.push(m3d[3][3]);
|
||
|
||
var inversePerspectiveMatrix = inverse(perspectiveMatrix);
|
||
var transposedInversePerspectiveMatrix =
|
||
transposeMatrix4(inversePerspectiveMatrix);
|
||
perspective = multVecMatrix(rhs, transposedInversePerspectiveMatrix);
|
||
} else {
|
||
perspective = [0, 0, 0, 1];
|
||
}
|
||
|
||
var translate = m3d[3].slice(0, 3);
|
||
|
||
var row = [];
|
||
row.push(m3d[0].slice(0, 3));
|
||
var scale = [];
|
||
scale.push(length(row[0]));
|
||
row[0] = normalize(row[0]);
|
||
|
||
var skew = [];
|
||
row.push(m3d[1].slice(0, 3));
|
||
skew.push(dot(row[0], row[1]));
|
||
row[1] = combine(row[1], row[0], 1.0, -skew[0]);
|
||
|
||
scale.push(length(row[1]));
|
||
row[1] = normalize(row[1]);
|
||
skew[0] /= scale[1];
|
||
|
||
row.push(m3d[2].slice(0, 3));
|
||
skew.push(dot(row[0], row[2]));
|
||
row[2] = combine(row[2], row[0], 1.0, -skew[1]);
|
||
skew.push(dot(row[1], row[2]));
|
||
row[2] = combine(row[2], row[1], 1.0, -skew[2]);
|
||
|
||
scale.push(length(row[2]));
|
||
row[2] = normalize(row[2]);
|
||
skew[1] /= scale[2];
|
||
skew[2] /= scale[2];
|
||
|
||
var pdum3 = cross(row[1], row[2]);
|
||
if (dot(row[0], pdum3) < 0) {
|
||
for (var i = 0; i < 3; i++) {
|
||
scale[i] *= -1;
|
||
row[i][0] *= -1;
|
||
row[i][1] *= -1;
|
||
row[i][2] *= -1;
|
||
}
|
||
}
|
||
|
||
var t = row[0][0] + row[1][1] + row[2][2] + 1;
|
||
var s;
|
||
var quaternion;
|
||
|
||
if (t > 1e-4) {
|
||
s = 0.5 / Math.sqrt(t);
|
||
quaternion = [
|
||
(row[2][1] - row[1][2]) * s,
|
||
(row[0][2] - row[2][0]) * s,
|
||
(row[1][0] - row[0][1]) * s,
|
||
0.25 / s
|
||
];
|
||
} else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
|
||
s = Math.sqrt(1 + row[0][0] - row[1][1] - row[2][2]) * 2.0;
|
||
quaternion = [
|
||
0.25 * s,
|
||
(row[0][1] + row[1][0]) / s,
|
||
(row[0][2] + row[2][0]) / s,
|
||
(row[2][1] - row[1][2]) / s
|
||
];
|
||
} else if (row[1][1] > row[2][2]) {
|
||
s = Math.sqrt(1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0;
|
||
quaternion = [
|
||
(row[0][1] + row[1][0]) / s,
|
||
0.25 * s,
|
||
(row[1][2] + row[2][1]) / s,
|
||
(row[0][2] - row[2][0]) / s
|
||
];
|
||
} else {
|
||
s = Math.sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0;
|
||
quaternion = [
|
||
(row[0][2] + row[2][0]) / s,
|
||
(row[1][2] + row[2][1]) / s,
|
||
0.25 * s,
|
||
(row[1][0] - row[0][1]) / s
|
||
];
|
||
}
|
||
|
||
return {
|
||
translate: translate, scale: scale, skew: skew,
|
||
quaternion: quaternion, perspective: perspective
|
||
};
|
||
}
|
||
return decomposeMatrix;
|
||
})();
|
||
|
||
function dot(v1, v2) {
|
||
var result = 0;
|
||
for (var i = 0; i < v1.length; i++) {
|
||
result += v1[i] * v2[i];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
function multiplyMatrices(a, b) {
|
||
return [
|
||
a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3],
|
||
a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3],
|
||
a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3],
|
||
a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3],
|
||
|
||
a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7],
|
||
a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7],
|
||
a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7],
|
||
a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7],
|
||
|
||
a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11],
|
||
a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11],
|
||
a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11],
|
||
a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11],
|
||
|
||
a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15],
|
||
a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15],
|
||
a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15],
|
||
a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15]
|
||
];
|
||
}
|
||
|
||
function convertItemToMatrix(item) {
|
||
switch (item.t) {
|
||
case 'rotateX':
|
||
var angle = item.d * Math.PI / 180;
|
||
return [1, 0, 0, 0,
|
||
0, Math.cos(angle), Math.sin(angle), 0,
|
||
0, -Math.sin(angle), Math.cos(angle), 0,
|
||
0, 0, 0, 1];
|
||
case 'rotateY':
|
||
var angle = item.d * Math.PI / 180;
|
||
return [Math.cos(angle), 0, -Math.sin(angle), 0,
|
||
0, 1, 0, 0,
|
||
Math.sin(angle), 0, Math.cos(angle), 0,
|
||
0, 0, 0, 1];
|
||
case 'rotate':
|
||
case 'rotateZ':
|
||
var angle = item.d * Math.PI / 180;
|
||
return [Math.cos(angle), Math.sin(angle), 0, 0,
|
||
-Math.sin(angle), Math.cos(angle), 0, 0,
|
||
0, 0, 1, 0,
|
||
0, 0, 0, 1];
|
||
case 'rotate3d':
|
||
var x = item.d[0];
|
||
var y = item.d[1];
|
||
var z = item.d[2];
|
||
var sqrLength = x * x + y * y + z * z;
|
||
if (sqrLength === 0) {
|
||
x = 1;
|
||
y = 0;
|
||
z = 0;
|
||
} else if (sqrLength !== 1) {
|
||
var length = Math.sqrt(sqrLength);
|
||
x /= length;
|
||
y /= length;
|
||
z /= length;
|
||
}
|
||
var s = Math.sin(item.d[3] * Math.PI / 360);
|
||
var sc = s * Math.cos(item.d[3] * Math.PI / 360);
|
||
var sq = s * s;
|
||
return [
|
||
1 - 2 * (y * y + z * z) * sq,
|
||
2 * (x * y * sq + z * sc),
|
||
2 * (x * z * sq - y * sc),
|
||
0,
|
||
|
||
2 * (x * y * sq - z * sc),
|
||
1 - 2 * (x * x + z * z) * sq,
|
||
2 * (y * z * sq + x * sc),
|
||
0,
|
||
|
||
2 * (x * z * sq + y * sc),
|
||
2 * (y * z * sq - x * sc),
|
||
1 - 2 * (x * x + y * y) * sq,
|
||
0,
|
||
|
||
0, 0, 0, 1
|
||
];
|
||
case 'scale':
|
||
return [item.d[0], 0, 0, 0,
|
||
0, item.d[1], 0, 0,
|
||
0, 0, 1, 0,
|
||
0, 0, 0, 1];
|
||
case 'scale3d':
|
||
return [item.d[0], 0, 0, 0,
|
||
0, item.d[1], 0, 0,
|
||
0, 0, item.d[2], 0,
|
||
0, 0, 0, 1];
|
||
case 'skew':
|
||
return [1, Math.tan(item.d[1] * Math.PI / 180), 0, 0,
|
||
Math.tan(item.d[0] * Math.PI / 180), 1, 0, 0,
|
||
0, 0, 1, 0,
|
||
0, 0, 0, 1];
|
||
case 'skewX':
|
||
return [1, 0, 0, 0,
|
||
Math.tan(item.d * Math.PI / 180), 1, 0, 0,
|
||
0, 0, 1, 0,
|
||
0, 0, 0, 1];
|
||
case 'skewY':
|
||
return [1, Math.tan(item.d * Math.PI / 180), 0, 0,
|
||
0, 1, 0, 0,
|
||
0, 0, 1, 0,
|
||
0, 0, 0, 1];
|
||
// TODO: Work out what to do with non-px values.
|
||
case 'translate':
|
||
return [1, 0, 0, 0,
|
||
0, 1, 0, 0,
|
||
0, 0, 1, 0,
|
||
item.d[0].px, item.d[1].px, 0, 1];
|
||
case 'translate3d':
|
||
return [1, 0, 0, 0,
|
||
0, 1, 0, 0,
|
||
0, 0, 1, 0,
|
||
item.d[0].px, item.d[1].px, item.d[2].px, 1];
|
||
case 'perspective':
|
||
return [
|
||
1, 0, 0, 0,
|
||
0, 1, 0, 0,
|
||
0, 0, 1, -1 / item.d.px,
|
||
0, 0, 0, 1];
|
||
case 'matrix':
|
||
return [item.d[0], item.d[1], 0, 0,
|
||
item.d[2], item.d[3], 0, 0,
|
||
0, 0, 1, 0,
|
||
item.d[4], item.d[5], 0, 1];
|
||
case 'matrix3d':
|
||
return item.d;
|
||
default:
|
||
ASSERT_ENABLED && assert(false, 'Transform item type ' + item.t +
|
||
' conversion to matrix not yet implemented.');
|
||
}
|
||
}
|
||
|
||
function convertToMatrix(transformList) {
|
||
if (transformList.length === 0) {
|
||
return [1, 0, 0, 0,
|
||
0, 1, 0, 0,
|
||
0, 0, 1, 0,
|
||
0, 0, 0, 1];
|
||
}
|
||
return transformList.map(convertItemToMatrix).reduce(multiplyMatrices);
|
||
}
|
||
|
||
var composeMatrix = (function() {
|
||
function multiply(a, b) {
|
||
var result = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
|
||
for (var i = 0; i < 4; i++) {
|
||
for (var j = 0; j < 4; j++) {
|
||
for (var k = 0; k < 4; k++) {
|
||
result[i][j] += b[i][k] * a[k][j];
|
||
}
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
function is2D(m) {
|
||
return (
|
||
m[0][2] == 0 &&
|
||
m[0][3] == 0 &&
|
||
m[1][2] == 0 &&
|
||
m[1][3] == 0 &&
|
||
m[2][0] == 0 &&
|
||
m[2][1] == 0 &&
|
||
m[2][2] == 1 &&
|
||
m[2][3] == 0 &&
|
||
m[3][2] == 0 &&
|
||
m[3][3] == 1);
|
||
}
|
||
|
||
function composeMatrix(translate, scale, skew, quat, perspective) {
|
||
var matrix = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]];
|
||
|
||
for (var i = 0; i < 4; i++) {
|
||
matrix[i][3] = perspective[i];
|
||
}
|
||
|
||
for (var i = 0; i < 3; i++) {
|
||
for (var j = 0; j < 3; j++) {
|
||
matrix[3][i] += translate[j] * matrix[j][i];
|
||
}
|
||
}
|
||
|
||
var x = quat[0], y = quat[1], z = quat[2], w = quat[3];
|
||
|
||
var rotMatrix = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]];
|
||
|
||
rotMatrix[0][0] = 1 - 2 * (y * y + z * z);
|
||
rotMatrix[0][1] = 2 * (x * y - z * w);
|
||
rotMatrix[0][2] = 2 * (x * z + y * w);
|
||
rotMatrix[1][0] = 2 * (x * y + z * w);
|
||
rotMatrix[1][1] = 1 - 2 * (x * x + z * z);
|
||
rotMatrix[1][2] = 2 * (y * z - x * w);
|
||
rotMatrix[2][0] = 2 * (x * z - y * w);
|
||
rotMatrix[2][1] = 2 * (y * z + x * w);
|
||
rotMatrix[2][2] = 1 - 2 * (x * x + y * y);
|
||
|
||
matrix = multiply(matrix, rotMatrix);
|
||
|
||
var temp = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]];
|
||
if (skew[2]) {
|
||
temp[2][1] = skew[2];
|
||
matrix = multiply(matrix, temp);
|
||
}
|
||
|
||
if (skew[1]) {
|
||
temp[2][1] = 0;
|
||
temp[2][0] = skew[0];
|
||
matrix = multiply(matrix, temp);
|
||
}
|
||
|
||
if (skew[0]) {
|
||
temp[2][0] = 0;
|
||
temp[1][0] = skew[0];
|
||
matrix = multiply(matrix, temp);
|
||
}
|
||
|
||
for (var i = 0; i < 3; i++) {
|
||
for (var j = 0; j < 3; j++) {
|
||
matrix[i][j] *= scale[i];
|
||
}
|
||
}
|
||
|
||
if (is2D(matrix)) {
|
||
return {
|
||
t: 'matrix',
|
||
d: [matrix[0][0], matrix[0][1], matrix[1][0], matrix[1][1],
|
||
matrix[3][0], matrix[3][1]]
|
||
};
|
||
}
|
||
return {
|
||
t: 'matrix3d',
|
||
d: matrix[0].concat(matrix[1], matrix[2], matrix[3])
|
||
};
|
||
}
|
||
return composeMatrix;
|
||
})();
|
||
|
||
function interpolateDecomposedTransformsWithMatrices(fromM, toM, f) {
|
||
var product = dot(fromM.quaternion, toM.quaternion);
|
||
product = clamp(product, -1.0, 1.0);
|
||
|
||
var quat = [];
|
||
if (product === 1.0) {
|
||
quat = fromM.quaternion;
|
||
} else {
|
||
var theta = Math.acos(product);
|
||
var w = Math.sin(f * theta) * 1 / Math.sqrt(1 - product * product);
|
||
|
||
for (var i = 0; i < 4; i++) {
|
||
quat.push(fromM.quaternion[i] * (Math.cos(f * theta) - product * w) +
|
||
toM.quaternion[i] * w);
|
||
}
|
||
}
|
||
|
||
var translate = interp(fromM.translate, toM.translate, f);
|
||
var scale = interp(fromM.scale, toM.scale, f);
|
||
var skew = interp(fromM.skew, toM.skew, f);
|
||
var perspective = interp(fromM.perspective, toM.perspective, f);
|
||
|
||
return composeMatrix(translate, scale, skew, quat, perspective);
|
||
}
|
||
|
||
function interpTransformValue(from, to, f) {
|
||
var type = from.t ? from.t : to.t;
|
||
switch (type) {
|
||
case 'matrix':
|
||
case 'matrix3d':
|
||
ASSERT_ENABLED && assert(false,
|
||
'Must use matrix decomposition when interpolating raw matrices');
|
||
// Transforms with unitless parameters.
|
||
case 'rotate':
|
||
case 'rotateX':
|
||
case 'rotateY':
|
||
case 'rotateZ':
|
||
case 'rotate3d':
|
||
case 'scale':
|
||
case 'scaleX':
|
||
case 'scaleY':
|
||
case 'scaleZ':
|
||
case 'scale3d':
|
||
case 'skew':
|
||
case 'skewX':
|
||
case 'skewY':
|
||
return {t: type, d: interp(from.d, to.d, f, type)};
|
||
default:
|
||
// Transforms with lengthType parameters.
|
||
var result = [];
|
||
var maxVal;
|
||
if (from.d && to.d) {
|
||
maxVal = Math.max(from.d.length, to.d.length);
|
||
} else if (from.d) {
|
||
maxVal = from.d.length;
|
||
} else {
|
||
maxVal = to.d.length;
|
||
}
|
||
for (var j = 0; j < maxVal; j++) {
|
||
var fromVal = from.d ? from.d[j] : {};
|
||
var toVal = to.d ? to.d[j] : {};
|
||
result.push(lengthType.interpolate(fromVal, toVal, f));
|
||
}
|
||
return {t: type, d: result};
|
||
}
|
||
}
|
||
|
||
function isMatrix(item) {
|
||
return item.t[0] === 'm';
|
||
}
|
||
|
||
// The CSSWG decided to disallow scientific notation in CSS property strings
|
||
// (see http://lists.w3.org/Archives/Public/www-style/2010Feb/0050.html).
|
||
// We need this function to hakonitize all numbers before adding them to
|
||
// property strings.
|
||
// TODO: Apply this function to all property strings
|
||
function n(num) {
|
||
return Number(num).toFixed(4);
|
||
}
|
||
|
||
var transformType = {
|
||
add: function(base, delta) { return base.concat(delta); },
|
||
interpolate: function(from, to, f) {
|
||
var out = [];
|
||
for (var i = 0; i < Math.min(from.length, to.length); i++) {
|
||
if (from[i].t !== to[i].t || isMatrix(from[i])) {
|
||
break;
|
||
}
|
||
out.push(interpTransformValue(from[i], to[i], f));
|
||
}
|
||
|
||
if (i < Math.min(from.length, to.length) ||
|
||
from.some(isMatrix) || to.some(isMatrix)) {
|
||
if (from.decompositionPair !== to) {
|
||
from.decompositionPair = to;
|
||
from.decomposition = decomposeMatrix(convertToMatrix(from.slice(i)));
|
||
}
|
||
if (to.decompositionPair !== from) {
|
||
to.decompositionPair = from;
|
||
to.decomposition = decomposeMatrix(convertToMatrix(to.slice(i)));
|
||
}
|
||
out.push(interpolateDecomposedTransformsWithMatrices(
|
||
from.decomposition, to.decomposition, f));
|
||
return out;
|
||
}
|
||
|
||
for (; i < from.length; i++) {
|
||
out.push(interpTransformValue(from[i], {t: null, d: null}, f));
|
||
}
|
||
for (; i < to.length; i++) {
|
||
out.push(interpTransformValue({t: null, d: null}, to[i], f));
|
||
}
|
||
return out;
|
||
},
|
||
toCssValue: function(value, svgMode) {
|
||
// TODO: fix this :)
|
||
var out = '';
|
||
for (var i = 0; i < value.length; i++) {
|
||
ASSERT_ENABLED && assert(
|
||
value[i].t, 'transform type should be resolved by now');
|
||
switch (value[i].t) {
|
||
case 'rotate':
|
||
case 'rotateX':
|
||
case 'rotateY':
|
||
case 'rotateZ':
|
||
case 'skewX':
|
||
case 'skewY':
|
||
var unit = svgMode ? '' : 'deg';
|
||
out += value[i].t + '(' + value[i].d + unit + ') ';
|
||
break;
|
||
case 'skew':
|
||
var unit = svgMode ? '' : 'deg';
|
||
out += value[i].t + '(' + value[i].d[0] + unit;
|
||
if (value[i].d[1] === 0) {
|
||
out += ') ';
|
||
} else {
|
||
out += ', ' + value[i].d[1] + unit + ') ';
|
||
}
|
||
break;
|
||
case 'rotate3d':
|
||
var unit = svgMode ? '' : 'deg';
|
||
out += value[i].t + '(' + value[i].d[0] + ', ' + value[i].d[1] +
|
||
', ' + value[i].d[2] + ', ' + value[i].d[3] + unit + ') ';
|
||
break;
|
||
case 'translateX':
|
||
case 'translateY':
|
||
case 'translateZ':
|
||
case 'perspective':
|
||
out += value[i].t + '(' + lengthType.toCssValue(value[i].d[0]) +
|
||
') ';
|
||
break;
|
||
case 'translate':
|
||
if (svgMode) {
|
||
if (value[i].d[1] === undefined) {
|
||
out += value[i].t + '(' + value[i].d[0].px + ') ';
|
||
} else {
|
||
out += (
|
||
value[i].t + '(' + value[i].d[0].px + ', ' +
|
||
value[i].d[1].px + ') ');
|
||
}
|
||
break;
|
||
}
|
||
if (value[i].d[1] === undefined) {
|
||
out += value[i].t + '(' + lengthType.toCssValue(value[i].d[0]) +
|
||
') ';
|
||
} else {
|
||
out += value[i].t + '(' + lengthType.toCssValue(value[i].d[0]) +
|
||
', ' + lengthType.toCssValue(value[i].d[1]) + ') ';
|
||
}
|
||
break;
|
||
case 'translate3d':
|
||
var values = value[i].d.map(lengthType.toCssValue);
|
||
out += value[i].t + '(' + values[0] + ', ' + values[1] +
|
||
', ' + values[2] + ') ';
|
||
break;
|
||
case 'scale':
|
||
if (value[i].d[0] === value[i].d[1]) {
|
||
out += value[i].t + '(' + value[i].d[0] + ') ';
|
||
} else {
|
||
out += value[i].t + '(' + value[i].d[0] + ', ' + value[i].d[1] +
|
||
') ';
|
||
}
|
||
break;
|
||
case 'scaleX':
|
||
case 'scaleY':
|
||
case 'scaleZ':
|
||
out += value[i].t + '(' + value[i].d[0] + ') ';
|
||
break;
|
||
case 'scale3d':
|
||
out += value[i].t + '(' + value[i].d[0] + ', ' +
|
||
value[i].d[1] + ', ' + value[i].d[2] + ') ';
|
||
break;
|
||
case 'matrix':
|
||
case 'matrix3d':
|
||
out += value[i].t + '(' + value[i].d.map(n).join(', ') + ') ';
|
||
break;
|
||
}
|
||
}
|
||
return out.substring(0, out.length - 1);
|
||
},
|
||
fromCssValue: function(value) {
|
||
// TODO: fix this :)
|
||
if (value === undefined) {
|
||
return undefined;
|
||
}
|
||
var result = [];
|
||
while (value.length > 0) {
|
||
var r;
|
||
for (var i = 0; i < transformREs.length; i++) {
|
||
var reSpec = transformREs[i];
|
||
r = reSpec[0].exec(value);
|
||
if (r) {
|
||
result.push({t: reSpec[2], d: reSpec[1](r)});
|
||
value = value.substring(r[0].length);
|
||
break;
|
||
}
|
||
}
|
||
if (!isDefinedAndNotNull(r)) {
|
||
return result;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
};
|
||
|
||
var pathType = {
|
||
// Properties ...
|
||
// - path: The target path element
|
||
// - points: The absolute points to set on the path
|
||
// - cachedCumulativeLengths: The lengths at the end of each segment
|
||
add: function() { throw 'Addition not supported for path attribute' },
|
||
cumulativeLengths: function(value) {
|
||
if (isDefinedAndNotNull(value.cachedCumulativeLengths))
|
||
return value.cachedCumulativeLengths;
|
||
var path = value.path.cloneNode(true);
|
||
var cumulativeLengths = [];
|
||
while (path.pathSegList.numberOfItems > 0) {
|
||
// TODO: It would be good to skip moves here and when generating points.
|
||
cumulativeLengths.unshift(path.getTotalLength());
|
||
path.pathSegList.removeItem(path.pathSegList.numberOfItems - 1);
|
||
}
|
||
value.cachedCumulativeLengths = cumulativeLengths;
|
||
return value.cachedCumulativeLengths;
|
||
},
|
||
appendFractions: function(fractions, cumulativeLengths) {
|
||
ASSERT_ENABLED && assert(cumulativeLengths[0] === 0);
|
||
var totalLength = cumulativeLengths[cumulativeLengths.length - 1];
|
||
for (var i = 1; i < cumulativeLengths.length - 1; ++i)
|
||
fractions.push(cumulativeLengths[i] / totalLength);
|
||
},
|
||
interpolate: function(from, to, f) {
|
||
// FIXME: Handle non-linear path segments.
|
||
// Get the fractions at which we need to sample.
|
||
var sampleFractions = [0, 1];
|
||
pathType.appendFractions(sampleFractions, pathType.cumulativeLengths(from));
|
||
pathType.appendFractions(sampleFractions, pathType.cumulativeLengths(to));
|
||
sampleFractions.sort();
|
||
ASSERT_ENABLED && assert(sampleFractions[0] === 0);
|
||
ASSERT_ENABLED && assert(sampleFractions[sampleFractions.length - 1] === 1);
|
||
|
||
// FIXME: Cache the 'from' and 'to' points.
|
||
var fromTotalLength = from.path.getTotalLength();
|
||
var toTotalLength = to.path.getTotalLength();
|
||
var points = [];
|
||
for (var i = 0; i < sampleFractions.length; ++i) {
|
||
var fromPoint = from.path.getPointAtLength(
|
||
fromTotalLength * sampleFractions[i]);
|
||
var toPoint = to.path.getPointAtLength(
|
||
toTotalLength * sampleFractions[i]);
|
||
points.push({
|
||
x: interp(fromPoint.x, toPoint.x, f),
|
||
y: interp(fromPoint.y, toPoint.y, f)
|
||
});
|
||
}
|
||
return {points: points};
|
||
},
|
||
pointToString: function(point) {
|
||
return point.x + ',' + point.y;
|
||
},
|
||
toCssValue: function(value, svgMode) {
|
||
// FIXME: It would be good to use PathSegList API on the target directly,
|
||
// rather than generating this string, but that would require a hack to
|
||
// setValue().
|
||
ASSERT_ENABLED && assert(svgMode,
|
||
'Path type should only be used with SVG \'d\' attribute');
|
||
if (value.path)
|
||
return value.path.getAttribute('d');
|
||
var ret = 'M' + pathType.pointToString(value.points[0]);
|
||
for (var i = 1; i < value.points.length; ++i)
|
||
ret += 'L' + pathType.pointToString(value.points[i]);
|
||
return ret;
|
||
},
|
||
fromCssValue: function(value) {
|
||
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||
if (value)
|
||
path.setAttribute('d', value);
|
||
return {path: path};
|
||
}
|
||
};
|
||
|
||
var propertyTypes = {
|
||
backgroundColor: colorType,
|
||
backgroundPosition: positionListType,
|
||
borderBottomColor: colorType,
|
||
borderBottomLeftRadius: percentLengthType,
|
||
borderBottomRightRadius: percentLengthType,
|
||
borderBottomWidth: lengthType,
|
||
borderLeftColor: colorType,
|
||
borderLeftWidth: lengthType,
|
||
borderRightColor: colorType,
|
||
borderRightWidth: lengthType,
|
||
borderSpacing: lengthType,
|
||
borderTopColor: colorType,
|
||
borderTopLeftRadius: percentLengthType,
|
||
borderTopRightRadius: percentLengthType,
|
||
borderTopWidth: lengthType,
|
||
bottom: percentLengthAutoType,
|
||
boxShadow: shadowType,
|
||
clip: typeWithKeywords(['auto'], rectangleType),
|
||
color: colorType,
|
||
cx: lengthType,
|
||
cy: lengthType,
|
||
d: pathType,
|
||
dx: lengthType,
|
||
dy: lengthType,
|
||
fill: colorType,
|
||
floodColor: colorType,
|
||
|
||
// TODO: Handle these keywords properly.
|
||
fontSize: typeWithKeywords(['smaller', 'larger'], percentLengthType),
|
||
fontWeight: typeWithKeywords(['lighter', 'bolder'], fontWeightType),
|
||
|
||
height: percentLengthAutoType,
|
||
left: percentLengthAutoType,
|
||
letterSpacing: typeWithKeywords(['normal'], lengthType),
|
||
lightingColor: colorType,
|
||
lineHeight: percentLengthType, // TODO: Should support numberType as well.
|
||
marginBottom: lengthAutoType,
|
||
marginLeft: lengthAutoType,
|
||
marginRight: lengthAutoType,
|
||
marginTop: lengthAutoType,
|
||
maxHeight: typeWithKeywords(
|
||
['none', 'max-content', 'min-content', 'fill-available', 'fit-content'],
|
||
percentLengthType),
|
||
maxWidth: typeWithKeywords(
|
||
['none', 'max-content', 'min-content', 'fill-available', 'fit-content'],
|
||
percentLengthType),
|
||
minHeight: typeWithKeywords(
|
||
['max-content', 'min-content', 'fill-available', 'fit-content'],
|
||
percentLengthType),
|
||
minWidth: typeWithKeywords(
|
||
['max-content', 'min-content', 'fill-available', 'fit-content'],
|
||
percentLengthType),
|
||
opacity: numberType,
|
||
outlineColor: typeWithKeywords(['invert'], colorType),
|
||
outlineOffset: lengthType,
|
||
outlineWidth: lengthType,
|
||
paddingBottom: lengthType,
|
||
paddingLeft: lengthType,
|
||
paddingRight: lengthType,
|
||
paddingTop: lengthType,
|
||
perspective: typeWithKeywords(['none'], lengthType),
|
||
perspectiveOrigin: originType,
|
||
r: lengthType,
|
||
right: percentLengthAutoType,
|
||
stopColor: colorType,
|
||
stroke: colorType,
|
||
textIndent: typeWithKeywords(['each-line', 'hanging'], percentLengthType),
|
||
textShadow: shadowType,
|
||
top: percentLengthAutoType,
|
||
transform: transformType,
|
||
transformOrigin: originType,
|
||
verticalAlign: typeWithKeywords([
|
||
'baseline',
|
||
'sub',
|
||
'super',
|
||
'text-top',
|
||
'text-bottom',
|
||
'middle',
|
||
'top',
|
||
'bottom'
|
||
], percentLengthType),
|
||
visibility: visibilityType,
|
||
width: typeWithKeywords([
|
||
'border-box',
|
||
'content-box',
|
||
'auto',
|
||
'max-content',
|
||
'min-content',
|
||
'available',
|
||
'fit-content'
|
||
], percentLengthType),
|
||
wordSpacing: typeWithKeywords(['normal'], percentLengthType),
|
||
x: lengthType,
|
||
y: lengthType,
|
||
zIndex: typeWithKeywords(['auto'], integerType)
|
||
};
|
||
|
||
var svgProperties = {
|
||
'cx': 1,
|
||
'cy': 1,
|
||
'd': 1,
|
||
'dx': 1,
|
||
'dy': 1,
|
||
'fill': 1,
|
||
'floodColor': 1,
|
||
'height': 1,
|
||
'lightingColor': 1,
|
||
'r': 1,
|
||
'stopColor': 1,
|
||
'stroke': 1,
|
||
'width': 1,
|
||
'x': 1,
|
||
'y': 1
|
||
};
|
||
|
||
var borderWidthAliases = {
|
||
initial: '3px',
|
||
thin: '1px',
|
||
medium: '3px',
|
||
thick: '5px'
|
||
};
|
||
|
||
var propertyValueAliases = {
|
||
backgroundColor: { initial: 'transparent' },
|
||
backgroundPosition: { initial: '0% 0%' },
|
||
borderBottomColor: { initial: 'currentColor' },
|
||
borderBottomLeftRadius: { initial: '0px' },
|
||
borderBottomRightRadius: { initial: '0px' },
|
||
borderBottomWidth: borderWidthAliases,
|
||
borderLeftColor: { initial: 'currentColor' },
|
||
borderLeftWidth: borderWidthAliases,
|
||
borderRightColor: { initial: 'currentColor' },
|
||
borderRightWidth: borderWidthAliases,
|
||
// Spec says this should be 0 but in practise it is 2px.
|
||
borderSpacing: { initial: '2px' },
|
||
borderTopColor: { initial: 'currentColor' },
|
||
borderTopLeftRadius: { initial: '0px' },
|
||
borderTopRightRadius: { initial: '0px' },
|
||
borderTopWidth: borderWidthAliases,
|
||
bottom: { initial: 'auto' },
|
||
clip: { initial: 'rect(0px, 0px, 0px, 0px)' },
|
||
color: { initial: 'black' }, // Depends on user agent.
|
||
fontSize: {
|
||
initial: '100%',
|
||
'xx-small': '60%',
|
||
'x-small': '75%',
|
||
'small': '89%',
|
||
'medium': '100%',
|
||
'large': '120%',
|
||
'x-large': '150%',
|
||
'xx-large': '200%'
|
||
},
|
||
fontWeight: {
|
||
initial: '400',
|
||
normal: '400',
|
||
bold: '700'
|
||
},
|
||
height: { initial: 'auto' },
|
||
left: { initial: 'auto' },
|
||
letterSpacing: { initial: 'normal' },
|
||
lineHeight: {
|
||
initial: '120%',
|
||
normal: '120%'
|
||
},
|
||
marginBottom: { initial: '0px' },
|
||
marginLeft: { initial: '0px' },
|
||
marginRight: { initial: '0px' },
|
||
marginTop: { initial: '0px' },
|
||
maxHeight: { initial: 'none' },
|
||
maxWidth: { initial: 'none' },
|
||
minHeight: { initial: '0px' },
|
||
minWidth: { initial: '0px' },
|
||
opacity: { initial: '1.0' },
|
||
outlineColor: { initial: 'invert' },
|
||
outlineOffset: { initial: '0px' },
|
||
outlineWidth: borderWidthAliases,
|
||
paddingBottom: { initial: '0px' },
|
||
paddingLeft: { initial: '0px' },
|
||
paddingRight: { initial: '0px' },
|
||
paddingTop: { initial: '0px' },
|
||
right: { initial: 'auto' },
|
||
textIndent: { initial: '0px' },
|
||
textShadow: {
|
||
initial: '0px 0px 0px transparent',
|
||
none: '0px 0px 0px transparent'
|
||
},
|
||
top: { initial: 'auto' },
|
||
transform: {
|
||
initial: '',
|
||
none: ''
|
||
},
|
||
verticalAlign: { initial: '0px' },
|
||
visibility: { initial: 'visible' },
|
||
width: { initial: 'auto' },
|
||
wordSpacing: { initial: 'normal' },
|
||
zIndex: { initial: 'auto' }
|
||
};
|
||
|
||
var propertyIsSVGAttrib = function(property, target) {
|
||
return target.namespaceURI === 'http://www.w3.org/2000/svg' &&
|
||
property in svgProperties;
|
||
};
|
||
|
||
var getType = function(property) {
|
||
return propertyTypes[property] || nonNumericType;
|
||
};
|
||
|
||
var add = function(property, base, delta) {
|
||
if (delta === rawNeutralValue) {
|
||
return base;
|
||
}
|
||
if (base === 'inherit' || delta === 'inherit') {
|
||
return nonNumericType.add(base, delta);
|
||
}
|
||
return getType(property).add(base, delta);
|
||
};
|
||
|
||
|
||
/**
|
||
* Interpolate the given property name (f*100)% of the way from 'from' to 'to'.
|
||
* 'from' and 'to' are both raw values already converted from CSS value
|
||
* strings. Requires the target element to be able to determine whether the
|
||
* given property is an SVG attribute or not, as this impacts the conversion of
|
||
* the interpolated value back into a CSS value string for transform
|
||
* translations.
|
||
*
|
||
* e.g. interpolate('transform', elem, 'rotate(40deg)', 'rotate(50deg)', 0.3);
|
||
* will return 'rotate(43deg)'.
|
||
*/
|
||
var interpolate = function(property, from, to, f) {
|
||
ASSERT_ENABLED && assert(
|
||
isDefinedAndNotNull(from) && isDefinedAndNotNull(to),
|
||
'Both to and from values should be specified for interpolation');
|
||
if (from === 'inherit' || to === 'inherit') {
|
||
return nonNumericType.interpolate(from, to, f);
|
||
}
|
||
if (f === 0) {
|
||
return from;
|
||
}
|
||
if (f === 1) {
|
||
return to;
|
||
}
|
||
return getType(property).interpolate(from, to, f);
|
||
};
|
||
|
||
|
||
/**
|
||
* Convert the provided interpolable value for the provided property to a CSS
|
||
* value string. Note that SVG transforms do not require units for translate
|
||
* or rotate values while CSS properties require 'px' or 'deg' units.
|
||
*/
|
||
var toCssValue = function(property, value, svgMode) {
|
||
if (value === 'inherit') {
|
||
return value;
|
||
}
|
||
return getType(property).toCssValue(value, svgMode);
|
||
};
|
||
|
||
var fromCssValue = function(property, value) {
|
||
if (value === cssNeutralValue) {
|
||
return rawNeutralValue;
|
||
}
|
||
if (value === 'inherit') {
|
||
return value;
|
||
}
|
||
if (property in propertyValueAliases &&
|
||
value in propertyValueAliases[property]) {
|
||
value = propertyValueAliases[property][value];
|
||
}
|
||
var result = getType(property).fromCssValue(value);
|
||
// Currently we'll hit this assert if input to the API is bad. To avoid this,
|
||
// we should eliminate invalid values when normalizing the list of keyframes.
|
||
// See the TODO in isSupportedPropertyValue().
|
||
ASSERT_ENABLED && assert(isDefinedAndNotNull(result),
|
||
'Invalid property value "' + value + '" for property "' + property + '"');
|
||
return result;
|
||
};
|
||
|
||
// Sentinel values
|
||
var cssNeutralValue = {};
|
||
var rawNeutralValue = {};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var CompositableValue = function() {
|
||
};
|
||
|
||
CompositableValue.prototype = {
|
||
compositeOnto: abstractMethod,
|
||
// This is purely an optimization.
|
||
dependsOnUnderlyingValue: function() {
|
||
return true;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AddReplaceCompositableValue = function(value, composite) {
|
||
this.value = value;
|
||
this.composite = composite;
|
||
ASSERT_ENABLED && assert(
|
||
!(this.value === cssNeutralValue && this.composite === 'replace'),
|
||
'Should never replace-composite the neutral value');
|
||
};
|
||
|
||
AddReplaceCompositableValue.prototype = createObject(
|
||
CompositableValue.prototype, {
|
||
compositeOnto: function(property, underlyingValue) {
|
||
switch (this.composite) {
|
||
case 'replace':
|
||
return this.value;
|
||
case 'add':
|
||
return add(property, underlyingValue, this.value);
|
||
default:
|
||
ASSERT_ENABLED && assert(
|
||
false, 'Invalid composite operation ' + this.composite);
|
||
}
|
||
},
|
||
dependsOnUnderlyingValue: function() {
|
||
return this.composite === 'add';
|
||
}
|
||
});
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var BlendedCompositableValue = function(startValue, endValue, fraction) {
|
||
this.startValue = startValue;
|
||
this.endValue = endValue;
|
||
this.fraction = fraction;
|
||
};
|
||
|
||
BlendedCompositableValue.prototype = createObject(
|
||
CompositableValue.prototype, {
|
||
compositeOnto: function(property, underlyingValue) {
|
||
return interpolate(property,
|
||
this.startValue.compositeOnto(property, underlyingValue),
|
||
this.endValue.compositeOnto(property, underlyingValue),
|
||
this.fraction);
|
||
},
|
||
dependsOnUnderlyingValue: function() {
|
||
// Travis crashes here randomly in Chrome beta and unstable,
|
||
// this try catch is to help debug the problem.
|
||
try {
|
||
return this.startValue.dependsOnUnderlyingValue() ||
|
||
this.endValue.dependsOnUnderlyingValue();
|
||
}
|
||
catch (error) {
|
||
throw new Error(
|
||
error + '\n JSON.stringify(this) = ' + JSON.stringify(this));
|
||
}
|
||
}
|
||
});
|
||
|
||
/** @constructor */
|
||
var CompositedPropertyMap = function(target) {
|
||
this.properties = {};
|
||
this.baseValues = {};
|
||
this.target = target;
|
||
};
|
||
|
||
CompositedPropertyMap.prototype = {
|
||
addValue: function(property, animValue) {
|
||
if (!(property in this.properties)) {
|
||
this.properties[property] = [];
|
||
}
|
||
if (!(animValue instanceof CompositableValue)) {
|
||
throw new TypeError('expected CompositableValue');
|
||
}
|
||
this.properties[property].push(animValue);
|
||
},
|
||
stackDependsOnUnderlyingValue: function(stack) {
|
||
for (var i = 0; i < stack.length; i++) {
|
||
if (!stack[i].dependsOnUnderlyingValue()) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
clear: function() {
|
||
for (var property in this.properties) {
|
||
if (this.stackDependsOnUnderlyingValue(this.properties[property])) {
|
||
clearValue(this.target, property);
|
||
}
|
||
}
|
||
},
|
||
captureBaseValues: function() {
|
||
for (var property in this.properties) {
|
||
var stack = this.properties[property];
|
||
if (stack.length > 0 && this.stackDependsOnUnderlyingValue(stack)) {
|
||
var baseValue = fromCssValue(property, getValue(this.target, property));
|
||
// TODO: Decide what to do with elements not in the DOM.
|
||
ASSERT_ENABLED && assert(
|
||
isDefinedAndNotNull(baseValue) && baseValue !== '',
|
||
'Base value should always be set. ' +
|
||
'Is the target element in the DOM?');
|
||
this.baseValues[property] = baseValue;
|
||
} else {
|
||
this.baseValues[property] = undefined;
|
||
}
|
||
}
|
||
},
|
||
applyAnimatedValues: function() {
|
||
for (var property in this.properties) {
|
||
var valuesToComposite = this.properties[property];
|
||
if (valuesToComposite.length === 0) {
|
||
continue;
|
||
}
|
||
var baseValue = this.baseValues[property];
|
||
var i = valuesToComposite.length - 1;
|
||
while (i > 0 && valuesToComposite[i].dependsOnUnderlyingValue()) {
|
||
i--;
|
||
}
|
||
for (; i < valuesToComposite.length; i++) {
|
||
baseValue = valuesToComposite[i].compositeOnto(property, baseValue);
|
||
}
|
||
ASSERT_ENABLED && assert(
|
||
isDefinedAndNotNull(baseValue) && baseValue !== '',
|
||
'Value should always be set after compositing');
|
||
var isSvgMode = propertyIsSVGAttrib(property, this.target);
|
||
setValue(this.target, property, toCssValue(property, baseValue,
|
||
isSvgMode));
|
||
this.properties[property] = [];
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
var cssStyleDeclarationAttribute = {
|
||
cssText: true,
|
||
length: true,
|
||
parentRule: true,
|
||
'var': true
|
||
};
|
||
|
||
var cssStyleDeclarationMethodModifiesStyle = {
|
||
getPropertyValue: false,
|
||
getPropertyCSSValue: false,
|
||
removeProperty: true,
|
||
getPropertyPriority: false,
|
||
setProperty: true,
|
||
item: false
|
||
};
|
||
|
||
var copyInlineStyle = function(sourceStyle, destinationStyle) {
|
||
for (var i = 0; i < sourceStyle.length; i++) {
|
||
var property = sourceStyle[i];
|
||
destinationStyle[property] = sourceStyle[property];
|
||
}
|
||
};
|
||
|
||
var retickThenGetComputedStyle = function() {
|
||
repeatLastTick();
|
||
ensureOriginalGetComputedStyle();
|
||
return window.getComputedStyle.apply(this, arguments);
|
||
};
|
||
|
||
// This redundant flag is to support Safari which has trouble determining
|
||
// function object equality during an animation.
|
||
var isGetComputedStylePatched = false;
|
||
var originalGetComputedStyle = window.getComputedStyle;
|
||
|
||
var ensureRetickBeforeGetComputedStyle = function() {
|
||
if (!isGetComputedStylePatched) {
|
||
Object.defineProperty(window, 'getComputedStyle', configureDescriptor({
|
||
value: retickThenGetComputedStyle
|
||
}));
|
||
isGetComputedStylePatched = true;
|
||
}
|
||
};
|
||
|
||
var ensureOriginalGetComputedStyle = function() {
|
||
if (isGetComputedStylePatched) {
|
||
Object.defineProperty(window, 'getComputedStyle', configureDescriptor({
|
||
value: originalGetComputedStyle
|
||
}));
|
||
isGetComputedStylePatched = false;
|
||
}
|
||
};
|
||
|
||
// Changing the inline style of an element under animation may require the
|
||
// animation to be recomputed ontop of the new inline style if
|
||
// getComputedStyle() is called inbetween setting the style and the next
|
||
// animation frame.
|
||
// We modify getComputedStyle() to re-evaluate the animations only if it is
|
||
// called instead of re-evaluating them here potentially unnecessarily.
|
||
var animatedInlineStyleChanged = function() {
|
||
maybeRestartAnimation();
|
||
ensureRetickBeforeGetComputedStyle();
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var AnimatedCSSStyleDeclaration = function(element) {
|
||
ASSERT_ENABLED && assert(
|
||
!(element.style instanceof AnimatedCSSStyleDeclaration),
|
||
'Element must not already have an animated style attached.');
|
||
|
||
// Stores the inline style of the element on its behalf while the
|
||
// polyfill uses the element's inline style to simulate web animations.
|
||
// This is needed to fake regular inline style CSSOM access on the element.
|
||
this._surrogateElement = createDummyElement();
|
||
this._style = element.style;
|
||
this._length = 0;
|
||
this._isAnimatedProperty = {};
|
||
|
||
// Populate the surrogate element's inline style.
|
||
copyInlineStyle(this._style, this._surrogateElement.style);
|
||
this._updateIndices();
|
||
};
|
||
|
||
AnimatedCSSStyleDeclaration.prototype = {
|
||
get cssText() {
|
||
return this._surrogateElement.style.cssText;
|
||
},
|
||
set cssText(text) {
|
||
var isAffectedProperty = {};
|
||
for (var i = 0; i < this._surrogateElement.style.length; i++) {
|
||
isAffectedProperty[this._surrogateElement.style[i]] = true;
|
||
}
|
||
this._surrogateElement.style.cssText = text;
|
||
this._updateIndices();
|
||
for (var i = 0; i < this._surrogateElement.style.length; i++) {
|
||
isAffectedProperty[this._surrogateElement.style[i]] = true;
|
||
}
|
||
for (var property in isAffectedProperty) {
|
||
if (!this._isAnimatedProperty[property]) {
|
||
this._style.setProperty(property,
|
||
this._surrogateElement.style.getPropertyValue(property));
|
||
}
|
||
}
|
||
animatedInlineStyleChanged();
|
||
},
|
||
get length() {
|
||
return this._surrogateElement.style.length;
|
||
},
|
||
get parentRule() {
|
||
return this._style.parentRule;
|
||
},
|
||
get 'var'() {
|
||
return this._style.var;
|
||
},
|
||
_updateIndices: function() {
|
||
while (this._length < this._surrogateElement.style.length) {
|
||
Object.defineProperty(this, this._length, {
|
||
configurable: true,
|
||
enumerable: false,
|
||
get: (function(index) {
|
||
return function() {
|
||
return this._surrogateElement.style[index];
|
||
};
|
||
})(this._length)
|
||
});
|
||
this._length++;
|
||
}
|
||
while (this._length > this._surrogateElement.style.length) {
|
||
this._length--;
|
||
Object.defineProperty(this, this._length, {
|
||
configurable: true,
|
||
enumerable: false,
|
||
value: undefined
|
||
});
|
||
}
|
||
},
|
||
_clearAnimatedProperty: function(property) {
|
||
this._style[property] = this._surrogateElement.style[property];
|
||
this._isAnimatedProperty[property] = false;
|
||
},
|
||
_setAnimatedProperty: function(property, value) {
|
||
this._style[property] = value;
|
||
this._isAnimatedProperty[property] = true;
|
||
}
|
||
};
|
||
|
||
for (var method in cssStyleDeclarationMethodModifiesStyle) {
|
||
AnimatedCSSStyleDeclaration.prototype[method] =
|
||
(function(method, modifiesStyle) {
|
||
return function() {
|
||
var result = this._surrogateElement.style[method].apply(
|
||
this._surrogateElement.style, arguments);
|
||
if (modifiesStyle) {
|
||
if (!this._isAnimatedProperty[arguments[0]]) {
|
||
this._style[method].apply(this._style, arguments);
|
||
}
|
||
this._updateIndices();
|
||
animatedInlineStyleChanged();
|
||
}
|
||
return result;
|
||
}
|
||
})(method, cssStyleDeclarationMethodModifiesStyle[method]);
|
||
}
|
||
|
||
for (var property in document.documentElement.style) {
|
||
if (cssStyleDeclarationAttribute[property] ||
|
||
property in cssStyleDeclarationMethodModifiesStyle) {
|
||
continue;
|
||
}
|
||
(function(property) {
|
||
Object.defineProperty(AnimatedCSSStyleDeclaration.prototype, property,
|
||
configureDescriptor({
|
||
get: function() {
|
||
return this._surrogateElement.style[property];
|
||
},
|
||
set: function(value) {
|
||
this._surrogateElement.style[property] = value;
|
||
this._updateIndices();
|
||
if (!this._isAnimatedProperty[property]) {
|
||
this._style[property] = value;
|
||
}
|
||
animatedInlineStyleChanged();
|
||
}
|
||
}));
|
||
})(property);
|
||
}
|
||
|
||
// This function is a fallback for when we can't replace an element's style with
|
||
// AnimatatedCSSStyleDeclaration and must patch the existing style to behave
|
||
// in a similar way.
|
||
// Only the methods listed in cssStyleDeclarationMethodModifiesStyle will
|
||
// be patched to behave in the same manner as a native implementation,
|
||
// getter properties like style.left or style[0] will be tainted by the
|
||
// polyfill's animation engine.
|
||
var patchInlineStyleForAnimation = function(style) {
|
||
var surrogateElement = document.createElement('div');
|
||
copyInlineStyle(style, surrogateElement.style);
|
||
var isAnimatedProperty = {};
|
||
for (var method in cssStyleDeclarationMethodModifiesStyle) {
|
||
if (!(method in style)) {
|
||
continue;
|
||
}
|
||
Object.defineProperty(style, method, configureDescriptor({
|
||
value: (function(method, originalMethod, modifiesStyle) {
|
||
return function() {
|
||
var result = surrogateElement.style[method].apply(
|
||
surrogateElement.style, arguments);
|
||
if (modifiesStyle) {
|
||
if (!isAnimatedProperty[arguments[0]]) {
|
||
originalMethod.apply(style, arguments);
|
||
}
|
||
animatedInlineStyleChanged();
|
||
}
|
||
return result;
|
||
}
|
||
})(method, style[method], cssStyleDeclarationMethodModifiesStyle[method])
|
||
}));
|
||
}
|
||
|
||
style._clearAnimatedProperty = function(property) {
|
||
this[property] = surrogateElement.style[property];
|
||
isAnimatedProperty[property] = false;
|
||
};
|
||
|
||
style._setAnimatedProperty = function(property, value) {
|
||
this[property] = value;
|
||
isAnimatedProperty[property] = true;
|
||
};
|
||
};
|
||
|
||
|
||
|
||
/** @constructor */
|
||
var Compositor = function() {
|
||
this.targets = [];
|
||
};
|
||
|
||
Compositor.prototype = {
|
||
setAnimatedValue: function(target, property, animValue) {
|
||
if (target !== null) {
|
||
if (target._animProperties === undefined) {
|
||
target._animProperties = new CompositedPropertyMap(target);
|
||
this.targets.push(target);
|
||
}
|
||
target._animProperties.addValue(property, animValue);
|
||
}
|
||
},
|
||
applyAnimatedValues: function() {
|
||
for (var i = 0; i < this.targets.length; i++) {
|
||
this.targets[i]._animProperties.clear();
|
||
}
|
||
for (var i = 0; i < this.targets.length; i++) {
|
||
this.targets[i]._animProperties.captureBaseValues();
|
||
}
|
||
for (var i = 0; i < this.targets.length; i++) {
|
||
this.targets[i]._animProperties.applyAnimatedValues();
|
||
}
|
||
}
|
||
};
|
||
|
||
var ensureTargetInitialised = function(property, target) {
|
||
if (propertyIsSVGAttrib(property, target)) {
|
||
ensureTargetSVGInitialised(property, target);
|
||
} else {
|
||
ensureTargetCSSInitialised(target);
|
||
}
|
||
};
|
||
|
||
var ensureTargetSVGInitialised = function(property, target) {
|
||
if (!isDefinedAndNotNull(target._actuals)) {
|
||
target._actuals = {};
|
||
target._bases = {};
|
||
target.actuals = {};
|
||
target._getAttribute = target.getAttribute;
|
||
target._setAttribute = target.setAttribute;
|
||
target.getAttribute = function(name) {
|
||
if (isDefinedAndNotNull(target._bases[name])) {
|
||
return target._bases[name];
|
||
}
|
||
return target._getAttribute(name);
|
||
};
|
||
target.setAttribute = function(name, value) {
|
||
if (isDefinedAndNotNull(target._actuals[name])) {
|
||
target._bases[name] = value;
|
||
} else {
|
||
target._setAttribute(name, value);
|
||
}
|
||
};
|
||
}
|
||
if (!isDefinedAndNotNull(target._actuals[property])) {
|
||
var baseVal = target.getAttribute(property);
|
||
target._actuals[property] = 0;
|
||
target._bases[property] = baseVal;
|
||
|
||
Object.defineProperty(target.actuals, property, configureDescriptor({
|
||
set: function(value) {
|
||
if (value === null) {
|
||
target._actuals[property] = target._bases[property];
|
||
target._setAttribute(property, target._bases[property]);
|
||
} else {
|
||
target._actuals[property] = value;
|
||
target._setAttribute(property, value);
|
||
}
|
||
},
|
||
get: function() {
|
||
return target._actuals[property];
|
||
}
|
||
}));
|
||
}
|
||
};
|
||
|
||
var ensureTargetCSSInitialised = function(target) {
|
||
if (target.style._webAnimationsStyleInitialised) {
|
||
return;
|
||
}
|
||
try {
|
||
var animatedStyle = new AnimatedCSSStyleDeclaration(target);
|
||
Object.defineProperty(target, 'style', configureDescriptor({
|
||
get: function() { return animatedStyle; }
|
||
}));
|
||
} catch (error) {
|
||
patchInlineStyleForAnimation(target.style);
|
||
}
|
||
target.style._webAnimationsStyleInitialised = true;
|
||
};
|
||
|
||
var setValue = function(target, property, value) {
|
||
ensureTargetInitialised(property, target);
|
||
property = prefixProperty(property);
|
||
if (propertyIsSVGAttrib(property, target)) {
|
||
target.actuals[property] = value;
|
||
} else {
|
||
target.style._setAnimatedProperty(property, value);
|
||
}
|
||
};
|
||
|
||
var clearValue = function(target, property) {
|
||
ensureTargetInitialised(property, target);
|
||
property = prefixProperty(property);
|
||
if (propertyIsSVGAttrib(property, target)) {
|
||
target.actuals[property] = null;
|
||
} else {
|
||
target.style._clearAnimatedProperty(property);
|
||
}
|
||
};
|
||
|
||
var getValue = function(target, property) {
|
||
ensureTargetInitialised(property, target);
|
||
property = prefixProperty(property);
|
||
if (propertyIsSVGAttrib(property, target)) {
|
||
return target.actuals[property];
|
||
} else {
|
||
return getComputedStyle(target)[property];
|
||
}
|
||
};
|
||
|
||
var rafScheduled = false;
|
||
|
||
var compositor = new Compositor();
|
||
|
||
var usePerformanceTiming =
|
||
typeof window.performance === 'object' &&
|
||
typeof window.performance.timing === 'object' &&
|
||
typeof window.performance.now === 'function';
|
||
|
||
// Don't use a local named requestAnimationFrame, to avoid potential problems
|
||
// with hoisting.
|
||
var nativeRaf = window.requestAnimationFrame ||
|
||
window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
|
||
var raf;
|
||
if (nativeRaf) {
|
||
raf = function(callback) {
|
||
nativeRaf(function() {
|
||
callback(clockMillis());
|
||
});
|
||
};
|
||
} else {
|
||
raf = function(callback) {
|
||
setTimeout(function() {
|
||
callback(clockMillis());
|
||
}, 1000 / 60);
|
||
};
|
||
}
|
||
|
||
var clockMillis = function() {
|
||
return usePerformanceTiming ? window.performance.now() : Date.now();
|
||
};
|
||
// Set up the zero times for document time. Document time is relative to the
|
||
// document load event.
|
||
var documentTimeZeroAsRafTime;
|
||
var documentTimeZeroAsClockTime;
|
||
var load;
|
||
if (usePerformanceTiming) {
|
||
load = function() {
|
||
// RAF time is relative to the navigationStart event.
|
||
documentTimeZeroAsRafTime =
|
||
window.performance.timing.loadEventStart -
|
||
window.performance.timing.navigationStart;
|
||
// performance.now() uses the same origin as RAF time.
|
||
documentTimeZeroAsClockTime = documentTimeZeroAsRafTime;
|
||
};
|
||
} else {
|
||
// The best approximation we have for the relevant clock and RAF times is to
|
||
// listen to the load event.
|
||
load = function() {
|
||
raf(function(rafTime) {
|
||
documentTimeZeroAsRafTime = rafTime;
|
||
});
|
||
documentTimeZeroAsClockTime = Date.now();
|
||
};
|
||
}
|
||
// Start timing when load event fires or if this script is processed when
|
||
// document loading is already complete.
|
||
if (document.readyState === 'complete') {
|
||
// When performance timing is unavailable and this script is loaded
|
||
// dynamically, document zero time is incorrect.
|
||
// Warn the user in this case.
|
||
if (!usePerformanceTiming) {
|
||
console.warn(
|
||
'Web animations can\'t discover document zero time when ' +
|
||
'asynchronously loaded in the absence of performance timing.');
|
||
}
|
||
load();
|
||
} else {
|
||
addEventListener('load', function() {
|
||
load();
|
||
if (usePerformanceTiming) {
|
||
// We use setTimeout() to clear cachedClockTimeMillis at the end of a
|
||
// frame, but this will not run until after other load handlers. We need
|
||
// those handlers to pick up the new value of clockMillis(), so we must
|
||
// clear the cached value.
|
||
cachedClockTimeMillis = undefined;
|
||
}
|
||
});
|
||
}
|
||
|
||
// A cached document time for use during the current callstack.
|
||
var cachedClockTimeMillis;
|
||
// Calculates one time relative to another, returning null if the zero time is
|
||
// undefined.
|
||
var relativeTime = function(time, zeroTime) {
|
||
return isDefined(zeroTime) ? time - zeroTime : null;
|
||
};
|
||
|
||
var lastClockTimeMillis;
|
||
|
||
var cachedClockTime = function() {
|
||
// Cache a document time for the remainder of this callstack.
|
||
if (!isDefined(cachedClockTimeMillis)) {
|
||
cachedClockTimeMillis = clockMillis();
|
||
lastClockTimeMillis = cachedClockTimeMillis;
|
||
setTimeout(function() { cachedClockTimeMillis = undefined; }, 0);
|
||
}
|
||
return cachedClockTimeMillis;
|
||
};
|
||
|
||
|
||
// These functions should be called in every stack that could possibly modify
|
||
// the effect results that have already been calculated for the current tick.
|
||
var modifyCurrentAnimationStateDepth = 0;
|
||
var enterModifyCurrentAnimationState = function() {
|
||
modifyCurrentAnimationStateDepth++;
|
||
};
|
||
var exitModifyCurrentAnimationState = function(updateCallback) {
|
||
modifyCurrentAnimationStateDepth--;
|
||
// updateCallback is set to null when we know we can't possibly affect the
|
||
// current state (eg. a TimedItem which is not attached to a player). We track
|
||
// the depth of recursive calls trigger just one repeat per entry. Only the
|
||
// updateCallback from the outermost call is considered, this allows certain
|
||
// locatations (eg. constructors) to override nested calls that would
|
||
// otherwise set updateCallback unconditionally.
|
||
if (modifyCurrentAnimationStateDepth === 0 && updateCallback) {
|
||
updateCallback();
|
||
}
|
||
};
|
||
|
||
var repeatLastTick = function() {
|
||
if (isDefined(lastTickTime)) {
|
||
ticker(lastTickTime, true);
|
||
}
|
||
};
|
||
|
||
var playerSortFunction = function(a, b) {
|
||
var result = a.startTime - b.startTime;
|
||
return result !== 0 ? result : a._sequenceNumber - b._sequenceNumber;
|
||
};
|
||
|
||
var lastTickTime;
|
||
var ticker = function(rafTime, isRepeat) {
|
||
// Don't tick till the page is loaded....
|
||
if (!isDefined(documentTimeZeroAsRafTime)) {
|
||
raf(ticker);
|
||
return;
|
||
}
|
||
|
||
if (!isRepeat) {
|
||
if (rafTime < lastClockTimeMillis) {
|
||
rafTime = lastClockTimeMillis;
|
||
}
|
||
lastTickTime = rafTime;
|
||
cachedClockTimeMillis = rafTime;
|
||
}
|
||
|
||
// Clear any modifications to getComputedStyle.
|
||
ensureOriginalGetComputedStyle();
|
||
|
||
// Get animations for this sample. We order by AnimationPlayer then by DFS
|
||
// order within each AnimationPlayer's tree.
|
||
if (!playersAreSorted) {
|
||
PLAYERS.sort(playerSortFunction);
|
||
playersAreSorted = true;
|
||
}
|
||
var finished = true;
|
||
var paused = true;
|
||
var animations = [];
|
||
var finishedPlayers = [];
|
||
PLAYERS.forEach(function(player) {
|
||
player._update();
|
||
finished = finished && !player._hasFutureAnimation();
|
||
if (!player._hasFutureEffect()) {
|
||
finishedPlayers.push(player);
|
||
}
|
||
paused = paused && player.paused;
|
||
player._getLeafItemsInEffect(animations);
|
||
});
|
||
|
||
// Apply animations in order
|
||
for (var i = 0; i < animations.length; i++) {
|
||
if (animations[i] instanceof Animation) {
|
||
animations[i]._sample();
|
||
}
|
||
}
|
||
|
||
// Generate events
|
||
PLAYERS.forEach(function(player) {
|
||
player._generateEvents();
|
||
});
|
||
|
||
// Remove finished players. Warning: _deregisterFromTimeline modifies
|
||
// the PLAYER list. It should not be called from within a PLAYERS.forEach
|
||
// loop directly.
|
||
finishedPlayers.forEach(function(player) {
|
||
player._deregisterFromTimeline();
|
||
playersAreSorted = false;
|
||
});
|
||
|
||
// Composite animated values into element styles
|
||
compositor.applyAnimatedValues();
|
||
|
||
if (!isRepeat) {
|
||
if (finished || paused) {
|
||
rafScheduled = false;
|
||
} else {
|
||
raf(ticker);
|
||
}
|
||
cachedClockTimeMillis = undefined;
|
||
}
|
||
};
|
||
|
||
// Multiplication where zero multiplied by any value (including infinity)
|
||
// gives zero.
|
||
var multiplyZeroGivesZero = function(a, b) {
|
||
return (a === 0 || b === 0) ? 0 : a * b;
|
||
};
|
||
|
||
var maybeRestartAnimation = function() {
|
||
if (rafScheduled) {
|
||
return;
|
||
}
|
||
raf(ticker);
|
||
rafScheduled = true;
|
||
};
|
||
|
||
var DOCUMENT_TIMELINE = new AnimationTimeline(constructorToken);
|
||
// attempt to override native implementation
|
||
try {
|
||
Object.defineProperty(document, 'timeline', {
|
||
configurable: true,
|
||
get: function() { return DOCUMENT_TIMELINE }
|
||
});
|
||
} catch (e) { }
|
||
// maintain support for Safari
|
||
try {
|
||
document.timeline = DOCUMENT_TIMELINE;
|
||
} catch (e) { }
|
||
|
||
window.Element.prototype.animate = function(effect, timing) {
|
||
var anim = new Animation(this, effect, timing);
|
||
DOCUMENT_TIMELINE.play(anim);
|
||
return anim.player;
|
||
};
|
||
window.Element.prototype.getCurrentPlayers = function() {
|
||
return PLAYERS.filter((function(player) {
|
||
return player._isCurrent() && player._isTargetingElement(this);
|
||
}).bind(this));
|
||
};
|
||
window.Element.prototype.getCurrentAnimations = function() {
|
||
var animations = [];
|
||
PLAYERS.forEach((function(player) {
|
||
if (player._isCurrent()) {
|
||
player._getAnimationsTargetingElement(this, animations);
|
||
}
|
||
}).bind(this));
|
||
return animations;
|
||
};
|
||
|
||
window.Animation = Animation;
|
||
window.AnimationEffect = AnimationEffect;
|
||
window.AnimationGroup = AnimationGroup;
|
||
window.AnimationPlayer = AnimationPlayer;
|
||
window.AnimationSequence = AnimationSequence;
|
||
window.AnimationTimeline = AnimationTimeline;
|
||
window.KeyframeEffect = KeyframeEffect;
|
||
window.MediaReference = MediaReference;
|
||
window.MotionPathEffect = MotionPathEffect;
|
||
window.PseudoElementReference = PseudoElementReference;
|
||
window.TimedItem = TimedItem;
|
||
window.TimedItemList = TimedItemList;
|
||
window.Timing = Timing;
|
||
window.TimingEvent = TimingEvent;
|
||
window.TimingGroup = TimingGroup;
|
||
|
||
window._WebAnimationsTestingUtilities = {
|
||
_constructorToken: constructorToken,
|
||
_deprecated: deprecated,
|
||
_positionListType: positionListType,
|
||
_hsl2rgb: hsl2rgb,
|
||
_types: propertyTypes,
|
||
_knownPlayers: PLAYERS,
|
||
_pacedTimingFunction: PacedTimingFunction,
|
||
_prefixProperty: prefixProperty,
|
||
_propertyIsSVGAttrib: propertyIsSVGAttrib
|
||
};
|
||
|
||
})();
|
||
</script>
|
||
|
||
<polymer-element name="paper-menu-button-transition" extends="core-transition-css" attributes="duration transformOrigin" assetpath="polymer/bower_components/paper-menu-button/">
|
||
<template>
|
||
<style no-shim="">/* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */
|
||
|
||
:host(.paper-menu-button-transition) {
|
||
outline: none;
|
||
opacity: 0;
|
||
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in;
|
||
-webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in;
|
||
}
|
||
|
||
:host(.paper-menu-button-transition.paper-menu-button-opened) {
|
||
opacity: 1;
|
||
transform: none;
|
||
-webkit-transform: none;
|
||
}
|
||
</style>
|
||
</template>
|
||
<script>
|
||
Polymer('paper-menu-button-transition', {
|
||
|
||
baseClass: 'paper-menu-button-transition',
|
||
revealedClass: 'paper-menu-button-revealed',
|
||
openedClass: 'paper-menu-button-opened',
|
||
closedClass: 'paper-menu-button-closed',
|
||
completeEventName: null,
|
||
|
||
duration: 500,
|
||
|
||
setup: function(node) {
|
||
this.super(arguments);
|
||
|
||
var bg = node.querySelector('.paper-menu-button-overlay-bg');
|
||
bg.style.transformOrigin = this.transformOrigin;
|
||
bg.style.webkitTransformOrigin = this.transformOrigin;
|
||
},
|
||
|
||
transitionOpened: function(node, opened) {
|
||
this.super(arguments);
|
||
|
||
if (opened) {
|
||
if (this.player) {
|
||
this.player.cancel();
|
||
}
|
||
|
||
var anims = [];
|
||
|
||
var size = node.getBoundingClientRect();
|
||
|
||
var ink = node.querySelector('.paper-menu-button-overlay-ink');
|
||
var offset = 40 / Math.max(size.width, size.height);
|
||
anims.push(new Animation(ink, [{
|
||
'opacity': 0.9,
|
||
'transform': 'scale(0)',
|
||
}, {
|
||
'opacity': 0.9,
|
||
'transform': 'scale(1)'
|
||
}], {
|
||
duration: this.duration * offset
|
||
}));
|
||
|
||
var bg = node.querySelector('.paper-menu-button-overlay-bg');
|
||
anims.push(new Animation(bg, [{
|
||
'opacity': 0.9,
|
||
'transform': 'scale(' + 40 / size.width + ',' + 40 / size.height + ')',
|
||
}, {
|
||
'opacity': 1,
|
||
'transform': 'scale(0.95, 0.5)'
|
||
}, {
|
||
'opacity': 1,
|
||
'transform': 'scale(1, 1)'
|
||
}], {
|
||
delay: this.duration * offset,
|
||
duration: this.duration * (1 - offset),
|
||
fill: 'forwards'
|
||
}));
|
||
|
||
var items = node.querySelector('#menu').items;
|
||
var itemDelay = offset + (1 - offset) / 2;
|
||
var itemDuration = this.duration * (1 - itemDelay) / items.length;
|
||
var reverse = this.transformOrigin.split(' ')[1] === '100%';
|
||
items.forEach(function(item, i) {
|
||
if (!item.classList.contains('paper-menu-button-overlay-bg') && !item.classList.contains('paper-menu-button-overlay-ink')) {
|
||
anims.push(new Animation(item, [{
|
||
'opacity': 0
|
||
}, {
|
||
'opacity': 1
|
||
}], {
|
||
delay: this.duration * itemDelay + itemDuration * (reverse ? items.length - 1 - i : i),
|
||
duration: itemDuration,
|
||
fill: 'both'
|
||
}));
|
||
}
|
||
}.bind(this));
|
||
|
||
var group = new AnimationGroup(anims, {
|
||
easing: 'cubic-bezier(0.4, 0, 0.2, 1)'
|
||
});
|
||
this.player = document.timeline.play(group);
|
||
this.player.onfinish = function() {
|
||
this.fire('core-transitionend', this, node);
|
||
}.bind(this);
|
||
|
||
} else {
|
||
this.listenOnce(node, 'transitionend', function() {
|
||
this.fire('core-transitionend', this, node);
|
||
}.bind(this));
|
||
}
|
||
},
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<paper-menu-button-transition id="paper-menu-button-transition-top-left" transformorigin="0% 0%"></paper-menu-button-transition>
|
||
<paper-menu-button-transition id="paper-menu-button-transition-top-right" transformorigin="100% 0%"></paper-menu-button-transition>
|
||
<paper-menu-button-transition id="paper-menu-button-transition-top-right-slow" transformorigin="100% 0%" duration="10000"></paper-menu-button-transition>
|
||
|
||
<paper-menu-button-transition id="paper-menu-button-transition-bottom-left" transformorigin="0% 100%"></paper-menu-button-transition>
|
||
<paper-menu-button-transition id="paper-menu-button-transition-bottom-right" transformorigin="100% 100%"></paper-menu-button-transition>
|
||
|
||
|
||
<core-style id="paper-menu-button">
|
||
|
||
.paper-menu-button-overlay-ink {
|
||
background: {{g.paperMenuButton.background}}
|
||
}
|
||
|
||
.paper-menu-button-overlay-bg {
|
||
background: {{g.paperMenuButton.background}}
|
||
}
|
||
|
||
</core-style>
|
||
|
||
<script>
|
||
(function() {
|
||
|
||
CoreStyle.g.paperMenuButton = CoreStyle.g.paperMenuButton || {
|
||
'background': '#fff'
|
||
};
|
||
|
||
})();
|
||
</script>
|
||
|
||
<polymer-element name="paper-menu-button" extends="paper-focusable" attributes="src icon opened halign valign slow" assetpath="polymer/bower_components/paper-menu-button/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright 2013 The Polymer Authors. All rights reserved.
|
||
Use of this source code is governed by a BSD-style
|
||
license that can be found in the LICENSE file.
|
||
*/
|
||
|
||
:host {
|
||
display: inline-block;
|
||
padding: 8px;
|
||
position: relative;
|
||
background-image: none;
|
||
outline: none;
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
cursor: pointer;
|
||
}
|
||
|
||
:host([disabled]) {
|
||
cursor: auto;
|
||
}
|
||
|
||
core-icon {
|
||
position: relative;
|
||
}
|
||
|
||
core-icon::shadow svg {
|
||
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
-webkit-transition: -webkit-transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
transform-origin: 50% 50%;
|
||
-webkit-transform-origin: 50% 50%;
|
||
}
|
||
|
||
:host(:hover) core-icon::shadow svg {
|
||
transform: scale(1.2);
|
||
-webkit-transform: scale(1.2);
|
||
}
|
||
|
||
:host([disabled]:hover) core-icon::shadow svg {
|
||
transform: none;
|
||
-webkit-transform: none;
|
||
}
|
||
|
||
:host([disabled]) core-icon::shadow path {
|
||
fill: #c9c9c9;
|
||
}
|
||
|
||
#dropdown {
|
||
background-color: transparent;
|
||
margin: 12px;
|
||
color: #000;
|
||
}
|
||
|
||
#menu {
|
||
padding-top: 8px;
|
||
padding-bottom: 8px;
|
||
margin: 0;
|
||
}
|
||
|
||
.paper-menu-button-overlay-ink {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 20px;
|
||
opacity: 0;
|
||
transform: scale(0);
|
||
-webkit-transform: scale(0);
|
||
}
|
||
|
||
:host([halign="right"]) .paper-menu-button-overlay-ink {
|
||
left: auto;
|
||
right: 0;
|
||
}
|
||
|
||
:host([valign="bottom"]) .paper-menu-button-overlay-ink {
|
||
top: auto;
|
||
bottom: 0;
|
||
}
|
||
|
||
.paper-menu-button-overlay-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
bottom: 0;
|
||
right: 0;
|
||
border-radius: 3px;
|
||
opacity: 0;
|
||
z-index: -1;
|
||
}
|
||
|
||
:host([noTransition]) .paper-menu-button-overlay-bg {
|
||
opacity: 1;
|
||
}
|
||
|
||
.paper-menu-button-menu-container {
|
||
overflow: auto;
|
||
max-height: 100%;
|
||
max-width: 100%;
|
||
}</style>
|
||
<core-style ref="paper-menu-button"></core-style>
|
||
|
||
<core-icon src="{{src}}" icon="{{icon}}" on-tap="{{tapAction}}"></core-icon>
|
||
|
||
<core-dropdown id="dropdown" relatedtarget="{{}}" opened="{{opened}}" halign="{{halign}}" valign="{{valign}}" transition="{{noTransition ? '' : transition}}" on-core-transitionend="{{transitionEndAction}}">
|
||
|
||
<paper-shadow id="shadow" z="1" target="{{$.dropdown}}"></paper-shadow>
|
||
|
||
<div class="paper-menu-button-overlay-ink"></div>
|
||
<div id="overlayBg" class="paper-menu-button-overlay-bg"></div>
|
||
|
||
<div class="paper-menu-button-menu-container">
|
||
<core-menu id="menu" selected="{{selected}}" selecteditem="{{selectedItem}}" selectedclass="{{selectedClass}}" valueattr="{{valueattr}}" selectedproperty="{{selectedProperty}}" selectedattribute="{{selectedAttribute}}" on-core-select="{{selectAction}}" on-core-activate="{{activateAction}}">
|
||
<content></content>
|
||
</core-menu>
|
||
</div>
|
||
|
||
</core-dropdown>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('paper-menu-button', {
|
||
|
||
publish: {
|
||
|
||
/**
|
||
* If true, this menu is currently visible.
|
||
*
|
||
* @attribute opened
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
opened: false,
|
||
|
||
/**
|
||
* The horizontal alignment of the menu relative to the button.
|
||
*
|
||
* @attribute halign
|
||
* @type 'left' | 'right'
|
||
* @default 'left'
|
||
*/
|
||
halign: 'left',
|
||
|
||
/**
|
||
* The vertical alignment of the menu relative to the button.
|
||
*
|
||
* @attribute valign
|
||
* @type 'bottom' | 'top'
|
||
* @default 'top'
|
||
*/
|
||
valign: 'top',
|
||
|
||
/**
|
||
* Set to true to disable the transition.
|
||
*
|
||
* @attribute noTransition
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
noTransition: false
|
||
|
||
},
|
||
|
||
computed: {
|
||
transition: '"paper-menu-button-transition-" + valign + "-" + halign'
|
||
},
|
||
|
||
/**
|
||
* The URL of an image for the icon. Should not use `icon` property
|
||
* if you are using this property.
|
||
*
|
||
* @attribute src
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
src: '',
|
||
|
||
/**
|
||
* Specifies the icon name or index in the set of icons available in
|
||
* the icon set. Should not use `src` property if you are using this
|
||
* property.
|
||
*
|
||
* @attribute icon
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
icon: '',
|
||
|
||
tapAction: function() {
|
||
if (this.disabled) {
|
||
return;
|
||
}
|
||
|
||
this.super();
|
||
this.toggle();
|
||
if (this.opened && !this.noTransition) {
|
||
this.$.shadow.z = 0;
|
||
}
|
||
},
|
||
|
||
transitionEndAction: function() {
|
||
this.$.shadow.z = 1;
|
||
},
|
||
|
||
activateAction: function() {
|
||
this.opened = false;
|
||
},
|
||
|
||
/**
|
||
* Toggle the opened state of the menu.
|
||
*
|
||
* @method toggle
|
||
*/
|
||
toggle: function() {
|
||
this.opened = !this.opened;
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`paper-tabs` is a `core-selector` styled to look like tabs. Tabs make it easy to
|
||
explore and switch between different views or functional aspects of an app, or
|
||
to browse categorized data sets.
|
||
|
||
Use `selected` property to get or set the selected tab.
|
||
|
||
Example:
|
||
|
||
<paper-tabs selected="0">
|
||
<paper-tab>TAB 1</paper-tab>
|
||
<paper-tab>TAB 2</paper-tab>
|
||
<paper-tab>TAB 3</paper-tab>
|
||
</paper-tabs>
|
||
|
||
See <a href="#paper-tab">paper-tab</a> for more information about
|
||
`paper-tab`.
|
||
|
||
Styling tabs:
|
||
|
||
To change the sliding bar color:
|
||
|
||
paper-tabs.pink::shadow #selectionBar {
|
||
background-color: #ff4081;
|
||
}
|
||
|
||
@group Paper Elements
|
||
@element paper-tabs
|
||
@extends core-selector
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`paper-tab` is styled to look like a tab. It should be used in conjunction with
|
||
`paper-tabs`.
|
||
|
||
Example:
|
||
|
||
<paper-tabs selected="0">
|
||
<paper-tab>TAB 1</paper-tab>
|
||
<paper-tab>TAB 2</paper-tab>
|
||
<paper-tab>TAB 3</paper-tab>
|
||
</paper-tabs>
|
||
|
||
Styling tab:
|
||
|
||
To change the ink color:
|
||
|
||
.pink paper-tab::shadow #ink {
|
||
color: #ff4081;
|
||
}
|
||
|
||
@group Paper Elements
|
||
@element paper-tab
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="paper-tab" attributes="noink" role="tab" assetpath="polymer/bower_components/paper-tabs/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: block;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#tabContainer {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
.tab-content {
|
||
transition: opacity .1s cubic-bezier(0.4, 0.0, 1, 1), color .1s cubic-bezier(0.4, 0.0, 1, 1);
|
||
cursor: default;
|
||
pointer-events: none;
|
||
}
|
||
|
||
:host(:not(.core-selected)) .tab-content {
|
||
opacity: 0.6;
|
||
}
|
||
|
||
#ink {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
color: #ffff8d;
|
||
}
|
||
|
||
:host[noink] #ink {
|
||
pointer-events: none;
|
||
}
|
||
|
||
:host-context(paper-tabs[noink]) #ink {
|
||
pointer-events: none;
|
||
}
|
||
</style>
|
||
|
||
<div id="tabContainer" center-justified="" center="" horizontal="" layout="">
|
||
|
||
<div class="tab-content"><content></content></div>
|
||
<paper-ripple id="ink" initialopacity="0.95" opacitydecayvelocity="0.98"></paper-ripple>
|
||
|
||
</div>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('paper-tab', {
|
||
|
||
/**
|
||
* If true, ink ripple effect is disabled.
|
||
*
|
||
* @attribute noink
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
noink: false
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="paper-tabs" extends="core-selector" attributes="noink nobar" role="tablist" assetpath="polymer/bower_components/paper-tabs/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: block;
|
||
position: relative;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
height: 48px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#tabsContainer {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#selectionBar {
|
||
position: absolute;
|
||
height: 2px;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 0;
|
||
background-color: #ffff8d;
|
||
transition: width, left;
|
||
}
|
||
|
||
#selectionBar[hidden] {
|
||
display: hidden;
|
||
}
|
||
|
||
#selectionBar.expand {
|
||
transition-duration: 0.15s;
|
||
transition-timing-function: cubic-bezier(0.4, 0.0, 1, 1);
|
||
}
|
||
|
||
#selectionBar.contract {
|
||
transition-duration: 0.18s;
|
||
transition-timing-function: cubic-bezier(0.0, 0.0, 0.2, 1);
|
||
}
|
||
|
||
polyfill-next-selector { content: '#tabsContainer > *:not(#selectionBar)'; }
|
||
::content > * {
|
||
-ms-flex: 1;
|
||
-webkit-flex: 1;
|
||
flex: 1;
|
||
}
|
||
</style>
|
||
|
||
<div id="tabsContainer" horizontal="" layout="">
|
||
|
||
<shadow></shadow>
|
||
<div id="selectionBar" hidden?="{{nobar}}" on-transitionend="{{barTransitionEnd}}"></div>
|
||
|
||
</div>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('paper-tabs', {
|
||
|
||
/**
|
||
* If true, ink effect is disabled.
|
||
*
|
||
* @attribute noink
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
noink: false,
|
||
|
||
/**
|
||
* If true, the bottom bar to indicate the selected tab will not be shown.
|
||
*
|
||
* @attribute nobar
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
nobar: false,
|
||
|
||
activateEvent: 'down',
|
||
|
||
nostretch: false,
|
||
|
||
selectedIndexChanged: function(old) {
|
||
var s = this.$.selectionBar.style;
|
||
|
||
if (!this.selectedItem) {
|
||
s.width = 0;
|
||
s.left = 0;
|
||
return;
|
||
}
|
||
|
||
var w = 100 / this.items.length;
|
||
|
||
if (this.nostretch || old === null || old === -1) {
|
||
s.width = w + '%';
|
||
s.left = this.selectedIndex * w + '%';
|
||
return;
|
||
}
|
||
|
||
var m = 5;
|
||
this.$.selectionBar.classList.add('expand');
|
||
if (old < this.selectedIndex) {
|
||
s.width = w + w * (this.selectedIndex - old) - m + '%';
|
||
this._transitionCounter = 1;
|
||
} else {
|
||
s.width = w + w * (old - this.selectedIndex) - m + '%';
|
||
s.left = this.selectedIndex * w + m + '%';
|
||
this._transitionCounter = 2;
|
||
}
|
||
},
|
||
|
||
barTransitionEnd: function(e) {
|
||
this._transitionCounter--;
|
||
var cl = this.$.selectionBar.classList;
|
||
if (cl.contains('expand') && !this._transitionCounter) {
|
||
cl.remove('expand');
|
||
cl.add('contract');
|
||
var s = this.$.selectionBar.style;
|
||
var w = 100 / this.items.length;
|
||
s.width = w + '%';
|
||
s.left = this.selectedIndex * w + '%';
|
||
} else if (cl.contains('contract')) {
|
||
cl.remove('contract');
|
||
}
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
|
||
|
||
<script>//! moment.js
|
||
//! version : 2.8.3
|
||
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
|
||
//! license : MIT
|
||
//! momentjs.com
|
||
|
||
(function (undefined) {
|
||
/************************************
|
||
Constants
|
||
************************************/
|
||
|
||
var moment,
|
||
VERSION = '2.8.3',
|
||
// the global-scope this is NOT the global object in Node.js
|
||
globalScope = typeof global !== 'undefined' ? global : this,
|
||
oldGlobalMoment,
|
||
round = Math.round,
|
||
hasOwnProperty = Object.prototype.hasOwnProperty,
|
||
i,
|
||
|
||
YEAR = 0,
|
||
MONTH = 1,
|
||
DATE = 2,
|
||
HOUR = 3,
|
||
MINUTE = 4,
|
||
SECOND = 5,
|
||
MILLISECOND = 6,
|
||
|
||
// internal storage for locale config files
|
||
locales = {},
|
||
|
||
// extra moment internal properties (plugins register props here)
|
||
momentProperties = [],
|
||
|
||
// check for nodeJS
|
||
hasModule = (typeof module !== 'undefined' && module.exports),
|
||
|
||
// ASP.NET json date format regex
|
||
aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
|
||
aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
|
||
|
||
// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
|
||
// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
|
||
isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
|
||
|
||
// format tokens
|
||
formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,
|
||
localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
|
||
|
||
// parsing token regexes
|
||
parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
|
||
parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
|
||
parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
|
||
parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
|
||
parseTokenDigits = /\d+/, // nonzero number of digits
|
||
parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
|
||
parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
|
||
parseTokenT = /T/i, // T (ISO separator)
|
||
parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
|
||
parseTokenOrdinal = /\d{1,2}/,
|
||
|
||
//strict parsing regexes
|
||
parseTokenOneDigit = /\d/, // 0 - 9
|
||
parseTokenTwoDigits = /\d\d/, // 00 - 99
|
||
parseTokenThreeDigits = /\d{3}/, // 000 - 999
|
||
parseTokenFourDigits = /\d{4}/, // 0000 - 9999
|
||
parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999
|
||
parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf
|
||
|
||
// iso 8601 regex
|
||
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
|
||
isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
|
||
|
||
isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
|
||
|
||
isoDates = [
|
||
['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
|
||
['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
|
||
['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
|
||
['GGGG-[W]WW', /\d{4}-W\d{2}/],
|
||
['YYYY-DDD', /\d{4}-\d{3}/]
|
||
],
|
||
|
||
// iso time formats and regexes
|
||
isoTimes = [
|
||
['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/],
|
||
['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
|
||
['HH:mm', /(T| )\d\d:\d\d/],
|
||
['HH', /(T| )\d\d/]
|
||
],
|
||
|
||
// timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-15', '30']
|
||
parseTimezoneChunker = /([\+\-]|\d\d)/gi,
|
||
|
||
// getter and setter names
|
||
proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
|
||
unitMillisecondFactors = {
|
||
'Milliseconds' : 1,
|
||
'Seconds' : 1e3,
|
||
'Minutes' : 6e4,
|
||
'Hours' : 36e5,
|
||
'Days' : 864e5,
|
||
'Months' : 2592e6,
|
||
'Years' : 31536e6
|
||
},
|
||
|
||
unitAliases = {
|
||
ms : 'millisecond',
|
||
s : 'second',
|
||
m : 'minute',
|
||
h : 'hour',
|
||
d : 'day',
|
||
D : 'date',
|
||
w : 'week',
|
||
W : 'isoWeek',
|
||
M : 'month',
|
||
Q : 'quarter',
|
||
y : 'year',
|
||
DDD : 'dayOfYear',
|
||
e : 'weekday',
|
||
E : 'isoWeekday',
|
||
gg: 'weekYear',
|
||
GG: 'isoWeekYear'
|
||
},
|
||
|
||
camelFunctions = {
|
||
dayofyear : 'dayOfYear',
|
||
isoweekday : 'isoWeekday',
|
||
isoweek : 'isoWeek',
|
||
weekyear : 'weekYear',
|
||
isoweekyear : 'isoWeekYear'
|
||
},
|
||
|
||
// format function strings
|
||
formatFunctions = {},
|
||
|
||
// default relative time thresholds
|
||
relativeTimeThresholds = {
|
||
s: 45, // seconds to minute
|
||
m: 45, // minutes to hour
|
||
h: 22, // hours to day
|
||
d: 26, // days to month
|
||
M: 11 // months to year
|
||
},
|
||
|
||
// tokens to ordinalize and pad
|
||
ordinalizeTokens = 'DDD w W M D d'.split(' '),
|
||
paddedTokens = 'M D H h m s w W'.split(' '),
|
||
|
||
formatTokenFunctions = {
|
||
M : function () {
|
||
return this.month() + 1;
|
||
},
|
||
MMM : function (format) {
|
||
return this.localeData().monthsShort(this, format);
|
||
},
|
||
MMMM : function (format) {
|
||
return this.localeData().months(this, format);
|
||
},
|
||
D : function () {
|
||
return this.date();
|
||
},
|
||
DDD : function () {
|
||
return this.dayOfYear();
|
||
},
|
||
d : function () {
|
||
return this.day();
|
||
},
|
||
dd : function (format) {
|
||
return this.localeData().weekdaysMin(this, format);
|
||
},
|
||
ddd : function (format) {
|
||
return this.localeData().weekdaysShort(this, format);
|
||
},
|
||
dddd : function (format) {
|
||
return this.localeData().weekdays(this, format);
|
||
},
|
||
w : function () {
|
||
return this.week();
|
||
},
|
||
W : function () {
|
||
return this.isoWeek();
|
||
},
|
||
YY : function () {
|
||
return leftZeroFill(this.year() % 100, 2);
|
||
},
|
||
YYYY : function () {
|
||
return leftZeroFill(this.year(), 4);
|
||
},
|
||
YYYYY : function () {
|
||
return leftZeroFill(this.year(), 5);
|
||
},
|
||
YYYYYY : function () {
|
||
var y = this.year(), sign = y >= 0 ? '+' : '-';
|
||
return sign + leftZeroFill(Math.abs(y), 6);
|
||
},
|
||
gg : function () {
|
||
return leftZeroFill(this.weekYear() % 100, 2);
|
||
},
|
||
gggg : function () {
|
||
return leftZeroFill(this.weekYear(), 4);
|
||
},
|
||
ggggg : function () {
|
||
return leftZeroFill(this.weekYear(), 5);
|
||
},
|
||
GG : function () {
|
||
return leftZeroFill(this.isoWeekYear() % 100, 2);
|
||
},
|
||
GGGG : function () {
|
||
return leftZeroFill(this.isoWeekYear(), 4);
|
||
},
|
||
GGGGG : function () {
|
||
return leftZeroFill(this.isoWeekYear(), 5);
|
||
},
|
||
e : function () {
|
||
return this.weekday();
|
||
},
|
||
E : function () {
|
||
return this.isoWeekday();
|
||
},
|
||
a : function () {
|
||
return this.localeData().meridiem(this.hours(), this.minutes(), true);
|
||
},
|
||
A : function () {
|
||
return this.localeData().meridiem(this.hours(), this.minutes(), false);
|
||
},
|
||
H : function () {
|
||
return this.hours();
|
||
},
|
||
h : function () {
|
||
return this.hours() % 12 || 12;
|
||
},
|
||
m : function () {
|
||
return this.minutes();
|
||
},
|
||
s : function () {
|
||
return this.seconds();
|
||
},
|
||
S : function () {
|
||
return toInt(this.milliseconds() / 100);
|
||
},
|
||
SS : function () {
|
||
return leftZeroFill(toInt(this.milliseconds() / 10), 2);
|
||
},
|
||
SSS : function () {
|
||
return leftZeroFill(this.milliseconds(), 3);
|
||
},
|
||
SSSS : function () {
|
||
return leftZeroFill(this.milliseconds(), 3);
|
||
},
|
||
Z : function () {
|
||
var a = -this.zone(),
|
||
b = '+';
|
||
if (a < 0) {
|
||
a = -a;
|
||
b = '-';
|
||
}
|
||
return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2);
|
||
},
|
||
ZZ : function () {
|
||
var a = -this.zone(),
|
||
b = '+';
|
||
if (a < 0) {
|
||
a = -a;
|
||
b = '-';
|
||
}
|
||
return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
|
||
},
|
||
z : function () {
|
||
return this.zoneAbbr();
|
||
},
|
||
zz : function () {
|
||
return this.zoneName();
|
||
},
|
||
X : function () {
|
||
return this.unix();
|
||
},
|
||
Q : function () {
|
||
return this.quarter();
|
||
}
|
||
},
|
||
|
||
deprecations = {},
|
||
|
||
lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'];
|
||
|
||
// Pick the first defined of two or three arguments. dfl comes from
|
||
// default.
|
||
function dfl(a, b, c) {
|
||
switch (arguments.length) {
|
||
case 2: return a != null ? a : b;
|
||
case 3: return a != null ? a : b != null ? b : c;
|
||
default: throw new Error('Implement me');
|
||
}
|
||
}
|
||
|
||
function hasOwnProp(a, b) {
|
||
return hasOwnProperty.call(a, b);
|
||
}
|
||
|
||
function defaultParsingFlags() {
|
||
// We need to deep clone this object, and es5 standard is not very
|
||
// helpful.
|
||
return {
|
||
empty : false,
|
||
unusedTokens : [],
|
||
unusedInput : [],
|
||
overflow : -2,
|
||
charsLeftOver : 0,
|
||
nullInput : false,
|
||
invalidMonth : null,
|
||
invalidFormat : false,
|
||
userInvalidated : false,
|
||
iso: false
|
||
};
|
||
}
|
||
|
||
function printMsg(msg) {
|
||
if (moment.suppressDeprecationWarnings === false &&
|
||
typeof console !== 'undefined' && console.warn) {
|
||
console.warn('Deprecation warning: ' + msg);
|
||
}
|
||
}
|
||
|
||
function deprecate(msg, fn) {
|
||
var firstTime = true;
|
||
return extend(function () {
|
||
if (firstTime) {
|
||
printMsg(msg);
|
||
firstTime = false;
|
||
}
|
||
return fn.apply(this, arguments);
|
||
}, fn);
|
||
}
|
||
|
||
function deprecateSimple(name, msg) {
|
||
if (!deprecations[name]) {
|
||
printMsg(msg);
|
||
deprecations[name] = true;
|
||
}
|
||
}
|
||
|
||
function padToken(func, count) {
|
||
return function (a) {
|
||
return leftZeroFill(func.call(this, a), count);
|
||
};
|
||
}
|
||
function ordinalizeToken(func, period) {
|
||
return function (a) {
|
||
return this.localeData().ordinal(func.call(this, a), period);
|
||
};
|
||
}
|
||
|
||
while (ordinalizeTokens.length) {
|
||
i = ordinalizeTokens.pop();
|
||
formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
|
||
}
|
||
while (paddedTokens.length) {
|
||
i = paddedTokens.pop();
|
||
formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
|
||
}
|
||
formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
|
||
|
||
|
||
/************************************
|
||
Constructors
|
||
************************************/
|
||
|
||
function Locale() {
|
||
}
|
||
|
||
// Moment prototype object
|
||
function Moment(config, skipOverflow) {
|
||
if (skipOverflow !== false) {
|
||
checkOverflow(config);
|
||
}
|
||
copyConfig(this, config);
|
||
this._d = new Date(+config._d);
|
||
}
|
||
|
||
// Duration Constructor
|
||
function Duration(duration) {
|
||
var normalizedInput = normalizeObjectUnits(duration),
|
||
years = normalizedInput.year || 0,
|
||
quarters = normalizedInput.quarter || 0,
|
||
months = normalizedInput.month || 0,
|
||
weeks = normalizedInput.week || 0,
|
||
days = normalizedInput.day || 0,
|
||
hours = normalizedInput.hour || 0,
|
||
minutes = normalizedInput.minute || 0,
|
||
seconds = normalizedInput.second || 0,
|
||
milliseconds = normalizedInput.millisecond || 0;
|
||
|
||
// representation for dateAddRemove
|
||
this._milliseconds = +milliseconds +
|
||
seconds * 1e3 + // 1000
|
||
minutes * 6e4 + // 1000 * 60
|
||
hours * 36e5; // 1000 * 60 * 60
|
||
// Because of dateAddRemove treats 24 hours as different from a
|
||
// day when working around DST, we need to store them separately
|
||
this._days = +days +
|
||
weeks * 7;
|
||
// It is impossible translate months into days without knowing
|
||
// which months you are are talking about, so we have to store
|
||
// it separately.
|
||
this._months = +months +
|
||
quarters * 3 +
|
||
years * 12;
|
||
|
||
this._data = {};
|
||
|
||
this._locale = moment.localeData();
|
||
|
||
this._bubble();
|
||
}
|
||
|
||
/************************************
|
||
Helpers
|
||
************************************/
|
||
|
||
|
||
function extend(a, b) {
|
||
for (var i in b) {
|
||
if (hasOwnProp(b, i)) {
|
||
a[i] = b[i];
|
||
}
|
||
}
|
||
|
||
if (hasOwnProp(b, 'toString')) {
|
||
a.toString = b.toString;
|
||
}
|
||
|
||
if (hasOwnProp(b, 'valueOf')) {
|
||
a.valueOf = b.valueOf;
|
||
}
|
||
|
||
return a;
|
||
}
|
||
|
||
function copyConfig(to, from) {
|
||
var i, prop, val;
|
||
|
||
if (typeof from._isAMomentObject !== 'undefined') {
|
||
to._isAMomentObject = from._isAMomentObject;
|
||
}
|
||
if (typeof from._i !== 'undefined') {
|
||
to._i = from._i;
|
||
}
|
||
if (typeof from._f !== 'undefined') {
|
||
to._f = from._f;
|
||
}
|
||
if (typeof from._l !== 'undefined') {
|
||
to._l = from._l;
|
||
}
|
||
if (typeof from._strict !== 'undefined') {
|
||
to._strict = from._strict;
|
||
}
|
||
if (typeof from._tzm !== 'undefined') {
|
||
to._tzm = from._tzm;
|
||
}
|
||
if (typeof from._isUTC !== 'undefined') {
|
||
to._isUTC = from._isUTC;
|
||
}
|
||
if (typeof from._offset !== 'undefined') {
|
||
to._offset = from._offset;
|
||
}
|
||
if (typeof from._pf !== 'undefined') {
|
||
to._pf = from._pf;
|
||
}
|
||
if (typeof from._locale !== 'undefined') {
|
||
to._locale = from._locale;
|
||
}
|
||
|
||
if (momentProperties.length > 0) {
|
||
for (i in momentProperties) {
|
||
prop = momentProperties[i];
|
||
val = from[prop];
|
||
if (typeof val !== 'undefined') {
|
||
to[prop] = val;
|
||
}
|
||
}
|
||
}
|
||
|
||
return to;
|
||
}
|
||
|
||
function absRound(number) {
|
||
if (number < 0) {
|
||
return Math.ceil(number);
|
||
} else {
|
||
return Math.floor(number);
|
||
}
|
||
}
|
||
|
||
// left zero fill a number
|
||
// see http://jsperf.com/left-zero-filling for performance comparison
|
||
function leftZeroFill(number, targetLength, forceSign) {
|
||
var output = '' + Math.abs(number),
|
||
sign = number >= 0;
|
||
|
||
while (output.length < targetLength) {
|
||
output = '0' + output;
|
||
}
|
||
return (sign ? (forceSign ? '+' : '') : '-') + output;
|
||
}
|
||
|
||
function positiveMomentsDifference(base, other) {
|
||
var res = {milliseconds: 0, months: 0};
|
||
|
||
res.months = other.month() - base.month() +
|
||
(other.year() - base.year()) * 12;
|
||
if (base.clone().add(res.months, 'M').isAfter(other)) {
|
||
--res.months;
|
||
}
|
||
|
||
res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
|
||
|
||
return res;
|
||
}
|
||
|
||
function momentsDifference(base, other) {
|
||
var res;
|
||
other = makeAs(other, base);
|
||
if (base.isBefore(other)) {
|
||
res = positiveMomentsDifference(base, other);
|
||
} else {
|
||
res = positiveMomentsDifference(other, base);
|
||
res.milliseconds = -res.milliseconds;
|
||
res.months = -res.months;
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
// TODO: remove 'name' arg after deprecation is removed
|
||
function createAdder(direction, name) {
|
||
return function (val, period) {
|
||
var dur, tmp;
|
||
//invert the arguments, but complain about it
|
||
if (period !== null && !isNaN(+period)) {
|
||
deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).');
|
||
tmp = val; val = period; period = tmp;
|
||
}
|
||
|
||
val = typeof val === 'string' ? +val : val;
|
||
dur = moment.duration(val, period);
|
||
addOrSubtractDurationFromMoment(this, dur, direction);
|
||
return this;
|
||
};
|
||
}
|
||
|
||
function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) {
|
||
var milliseconds = duration._milliseconds,
|
||
days = duration._days,
|
||
months = duration._months;
|
||
updateOffset = updateOffset == null ? true : updateOffset;
|
||
|
||
if (milliseconds) {
|
||
mom._d.setTime(+mom._d + milliseconds * isAdding);
|
||
}
|
||
if (days) {
|
||
rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding);
|
||
}
|
||
if (months) {
|
||
rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding);
|
||
}
|
||
if (updateOffset) {
|
||
moment.updateOffset(mom, days || months);
|
||
}
|
||
}
|
||
|
||
// check if is an array
|
||
function isArray(input) {
|
||
return Object.prototype.toString.call(input) === '[object Array]';
|
||
}
|
||
|
||
function isDate(input) {
|
||
return Object.prototype.toString.call(input) === '[object Date]' ||
|
||
input instanceof Date;
|
||
}
|
||
|
||
// compare two arrays, return the number of differences
|
||
function compareArrays(array1, array2, dontConvert) {
|
||
var len = Math.min(array1.length, array2.length),
|
||
lengthDiff = Math.abs(array1.length - array2.length),
|
||
diffs = 0,
|
||
i;
|
||
for (i = 0; i < len; i++) {
|
||
if ((dontConvert && array1[i] !== array2[i]) ||
|
||
(!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
|
||
diffs++;
|
||
}
|
||
}
|
||
return diffs + lengthDiff;
|
||
}
|
||
|
||
function normalizeUnits(units) {
|
||
if (units) {
|
||
var lowered = units.toLowerCase().replace(/(.)s$/, '$1');
|
||
units = unitAliases[units] || camelFunctions[lowered] || lowered;
|
||
}
|
||
return units;
|
||
}
|
||
|
||
function normalizeObjectUnits(inputObject) {
|
||
var normalizedInput = {},
|
||
normalizedProp,
|
||
prop;
|
||
|
||
for (prop in inputObject) {
|
||
if (hasOwnProp(inputObject, prop)) {
|
||
normalizedProp = normalizeUnits(prop);
|
||
if (normalizedProp) {
|
||
normalizedInput[normalizedProp] = inputObject[prop];
|
||
}
|
||
}
|
||
}
|
||
|
||
return normalizedInput;
|
||
}
|
||
|
||
function makeList(field) {
|
||
var count, setter;
|
||
|
||
if (field.indexOf('week') === 0) {
|
||
count = 7;
|
||
setter = 'day';
|
||
}
|
||
else if (field.indexOf('month') === 0) {
|
||
count = 12;
|
||
setter = 'month';
|
||
}
|
||
else {
|
||
return;
|
||
}
|
||
|
||
moment[field] = function (format, index) {
|
||
var i, getter,
|
||
method = moment._locale[field],
|
||
results = [];
|
||
|
||
if (typeof format === 'number') {
|
||
index = format;
|
||
format = undefined;
|
||
}
|
||
|
||
getter = function (i) {
|
||
var m = moment().utc().set(setter, i);
|
||
return method.call(moment._locale, m, format || '');
|
||
};
|
||
|
||
if (index != null) {
|
||
return getter(index);
|
||
}
|
||
else {
|
||
for (i = 0; i < count; i++) {
|
||
results.push(getter(i));
|
||
}
|
||
return results;
|
||
}
|
||
};
|
||
}
|
||
|
||
function toInt(argumentForCoercion) {
|
||
var coercedNumber = +argumentForCoercion,
|
||
value = 0;
|
||
|
||
if (coercedNumber !== 0 && isFinite(coercedNumber)) {
|
||
if (coercedNumber >= 0) {
|
||
value = Math.floor(coercedNumber);
|
||
} else {
|
||
value = Math.ceil(coercedNumber);
|
||
}
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
function daysInMonth(year, month) {
|
||
return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
||
}
|
||
|
||
function weeksInYear(year, dow, doy) {
|
||
return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week;
|
||
}
|
||
|
||
function daysInYear(year) {
|
||
return isLeapYear(year) ? 366 : 365;
|
||
}
|
||
|
||
function isLeapYear(year) {
|
||
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
||
}
|
||
|
||
function checkOverflow(m) {
|
||
var overflow;
|
||
if (m._a && m._pf.overflow === -2) {
|
||
overflow =
|
||
m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
|
||
m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
|
||
m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR :
|
||
m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
|
||
m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
|
||
m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
|
||
-1;
|
||
|
||
if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
|
||
overflow = DATE;
|
||
}
|
||
|
||
m._pf.overflow = overflow;
|
||
}
|
||
}
|
||
|
||
function isValid(m) {
|
||
if (m._isValid == null) {
|
||
m._isValid = !isNaN(m._d.getTime()) &&
|
||
m._pf.overflow < 0 &&
|
||
!m._pf.empty &&
|
||
!m._pf.invalidMonth &&
|
||
!m._pf.nullInput &&
|
||
!m._pf.invalidFormat &&
|
||
!m._pf.userInvalidated;
|
||
|
||
if (m._strict) {
|
||
m._isValid = m._isValid &&
|
||
m._pf.charsLeftOver === 0 &&
|
||
m._pf.unusedTokens.length === 0;
|
||
}
|
||
}
|
||
return m._isValid;
|
||
}
|
||
|
||
function normalizeLocale(key) {
|
||
return key ? key.toLowerCase().replace('_', '-') : key;
|
||
}
|
||
|
||
// pick the locale from the array
|
||
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
|
||
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
|
||
function chooseLocale(names) {
|
||
var i = 0, j, next, locale, split;
|
||
|
||
while (i < names.length) {
|
||
split = normalizeLocale(names[i]).split('-');
|
||
j = split.length;
|
||
next = normalizeLocale(names[i + 1]);
|
||
next = next ? next.split('-') : null;
|
||
while (j > 0) {
|
||
locale = loadLocale(split.slice(0, j).join('-'));
|
||
if (locale) {
|
||
return locale;
|
||
}
|
||
if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
|
||
//the next array item is better than a shallower substring of this one
|
||
break;
|
||
}
|
||
j--;
|
||
}
|
||
i++;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function loadLocale(name) {
|
||
var oldLocale = null;
|
||
if (!locales[name] && hasModule) {
|
||
try {
|
||
oldLocale = moment.locale();
|
||
require('./locale/' + name);
|
||
// because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales
|
||
moment.locale(oldLocale);
|
||
} catch (e) { }
|
||
}
|
||
return locales[name];
|
||
}
|
||
|
||
// Return a moment from input, that is local/utc/zone equivalent to model.
|
||
function makeAs(input, model) {
|
||
return model._isUTC ? moment(input).zone(model._offset || 0) :
|
||
moment(input).local();
|
||
}
|
||
|
||
/************************************
|
||
Locale
|
||
************************************/
|
||
|
||
|
||
extend(Locale.prototype, {
|
||
|
||
set : function (config) {
|
||
var prop, i;
|
||
for (i in config) {
|
||
prop = config[i];
|
||
if (typeof prop === 'function') {
|
||
this[i] = prop;
|
||
} else {
|
||
this['_' + i] = prop;
|
||
}
|
||
}
|
||
},
|
||
|
||
_months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
|
||
months : function (m) {
|
||
return this._months[m.month()];
|
||
},
|
||
|
||
_monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
|
||
monthsShort : function (m) {
|
||
return this._monthsShort[m.month()];
|
||
},
|
||
|
||
monthsParse : function (monthName) {
|
||
var i, mom, regex;
|
||
|
||
if (!this._monthsParse) {
|
||
this._monthsParse = [];
|
||
}
|
||
|
||
for (i = 0; i < 12; i++) {
|
||
// make the regex if we don't have it already
|
||
if (!this._monthsParse[i]) {
|
||
mom = moment.utc([2000, i]);
|
||
regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
|
||
this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
|
||
}
|
||
// test the regex
|
||
if (this._monthsParse[i].test(monthName)) {
|
||
return i;
|
||
}
|
||
}
|
||
},
|
||
|
||
_weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
|
||
weekdays : function (m) {
|
||
return this._weekdays[m.day()];
|
||
},
|
||
|
||
_weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
|
||
weekdaysShort : function (m) {
|
||
return this._weekdaysShort[m.day()];
|
||
},
|
||
|
||
_weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
|
||
weekdaysMin : function (m) {
|
||
return this._weekdaysMin[m.day()];
|
||
},
|
||
|
||
weekdaysParse : function (weekdayName) {
|
||
var i, mom, regex;
|
||
|
||
if (!this._weekdaysParse) {
|
||
this._weekdaysParse = [];
|
||
}
|
||
|
||
for (i = 0; i < 7; i++) {
|
||
// make the regex if we don't have it already
|
||
if (!this._weekdaysParse[i]) {
|
||
mom = moment([2000, 1]).day(i);
|
||
regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
|
||
this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
|
||
}
|
||
// test the regex
|
||
if (this._weekdaysParse[i].test(weekdayName)) {
|
||
return i;
|
||
}
|
||
}
|
||
},
|
||
|
||
_longDateFormat : {
|
||
LT : 'h:mm A',
|
||
L : 'MM/DD/YYYY',
|
||
LL : 'MMMM D, YYYY',
|
||
LLL : 'MMMM D, YYYY LT',
|
||
LLLL : 'dddd, MMMM D, YYYY LT'
|
||
},
|
||
longDateFormat : function (key) {
|
||
var output = this._longDateFormat[key];
|
||
if (!output && this._longDateFormat[key.toUpperCase()]) {
|
||
output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
|
||
return val.slice(1);
|
||
});
|
||
this._longDateFormat[key] = output;
|
||
}
|
||
return output;
|
||
},
|
||
|
||
isPM : function (input) {
|
||
// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
|
||
// Using charAt should be more compatible.
|
||
return ((input + '').toLowerCase().charAt(0) === 'p');
|
||
},
|
||
|
||
_meridiemParse : /[ap]\.?m?\.?/i,
|
||
meridiem : function (hours, minutes, isLower) {
|
||
if (hours > 11) {
|
||
return isLower ? 'pm' : 'PM';
|
||
} else {
|
||
return isLower ? 'am' : 'AM';
|
||
}
|
||
},
|
||
|
||
_calendar : {
|
||
sameDay : '[Today at] LT',
|
||
nextDay : '[Tomorrow at] LT',
|
||
nextWeek : 'dddd [at] LT',
|
||
lastDay : '[Yesterday at] LT',
|
||
lastWeek : '[Last] dddd [at] LT',
|
||
sameElse : 'L'
|
||
},
|
||
calendar : function (key, mom) {
|
||
var output = this._calendar[key];
|
||
return typeof output === 'function' ? output.apply(mom) : output;
|
||
},
|
||
|
||
_relativeTime : {
|
||
future : 'in %s',
|
||
past : '%s ago',
|
||
s : 'a few seconds',
|
||
m : 'a minute',
|
||
mm : '%d minutes',
|
||
h : 'an hour',
|
||
hh : '%d hours',
|
||
d : 'a day',
|
||
dd : '%d days',
|
||
M : 'a month',
|
||
MM : '%d months',
|
||
y : 'a year',
|
||
yy : '%d years'
|
||
},
|
||
|
||
relativeTime : function (number, withoutSuffix, string, isFuture) {
|
||
var output = this._relativeTime[string];
|
||
return (typeof output === 'function') ?
|
||
output(number, withoutSuffix, string, isFuture) :
|
||
output.replace(/%d/i, number);
|
||
},
|
||
|
||
pastFuture : function (diff, output) {
|
||
var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
|
||
return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
|
||
},
|
||
|
||
ordinal : function (number) {
|
||
return this._ordinal.replace('%d', number);
|
||
},
|
||
_ordinal : '%d',
|
||
|
||
preparse : function (string) {
|
||
return string;
|
||
},
|
||
|
||
postformat : function (string) {
|
||
return string;
|
||
},
|
||
|
||
week : function (mom) {
|
||
return weekOfYear(mom, this._week.dow, this._week.doy).week;
|
||
},
|
||
|
||
_week : {
|
||
dow : 0, // Sunday is the first day of the week.
|
||
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
||
},
|
||
|
||
_invalidDate: 'Invalid date',
|
||
invalidDate: function () {
|
||
return this._invalidDate;
|
||
}
|
||
});
|
||
|
||
/************************************
|
||
Formatting
|
||
************************************/
|
||
|
||
|
||
function removeFormattingTokens(input) {
|
||
if (input.match(/\[[\s\S]/)) {
|
||
return input.replace(/^\[|\]$/g, '');
|
||
}
|
||
return input.replace(/\\/g, '');
|
||
}
|
||
|
||
function makeFormatFunction(format) {
|
||
var array = format.match(formattingTokens), i, length;
|
||
|
||
for (i = 0, length = array.length; i < length; i++) {
|
||
if (formatTokenFunctions[array[i]]) {
|
||
array[i] = formatTokenFunctions[array[i]];
|
||
} else {
|
||
array[i] = removeFormattingTokens(array[i]);
|
||
}
|
||
}
|
||
|
||
return function (mom) {
|
||
var output = '';
|
||
for (i = 0; i < length; i++) {
|
||
output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
|
||
}
|
||
return output;
|
||
};
|
||
}
|
||
|
||
// format date using native date object
|
||
function formatMoment(m, format) {
|
||
if (!m.isValid()) {
|
||
return m.localeData().invalidDate();
|
||
}
|
||
|
||
format = expandFormat(format, m.localeData());
|
||
|
||
if (!formatFunctions[format]) {
|
||
formatFunctions[format] = makeFormatFunction(format);
|
||
}
|
||
|
||
return formatFunctions[format](m);
|
||
}
|
||
|
||
function expandFormat(format, locale) {
|
||
var i = 5;
|
||
|
||
function replaceLongDateFormatTokens(input) {
|
||
return locale.longDateFormat(input) || input;
|
||
}
|
||
|
||
localFormattingTokens.lastIndex = 0;
|
||
while (i >= 0 && localFormattingTokens.test(format)) {
|
||
format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
|
||
localFormattingTokens.lastIndex = 0;
|
||
i -= 1;
|
||
}
|
||
|
||
return format;
|
||
}
|
||
|
||
|
||
/************************************
|
||
Parsing
|
||
************************************/
|
||
|
||
|
||
// get the regex to find the next token
|
||
function getParseRegexForToken(token, config) {
|
||
var a, strict = config._strict;
|
||
switch (token) {
|
||
case 'Q':
|
||
return parseTokenOneDigit;
|
||
case 'DDDD':
|
||
return parseTokenThreeDigits;
|
||
case 'YYYY':
|
||
case 'GGGG':
|
||
case 'gggg':
|
||
return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
|
||
case 'Y':
|
||
case 'G':
|
||
case 'g':
|
||
return parseTokenSignedNumber;
|
||
case 'YYYYYY':
|
||
case 'YYYYY':
|
||
case 'GGGGG':
|
||
case 'ggggg':
|
||
return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
|
||
case 'S':
|
||
if (strict) {
|
||
return parseTokenOneDigit;
|
||
}
|
||
/* falls through */
|
||
case 'SS':
|
||
if (strict) {
|
||
return parseTokenTwoDigits;
|
||
}
|
||
/* falls through */
|
||
case 'SSS':
|
||
if (strict) {
|
||
return parseTokenThreeDigits;
|
||
}
|
||
/* falls through */
|
||
case 'DDD':
|
||
return parseTokenOneToThreeDigits;
|
||
case 'MMM':
|
||
case 'MMMM':
|
||
case 'dd':
|
||
case 'ddd':
|
||
case 'dddd':
|
||
return parseTokenWord;
|
||
case 'a':
|
||
case 'A':
|
||
return config._locale._meridiemParse;
|
||
case 'X':
|
||
return parseTokenTimestampMs;
|
||
case 'Z':
|
||
case 'ZZ':
|
||
return parseTokenTimezone;
|
||
case 'T':
|
||
return parseTokenT;
|
||
case 'SSSS':
|
||
return parseTokenDigits;
|
||
case 'MM':
|
||
case 'DD':
|
||
case 'YY':
|
||
case 'GG':
|
||
case 'gg':
|
||
case 'HH':
|
||
case 'hh':
|
||
case 'mm':
|
||
case 'ss':
|
||
case 'ww':
|
||
case 'WW':
|
||
return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
|
||
case 'M':
|
||
case 'D':
|
||
case 'd':
|
||
case 'H':
|
||
case 'h':
|
||
case 'm':
|
||
case 's':
|
||
case 'w':
|
||
case 'W':
|
||
case 'e':
|
||
case 'E':
|
||
return parseTokenOneOrTwoDigits;
|
||
case 'Do':
|
||
return parseTokenOrdinal;
|
||
default :
|
||
a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i'));
|
||
return a;
|
||
}
|
||
}
|
||
|
||
function timezoneMinutesFromString(string) {
|
||
string = string || '';
|
||
var possibleTzMatches = (string.match(parseTokenTimezone) || []),
|
||
tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
|
||
parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
|
||
minutes = +(parts[1] * 60) + toInt(parts[2]);
|
||
|
||
return parts[0] === '+' ? -minutes : minutes;
|
||
}
|
||
|
||
// function to convert string input to date
|
||
function addTimeToArrayFromToken(token, input, config) {
|
||
var a, datePartArray = config._a;
|
||
|
||
switch (token) {
|
||
// QUARTER
|
||
case 'Q':
|
||
if (input != null) {
|
||
datePartArray[MONTH] = (toInt(input) - 1) * 3;
|
||
}
|
||
break;
|
||
// MONTH
|
||
case 'M' : // fall through to MM
|
||
case 'MM' :
|
||
if (input != null) {
|
||
datePartArray[MONTH] = toInt(input) - 1;
|
||
}
|
||
break;
|
||
case 'MMM' : // fall through to MMMM
|
||
case 'MMMM' :
|
||
a = config._locale.monthsParse(input);
|
||
// if we didn't find a month name, mark the date as invalid.
|
||
if (a != null) {
|
||
datePartArray[MONTH] = a;
|
||
} else {
|
||
config._pf.invalidMonth = input;
|
||
}
|
||
break;
|
||
// DAY OF MONTH
|
||
case 'D' : // fall through to DD
|
||
case 'DD' :
|
||
if (input != null) {
|
||
datePartArray[DATE] = toInt(input);
|
||
}
|
||
break;
|
||
case 'Do' :
|
||
if (input != null) {
|
||
datePartArray[DATE] = toInt(parseInt(input, 10));
|
||
}
|
||
break;
|
||
// DAY OF YEAR
|
||
case 'DDD' : // fall through to DDDD
|
||
case 'DDDD' :
|
||
if (input != null) {
|
||
config._dayOfYear = toInt(input);
|
||
}
|
||
|
||
break;
|
||
// YEAR
|
||
case 'YY' :
|
||
datePartArray[YEAR] = moment.parseTwoDigitYear(input);
|
||
break;
|
||
case 'YYYY' :
|
||
case 'YYYYY' :
|
||
case 'YYYYYY' :
|
||
datePartArray[YEAR] = toInt(input);
|
||
break;
|
||
// AM / PM
|
||
case 'a' : // fall through to A
|
||
case 'A' :
|
||
config._isPm = config._locale.isPM(input);
|
||
break;
|
||
// 24 HOUR
|
||
case 'H' : // fall through to hh
|
||
case 'HH' : // fall through to hh
|
||
case 'h' : // fall through to hh
|
||
case 'hh' :
|
||
datePartArray[HOUR] = toInt(input);
|
||
break;
|
||
// MINUTE
|
||
case 'm' : // fall through to mm
|
||
case 'mm' :
|
||
datePartArray[MINUTE] = toInt(input);
|
||
break;
|
||
// SECOND
|
||
case 's' : // fall through to ss
|
||
case 'ss' :
|
||
datePartArray[SECOND] = toInt(input);
|
||
break;
|
||
// MILLISECOND
|
||
case 'S' :
|
||
case 'SS' :
|
||
case 'SSS' :
|
||
case 'SSSS' :
|
||
datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
|
||
break;
|
||
// UNIX TIMESTAMP WITH MS
|
||
case 'X':
|
||
config._d = new Date(parseFloat(input) * 1000);
|
||
break;
|
||
// TIMEZONE
|
||
case 'Z' : // fall through to ZZ
|
||
case 'ZZ' :
|
||
config._useUTC = true;
|
||
config._tzm = timezoneMinutesFromString(input);
|
||
break;
|
||
// WEEKDAY - human
|
||
case 'dd':
|
||
case 'ddd':
|
||
case 'dddd':
|
||
a = config._locale.weekdaysParse(input);
|
||
// if we didn't get a weekday name, mark the date as invalid
|
||
if (a != null) {
|
||
config._w = config._w || {};
|
||
config._w['d'] = a;
|
||
} else {
|
||
config._pf.invalidWeekday = input;
|
||
}
|
||
break;
|
||
// WEEK, WEEK DAY - numeric
|
||
case 'w':
|
||
case 'ww':
|
||
case 'W':
|
||
case 'WW':
|
||
case 'd':
|
||
case 'e':
|
||
case 'E':
|
||
token = token.substr(0, 1);
|
||
/* falls through */
|
||
case 'gggg':
|
||
case 'GGGG':
|
||
case 'GGGGG':
|
||
token = token.substr(0, 2);
|
||
if (input) {
|
||
config._w = config._w || {};
|
||
config._w[token] = toInt(input);
|
||
}
|
||
break;
|
||
case 'gg':
|
||
case 'GG':
|
||
config._w = config._w || {};
|
||
config._w[token] = moment.parseTwoDigitYear(input);
|
||
}
|
||
}
|
||
|
||
function dayOfYearFromWeekInfo(config) {
|
||
var w, weekYear, week, weekday, dow, doy, temp;
|
||
|
||
w = config._w;
|
||
if (w.GG != null || w.W != null || w.E != null) {
|
||
dow = 1;
|
||
doy = 4;
|
||
|
||
// TODO: We need to take the current isoWeekYear, but that depends on
|
||
// how we interpret now (local, utc, fixed offset). So create
|
||
// a now version of current config (take local/utc/offset flags, and
|
||
// create now).
|
||
weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year);
|
||
week = dfl(w.W, 1);
|
||
weekday = dfl(w.E, 1);
|
||
} else {
|
||
dow = config._locale._week.dow;
|
||
doy = config._locale._week.doy;
|
||
|
||
weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year);
|
||
week = dfl(w.w, 1);
|
||
|
||
if (w.d != null) {
|
||
// weekday -- low day numbers are considered next week
|
||
weekday = w.d;
|
||
if (weekday < dow) {
|
||
++week;
|
||
}
|
||
} else if (w.e != null) {
|
||
// local weekday -- counting starts from begining of week
|
||
weekday = w.e + dow;
|
||
} else {
|
||
// default to begining of week
|
||
weekday = dow;
|
||
}
|
||
}
|
||
temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);
|
||
|
||
config._a[YEAR] = temp.year;
|
||
config._dayOfYear = temp.dayOfYear;
|
||
}
|
||
|
||
// convert an array to a date.
|
||
// the array should mirror the parameters below
|
||
// note: all values past the year are optional and will default to the lowest possible value.
|
||
// [year, month, day , hour, minute, second, millisecond]
|
||
function dateFromConfig(config) {
|
||
var i, date, input = [], currentDate, yearToUse;
|
||
|
||
if (config._d) {
|
||
return;
|
||
}
|
||
|
||
currentDate = currentDateArray(config);
|
||
|
||
//compute day of the year from weeks and weekdays
|
||
if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
|
||
dayOfYearFromWeekInfo(config);
|
||
}
|
||
|
||
//if the day of the year is set, figure out what it is
|
||
if (config._dayOfYear) {
|
||
yearToUse = dfl(config._a[YEAR], currentDate[YEAR]);
|
||
|
||
if (config._dayOfYear > daysInYear(yearToUse)) {
|
||
config._pf._overflowDayOfYear = true;
|
||
}
|
||
|
||
date = makeUTCDate(yearToUse, 0, config._dayOfYear);
|
||
config._a[MONTH] = date.getUTCMonth();
|
||
config._a[DATE] = date.getUTCDate();
|
||
}
|
||
|
||
// Default to current date.
|
||
// * if no year, month, day of month are given, default to today
|
||
// * if day of month is given, default month and year
|
||
// * if month is given, default only year
|
||
// * if year is given, don't default anything
|
||
for (i = 0; i < 3 && config._a[i] == null; ++i) {
|
||
config._a[i] = input[i] = currentDate[i];
|
||
}
|
||
|
||
// Zero out whatever was not defaulted, including time
|
||
for (; i < 7; i++) {
|
||
config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
|
||
}
|
||
|
||
config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
|
||
// Apply timezone offset from input. The actual zone can be changed
|
||
// with parseZone.
|
||
if (config._tzm != null) {
|
||
config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm);
|
||
}
|
||
}
|
||
|
||
function dateFromObject(config) {
|
||
var normalizedInput;
|
||
|
||
if (config._d) {
|
||
return;
|
||
}
|
||
|
||
normalizedInput = normalizeObjectUnits(config._i);
|
||
config._a = [
|
||
normalizedInput.year,
|
||
normalizedInput.month,
|
||
normalizedInput.day,
|
||
normalizedInput.hour,
|
||
normalizedInput.minute,
|
||
normalizedInput.second,
|
||
normalizedInput.millisecond
|
||
];
|
||
|
||
dateFromConfig(config);
|
||
}
|
||
|
||
function currentDateArray(config) {
|
||
var now = new Date();
|
||
if (config._useUTC) {
|
||
return [
|
||
now.getUTCFullYear(),
|
||
now.getUTCMonth(),
|
||
now.getUTCDate()
|
||
];
|
||
} else {
|
||
return [now.getFullYear(), now.getMonth(), now.getDate()];
|
||
}
|
||
}
|
||
|
||
// date from string and format string
|
||
function makeDateFromStringAndFormat(config) {
|
||
if (config._f === moment.ISO_8601) {
|
||
parseISO(config);
|
||
return;
|
||
}
|
||
|
||
config._a = [];
|
||
config._pf.empty = true;
|
||
|
||
// This array is used to make a Date, either with `new Date` or `Date.UTC`
|
||
var string = '' + config._i,
|
||
i, parsedInput, tokens, token, skipped,
|
||
stringLength = string.length,
|
||
totalParsedInputLength = 0;
|
||
|
||
tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
|
||
|
||
for (i = 0; i < tokens.length; i++) {
|
||
token = tokens[i];
|
||
parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
|
||
if (parsedInput) {
|
||
skipped = string.substr(0, string.indexOf(parsedInput));
|
||
if (skipped.length > 0) {
|
||
config._pf.unusedInput.push(skipped);
|
||
}
|
||
string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
|
||
totalParsedInputLength += parsedInput.length;
|
||
}
|
||
// don't parse if it's not a known token
|
||
if (formatTokenFunctions[token]) {
|
||
if (parsedInput) {
|
||
config._pf.empty = false;
|
||
}
|
||
else {
|
||
config._pf.unusedTokens.push(token);
|
||
}
|
||
addTimeToArrayFromToken(token, parsedInput, config);
|
||
}
|
||
else if (config._strict && !parsedInput) {
|
||
config._pf.unusedTokens.push(token);
|
||
}
|
||
}
|
||
|
||
// add remaining unparsed input length to the string
|
||
config._pf.charsLeftOver = stringLength - totalParsedInputLength;
|
||
if (string.length > 0) {
|
||
config._pf.unusedInput.push(string);
|
||
}
|
||
|
||
// handle am pm
|
||
if (config._isPm && config._a[HOUR] < 12) {
|
||
config._a[HOUR] += 12;
|
||
}
|
||
// if is 12 am, change hours to 0
|
||
if (config._isPm === false && config._a[HOUR] === 12) {
|
||
config._a[HOUR] = 0;
|
||
}
|
||
|
||
dateFromConfig(config);
|
||
checkOverflow(config);
|
||
}
|
||
|
||
function unescapeFormat(s) {
|
||
return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
|
||
return p1 || p2 || p3 || p4;
|
||
});
|
||
}
|
||
|
||
// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
|
||
function regexpEscape(s) {
|
||
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||
}
|
||
|
||
// date from string and array of format strings
|
||
function makeDateFromStringAndArray(config) {
|
||
var tempConfig,
|
||
bestMoment,
|
||
|
||
scoreToBeat,
|
||
i,
|
||
currentScore;
|
||
|
||
if (config._f.length === 0) {
|
||
config._pf.invalidFormat = true;
|
||
config._d = new Date(NaN);
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < config._f.length; i++) {
|
||
currentScore = 0;
|
||
tempConfig = copyConfig({}, config);
|
||
if (config._useUTC != null) {
|
||
tempConfig._useUTC = config._useUTC;
|
||
}
|
||
tempConfig._pf = defaultParsingFlags();
|
||
tempConfig._f = config._f[i];
|
||
makeDateFromStringAndFormat(tempConfig);
|
||
|
||
if (!isValid(tempConfig)) {
|
||
continue;
|
||
}
|
||
|
||
// if there is any input that was not parsed add a penalty for that format
|
||
currentScore += tempConfig._pf.charsLeftOver;
|
||
|
||
//or tokens
|
||
currentScore += tempConfig._pf.unusedTokens.length * 10;
|
||
|
||
tempConfig._pf.score = currentScore;
|
||
|
||
if (scoreToBeat == null || currentScore < scoreToBeat) {
|
||
scoreToBeat = currentScore;
|
||
bestMoment = tempConfig;
|
||
}
|
||
}
|
||
|
||
extend(config, bestMoment || tempConfig);
|
||
}
|
||
|
||
// date from iso format
|
||
function parseISO(config) {
|
||
var i, l,
|
||
string = config._i,
|
||
match = isoRegex.exec(string);
|
||
|
||
if (match) {
|
||
config._pf.iso = true;
|
||
for (i = 0, l = isoDates.length; i < l; i++) {
|
||
if (isoDates[i][1].exec(string)) {
|
||
// match[5] should be 'T' or undefined
|
||
config._f = isoDates[i][0] + (match[6] || ' ');
|
||
break;
|
||
}
|
||
}
|
||
for (i = 0, l = isoTimes.length; i < l; i++) {
|
||
if (isoTimes[i][1].exec(string)) {
|
||
config._f += isoTimes[i][0];
|
||
break;
|
||
}
|
||
}
|
||
if (string.match(parseTokenTimezone)) {
|
||
config._f += 'Z';
|
||
}
|
||
makeDateFromStringAndFormat(config);
|
||
} else {
|
||
config._isValid = false;
|
||
}
|
||
}
|
||
|
||
// date from iso format or fallback
|
||
function makeDateFromString(config) {
|
||
parseISO(config);
|
||
if (config._isValid === false) {
|
||
delete config._isValid;
|
||
moment.createFromInputFallback(config);
|
||
}
|
||
}
|
||
|
||
function map(arr, fn) {
|
||
var res = [], i;
|
||
for (i = 0; i < arr.length; ++i) {
|
||
res.push(fn(arr[i], i));
|
||
}
|
||
return res;
|
||
}
|
||
|
||
function makeDateFromInput(config) {
|
||
var input = config._i, matched;
|
||
if (input === undefined) {
|
||
config._d = new Date();
|
||
} else if (isDate(input)) {
|
||
config._d = new Date(+input);
|
||
} else if ((matched = aspNetJsonRegex.exec(input)) !== null) {
|
||
config._d = new Date(+matched[1]);
|
||
} else if (typeof input === 'string') {
|
||
makeDateFromString(config);
|
||
} else if (isArray(input)) {
|
||
config._a = map(input.slice(0), function (obj) {
|
||
return parseInt(obj, 10);
|
||
});
|
||
dateFromConfig(config);
|
||
} else if (typeof(input) === 'object') {
|
||
dateFromObject(config);
|
||
} else if (typeof(input) === 'number') {
|
||
// from milliseconds
|
||
config._d = new Date(input);
|
||
} else {
|
||
moment.createFromInputFallback(config);
|
||
}
|
||
}
|
||
|
||
function makeDate(y, m, d, h, M, s, ms) {
|
||
//can't just apply() to create a date:
|
||
//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
|
||
var date = new Date(y, m, d, h, M, s, ms);
|
||
|
||
//the date constructor doesn't accept years < 1970
|
||
if (y < 1970) {
|
||
date.setFullYear(y);
|
||
}
|
||
return date;
|
||
}
|
||
|
||
function makeUTCDate(y) {
|
||
var date = new Date(Date.UTC.apply(null, arguments));
|
||
if (y < 1970) {
|
||
date.setUTCFullYear(y);
|
||
}
|
||
return date;
|
||
}
|
||
|
||
function parseWeekday(input, locale) {
|
||
if (typeof input === 'string') {
|
||
if (!isNaN(input)) {
|
||
input = parseInt(input, 10);
|
||
}
|
||
else {
|
||
input = locale.weekdaysParse(input);
|
||
if (typeof input !== 'number') {
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
return input;
|
||
}
|
||
|
||
/************************************
|
||
Relative Time
|
||
************************************/
|
||
|
||
|
||
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
|
||
function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
|
||
return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
|
||
}
|
||
|
||
function relativeTime(posNegDuration, withoutSuffix, locale) {
|
||
var duration = moment.duration(posNegDuration).abs(),
|
||
seconds = round(duration.as('s')),
|
||
minutes = round(duration.as('m')),
|
||
hours = round(duration.as('h')),
|
||
days = round(duration.as('d')),
|
||
months = round(duration.as('M')),
|
||
years = round(duration.as('y')),
|
||
|
||
args = seconds < relativeTimeThresholds.s && ['s', seconds] ||
|
||
minutes === 1 && ['m'] ||
|
||
minutes < relativeTimeThresholds.m && ['mm', minutes] ||
|
||
hours === 1 && ['h'] ||
|
||
hours < relativeTimeThresholds.h && ['hh', hours] ||
|
||
days === 1 && ['d'] ||
|
||
days < relativeTimeThresholds.d && ['dd', days] ||
|
||
months === 1 && ['M'] ||
|
||
months < relativeTimeThresholds.M && ['MM', months] ||
|
||
years === 1 && ['y'] || ['yy', years];
|
||
|
||
args[2] = withoutSuffix;
|
||
args[3] = +posNegDuration > 0;
|
||
args[4] = locale;
|
||
return substituteTimeAgo.apply({}, args);
|
||
}
|
||
|
||
|
||
/************************************
|
||
Week of Year
|
||
************************************/
|
||
|
||
|
||
// firstDayOfWeek 0 = sun, 6 = sat
|
||
// the day of the week that starts the week
|
||
// (usually sunday or monday)
|
||
// firstDayOfWeekOfYear 0 = sun, 6 = sat
|
||
// the first week is the week that contains the first
|
||
// of this day of the week
|
||
// (eg. ISO weeks use thursday (4))
|
||
function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
|
||
var end = firstDayOfWeekOfYear - firstDayOfWeek,
|
||
daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
|
||
adjustedMoment;
|
||
|
||
|
||
if (daysToDayOfWeek > end) {
|
||
daysToDayOfWeek -= 7;
|
||
}
|
||
|
||
if (daysToDayOfWeek < end - 7) {
|
||
daysToDayOfWeek += 7;
|
||
}
|
||
|
||
adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd');
|
||
return {
|
||
week: Math.ceil(adjustedMoment.dayOfYear() / 7),
|
||
year: adjustedMoment.year()
|
||
};
|
||
}
|
||
|
||
//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
|
||
function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
|
||
var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear;
|
||
|
||
d = d === 0 ? 7 : d;
|
||
weekday = weekday != null ? weekday : firstDayOfWeek;
|
||
daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);
|
||
dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
|
||
|
||
return {
|
||
year: dayOfYear > 0 ? year : year - 1,
|
||
dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear
|
||
};
|
||
}
|
||
|
||
/************************************
|
||
Top Level Functions
|
||
************************************/
|
||
|
||
function makeMoment(config) {
|
||
var input = config._i,
|
||
format = config._f;
|
||
|
||
config._locale = config._locale || moment.localeData(config._l);
|
||
|
||
if (input === null || (format === undefined && input === '')) {
|
||
return moment.invalid({nullInput: true});
|
||
}
|
||
|
||
if (typeof input === 'string') {
|
||
config._i = input = config._locale.preparse(input);
|
||
}
|
||
|
||
if (moment.isMoment(input)) {
|
||
return new Moment(input, true);
|
||
} else if (format) {
|
||
if (isArray(format)) {
|
||
makeDateFromStringAndArray(config);
|
||
} else {
|
||
makeDateFromStringAndFormat(config);
|
||
}
|
||
} else {
|
||
makeDateFromInput(config);
|
||
}
|
||
|
||
return new Moment(config);
|
||
}
|
||
|
||
moment = function (input, format, locale, strict) {
|
||
var c;
|
||
|
||
if (typeof(locale) === 'boolean') {
|
||
strict = locale;
|
||
locale = undefined;
|
||
}
|
||
// object construction must be done this way.
|
||
// https://github.com/moment/moment/issues/1423
|
||
c = {};
|
||
c._isAMomentObject = true;
|
||
c._i = input;
|
||
c._f = format;
|
||
c._l = locale;
|
||
c._strict = strict;
|
||
c._isUTC = false;
|
||
c._pf = defaultParsingFlags();
|
||
|
||
return makeMoment(c);
|
||
};
|
||
|
||
moment.suppressDeprecationWarnings = false;
|
||
|
||
moment.createFromInputFallback = deprecate(
|
||
'moment construction falls back to js Date. This is ' +
|
||
'discouraged and will be removed in upcoming major ' +
|
||
'release. Please refer to ' +
|
||
'https://github.com/moment/moment/issues/1407 for more info.',
|
||
function (config) {
|
||
config._d = new Date(config._i);
|
||
}
|
||
);
|
||
|
||
// Pick a moment m from moments so that m[fn](other) is true for all
|
||
// other. This relies on the function fn to be transitive.
|
||
//
|
||
// moments should either be an array of moment objects or an array, whose
|
||
// first element is an array of moment objects.
|
||
function pickBy(fn, moments) {
|
||
var res, i;
|
||
if (moments.length === 1 && isArray(moments[0])) {
|
||
moments = moments[0];
|
||
}
|
||
if (!moments.length) {
|
||
return moment();
|
||
}
|
||
res = moments[0];
|
||
for (i = 1; i < moments.length; ++i) {
|
||
if (moments[i][fn](res)) {
|
||
res = moments[i];
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
moment.min = function () {
|
||
var args = [].slice.call(arguments, 0);
|
||
|
||
return pickBy('isBefore', args);
|
||
};
|
||
|
||
moment.max = function () {
|
||
var args = [].slice.call(arguments, 0);
|
||
|
||
return pickBy('isAfter', args);
|
||
};
|
||
|
||
// creating with utc
|
||
moment.utc = function (input, format, locale, strict) {
|
||
var c;
|
||
|
||
if (typeof(locale) === 'boolean') {
|
||
strict = locale;
|
||
locale = undefined;
|
||
}
|
||
// object construction must be done this way.
|
||
// https://github.com/moment/moment/issues/1423
|
||
c = {};
|
||
c._isAMomentObject = true;
|
||
c._useUTC = true;
|
||
c._isUTC = true;
|
||
c._l = locale;
|
||
c._i = input;
|
||
c._f = format;
|
||
c._strict = strict;
|
||
c._pf = defaultParsingFlags();
|
||
|
||
return makeMoment(c).utc();
|
||
};
|
||
|
||
// creating with unix timestamp (in seconds)
|
||
moment.unix = function (input) {
|
||
return moment(input * 1000);
|
||
};
|
||
|
||
// duration
|
||
moment.duration = function (input, key) {
|
||
var duration = input,
|
||
// matching against regexp is expensive, do it on demand
|
||
match = null,
|
||
sign,
|
||
ret,
|
||
parseIso,
|
||
diffRes;
|
||
|
||
if (moment.isDuration(input)) {
|
||
duration = {
|
||
ms: input._milliseconds,
|
||
d: input._days,
|
||
M: input._months
|
||
};
|
||
} else if (typeof input === 'number') {
|
||
duration = {};
|
||
if (key) {
|
||
duration[key] = input;
|
||
} else {
|
||
duration.milliseconds = input;
|
||
}
|
||
} else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {
|
||
sign = (match[1] === '-') ? -1 : 1;
|
||
duration = {
|
||
y: 0,
|
||
d: toInt(match[DATE]) * sign,
|
||
h: toInt(match[HOUR]) * sign,
|
||
m: toInt(match[MINUTE]) * sign,
|
||
s: toInt(match[SECOND]) * sign,
|
||
ms: toInt(match[MILLISECOND]) * sign
|
||
};
|
||
} else if (!!(match = isoDurationRegex.exec(input))) {
|
||
sign = (match[1] === '-') ? -1 : 1;
|
||
parseIso = function (inp) {
|
||
// We'd normally use ~~inp for this, but unfortunately it also
|
||
// converts floats to ints.
|
||
// inp may be undefined, so careful calling replace on it.
|
||
var res = inp && parseFloat(inp.replace(',', '.'));
|
||
// apply sign while we're at it
|
||
return (isNaN(res) ? 0 : res) * sign;
|
||
};
|
||
duration = {
|
||
y: parseIso(match[2]),
|
||
M: parseIso(match[3]),
|
||
d: parseIso(match[4]),
|
||
h: parseIso(match[5]),
|
||
m: parseIso(match[6]),
|
||
s: parseIso(match[7]),
|
||
w: parseIso(match[8])
|
||
};
|
||
} else if (typeof duration === 'object' &&
|
||
('from' in duration || 'to' in duration)) {
|
||
diffRes = momentsDifference(moment(duration.from), moment(duration.to));
|
||
|
||
duration = {};
|
||
duration.ms = diffRes.milliseconds;
|
||
duration.M = diffRes.months;
|
||
}
|
||
|
||
ret = new Duration(duration);
|
||
|
||
if (moment.isDuration(input) && hasOwnProp(input, '_locale')) {
|
||
ret._locale = input._locale;
|
||
}
|
||
|
||
return ret;
|
||
};
|
||
|
||
// version number
|
||
moment.version = VERSION;
|
||
|
||
// default format
|
||
moment.defaultFormat = isoFormat;
|
||
|
||
// constant that refers to the ISO standard
|
||
moment.ISO_8601 = function () {};
|
||
|
||
// Plugins that add properties should also add the key here (null value),
|
||
// so we can properly clone ourselves.
|
||
moment.momentProperties = momentProperties;
|
||
|
||
// This function will be called whenever a moment is mutated.
|
||
// It is intended to keep the offset in sync with the timezone.
|
||
moment.updateOffset = function () {};
|
||
|
||
// This function allows you to set a threshold for relative time strings
|
||
moment.relativeTimeThreshold = function (threshold, limit) {
|
||
if (relativeTimeThresholds[threshold] === undefined) {
|
||
return false;
|
||
}
|
||
if (limit === undefined) {
|
||
return relativeTimeThresholds[threshold];
|
||
}
|
||
relativeTimeThresholds[threshold] = limit;
|
||
return true;
|
||
};
|
||
|
||
moment.lang = deprecate(
|
||
'moment.lang is deprecated. Use moment.locale instead.',
|
||
function (key, value) {
|
||
return moment.locale(key, value);
|
||
}
|
||
);
|
||
|
||
// This function will load locale and then set the global locale. If
|
||
// no arguments are passed in, it will simply return the current global
|
||
// locale key.
|
||
moment.locale = function (key, values) {
|
||
var data;
|
||
if (key) {
|
||
if (typeof(values) !== 'undefined') {
|
||
data = moment.defineLocale(key, values);
|
||
}
|
||
else {
|
||
data = moment.localeData(key);
|
||
}
|
||
|
||
if (data) {
|
||
moment.duration._locale = moment._locale = data;
|
||
}
|
||
}
|
||
|
||
return moment._locale._abbr;
|
||
};
|
||
|
||
moment.defineLocale = function (name, values) {
|
||
if (values !== null) {
|
||
values.abbr = name;
|
||
if (!locales[name]) {
|
||
locales[name] = new Locale();
|
||
}
|
||
locales[name].set(values);
|
||
|
||
// backwards compat for now: also set the locale
|
||
moment.locale(name);
|
||
|
||
return locales[name];
|
||
} else {
|
||
// useful for testing
|
||
delete locales[name];
|
||
return null;
|
||
}
|
||
};
|
||
|
||
moment.langData = deprecate(
|
||
'moment.langData is deprecated. Use moment.localeData instead.',
|
||
function (key) {
|
||
return moment.localeData(key);
|
||
}
|
||
);
|
||
|
||
// returns locale data
|
||
moment.localeData = function (key) {
|
||
var locale;
|
||
|
||
if (key && key._locale && key._locale._abbr) {
|
||
key = key._locale._abbr;
|
||
}
|
||
|
||
if (!key) {
|
||
return moment._locale;
|
||
}
|
||
|
||
if (!isArray(key)) {
|
||
//short-circuit everything else
|
||
locale = loadLocale(key);
|
||
if (locale) {
|
||
return locale;
|
||
}
|
||
key = [key];
|
||
}
|
||
|
||
return chooseLocale(key);
|
||
};
|
||
|
||
// compare moment object
|
||
moment.isMoment = function (obj) {
|
||
return obj instanceof Moment ||
|
||
(obj != null && hasOwnProp(obj, '_isAMomentObject'));
|
||
};
|
||
|
||
// for typechecking Duration objects
|
||
moment.isDuration = function (obj) {
|
||
return obj instanceof Duration;
|
||
};
|
||
|
||
for (i = lists.length - 1; i >= 0; --i) {
|
||
makeList(lists[i]);
|
||
}
|
||
|
||
moment.normalizeUnits = function (units) {
|
||
return normalizeUnits(units);
|
||
};
|
||
|
||
moment.invalid = function (flags) {
|
||
var m = moment.utc(NaN);
|
||
if (flags != null) {
|
||
extend(m._pf, flags);
|
||
}
|
||
else {
|
||
m._pf.userInvalidated = true;
|
||
}
|
||
|
||
return m;
|
||
};
|
||
|
||
moment.parseZone = function () {
|
||
return moment.apply(null, arguments).parseZone();
|
||
};
|
||
|
||
moment.parseTwoDigitYear = function (input) {
|
||
return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
|
||
};
|
||
|
||
/************************************
|
||
Moment Prototype
|
||
************************************/
|
||
|
||
|
||
extend(moment.fn = Moment.prototype, {
|
||
|
||
clone : function () {
|
||
return moment(this);
|
||
},
|
||
|
||
valueOf : function () {
|
||
return +this._d + ((this._offset || 0) * 60000);
|
||
},
|
||
|
||
unix : function () {
|
||
return Math.floor(+this / 1000);
|
||
},
|
||
|
||
toString : function () {
|
||
return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
|
||
},
|
||
|
||
toDate : function () {
|
||
return this._offset ? new Date(+this) : this._d;
|
||
},
|
||
|
||
toISOString : function () {
|
||
var m = moment(this).utc();
|
||
if (0 < m.year() && m.year() <= 9999) {
|
||
return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
|
||
} else {
|
||
return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
|
||
}
|
||
},
|
||
|
||
toArray : function () {
|
||
var m = this;
|
||
return [
|
||
m.year(),
|
||
m.month(),
|
||
m.date(),
|
||
m.hours(),
|
||
m.minutes(),
|
||
m.seconds(),
|
||
m.milliseconds()
|
||
];
|
||
},
|
||
|
||
isValid : function () {
|
||
return isValid(this);
|
||
},
|
||
|
||
isDSTShifted : function () {
|
||
if (this._a) {
|
||
return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
|
||
}
|
||
|
||
return false;
|
||
},
|
||
|
||
parsingFlags : function () {
|
||
return extend({}, this._pf);
|
||
},
|
||
|
||
invalidAt: function () {
|
||
return this._pf.overflow;
|
||
},
|
||
|
||
utc : function (keepLocalTime) {
|
||
return this.zone(0, keepLocalTime);
|
||
},
|
||
|
||
local : function (keepLocalTime) {
|
||
if (this._isUTC) {
|
||
this.zone(0, keepLocalTime);
|
||
this._isUTC = false;
|
||
|
||
if (keepLocalTime) {
|
||
this.add(this._dateTzOffset(), 'm');
|
||
}
|
||
}
|
||
return this;
|
||
},
|
||
|
||
format : function (inputString) {
|
||
var output = formatMoment(this, inputString || moment.defaultFormat);
|
||
return this.localeData().postformat(output);
|
||
},
|
||
|
||
add : createAdder(1, 'add'),
|
||
|
||
subtract : createAdder(-1, 'subtract'),
|
||
|
||
diff : function (input, units, asFloat) {
|
||
var that = makeAs(input, this),
|
||
zoneDiff = (this.zone() - that.zone()) * 6e4,
|
||
diff, output, daysAdjust;
|
||
|
||
units = normalizeUnits(units);
|
||
|
||
if (units === 'year' || units === 'month') {
|
||
// average number of days in the months in the given dates
|
||
diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
|
||
// difference in months
|
||
output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
|
||
// adjust by taking difference in days, average number of days
|
||
// and dst in the given months.
|
||
daysAdjust = (this - moment(this).startOf('month')) -
|
||
(that - moment(that).startOf('month'));
|
||
// same as above but with zones, to negate all dst
|
||
daysAdjust -= ((this.zone() - moment(this).startOf('month').zone()) -
|
||
(that.zone() - moment(that).startOf('month').zone())) * 6e4;
|
||
output += daysAdjust / diff;
|
||
if (units === 'year') {
|
||
output = output / 12;
|
||
}
|
||
} else {
|
||
diff = (this - that);
|
||
output = units === 'second' ? diff / 1e3 : // 1000
|
||
units === 'minute' ? diff / 6e4 : // 1000 * 60
|
||
units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
|
||
units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
|
||
units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
|
||
diff;
|
||
}
|
||
return asFloat ? output : absRound(output);
|
||
},
|
||
|
||
from : function (time, withoutSuffix) {
|
||
return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
|
||
},
|
||
|
||
fromNow : function (withoutSuffix) {
|
||
return this.from(moment(), withoutSuffix);
|
||
},
|
||
|
||
calendar : function (time) {
|
||
// We want to compare the start of today, vs this.
|
||
// Getting start-of-today depends on whether we're zone'd or not.
|
||
var now = time || moment(),
|
||
sod = makeAs(now, this).startOf('day'),
|
||
diff = this.diff(sod, 'days', true),
|
||
format = diff < -6 ? 'sameElse' :
|
||
diff < -1 ? 'lastWeek' :
|
||
diff < 0 ? 'lastDay' :
|
||
diff < 1 ? 'sameDay' :
|
||
diff < 2 ? 'nextDay' :
|
||
diff < 7 ? 'nextWeek' : 'sameElse';
|
||
return this.format(this.localeData().calendar(format, this));
|
||
},
|
||
|
||
isLeapYear : function () {
|
||
return isLeapYear(this.year());
|
||
},
|
||
|
||
isDST : function () {
|
||
return (this.zone() < this.clone().month(0).zone() ||
|
||
this.zone() < this.clone().month(5).zone());
|
||
},
|
||
|
||
day : function (input) {
|
||
var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
|
||
if (input != null) {
|
||
input = parseWeekday(input, this.localeData());
|
||
return this.add(input - day, 'd');
|
||
} else {
|
||
return day;
|
||
}
|
||
},
|
||
|
||
month : makeAccessor('Month', true),
|
||
|
||
startOf : function (units) {
|
||
units = normalizeUnits(units);
|
||
// the following switch intentionally omits break keywords
|
||
// to utilize falling through the cases.
|
||
switch (units) {
|
||
case 'year':
|
||
this.month(0);
|
||
/* falls through */
|
||
case 'quarter':
|
||
case 'month':
|
||
this.date(1);
|
||
/* falls through */
|
||
case 'week':
|
||
case 'isoWeek':
|
||
case 'day':
|
||
this.hours(0);
|
||
/* falls through */
|
||
case 'hour':
|
||
this.minutes(0);
|
||
/* falls through */
|
||
case 'minute':
|
||
this.seconds(0);
|
||
/* falls through */
|
||
case 'second':
|
||
this.milliseconds(0);
|
||
/* falls through */
|
||
}
|
||
|
||
// weeks are a special case
|
||
if (units === 'week') {
|
||
this.weekday(0);
|
||
} else if (units === 'isoWeek') {
|
||
this.isoWeekday(1);
|
||
}
|
||
|
||
// quarters are also special
|
||
if (units === 'quarter') {
|
||
this.month(Math.floor(this.month() / 3) * 3);
|
||
}
|
||
|
||
return this;
|
||
},
|
||
|
||
endOf: function (units) {
|
||
units = normalizeUnits(units);
|
||
return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
|
||
},
|
||
|
||
isAfter: function (input, units) {
|
||
units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');
|
||
if (units === 'millisecond') {
|
||
input = moment.isMoment(input) ? input : moment(input);
|
||
return +this > +input;
|
||
} else {
|
||
return +this.clone().startOf(units) > +moment(input).startOf(units);
|
||
}
|
||
},
|
||
|
||
isBefore: function (input, units) {
|
||
units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');
|
||
if (units === 'millisecond') {
|
||
input = moment.isMoment(input) ? input : moment(input);
|
||
return +this < +input;
|
||
} else {
|
||
return +this.clone().startOf(units) < +moment(input).startOf(units);
|
||
}
|
||
},
|
||
|
||
isSame: function (input, units) {
|
||
units = normalizeUnits(units || 'millisecond');
|
||
if (units === 'millisecond') {
|
||
input = moment.isMoment(input) ? input : moment(input);
|
||
return +this === +input;
|
||
} else {
|
||
return +this.clone().startOf(units) === +makeAs(input, this).startOf(units);
|
||
}
|
||
},
|
||
|
||
min: deprecate(
|
||
'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548',
|
||
function (other) {
|
||
other = moment.apply(null, arguments);
|
||
return other < this ? this : other;
|
||
}
|
||
),
|
||
|
||
max: deprecate(
|
||
'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548',
|
||
function (other) {
|
||
other = moment.apply(null, arguments);
|
||
return other > this ? this : other;
|
||
}
|
||
),
|
||
|
||
// keepLocalTime = true means only change the timezone, without
|
||
// affecting the local hour. So 5:31:26 +0300 --[zone(2, true)]-->
|
||
// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist int zone
|
||
// +0200, so we adjust the time as needed, to be valid.
|
||
//
|
||
// Keeping the time actually adds/subtracts (one hour)
|
||
// from the actual represented time. That is why we call updateOffset
|
||
// a second time. In case it wants us to change the offset again
|
||
// _changeInProgress == true case, then we have to adjust, because
|
||
// there is no such time in the given timezone.
|
||
zone : function (input, keepLocalTime) {
|
||
var offset = this._offset || 0,
|
||
localAdjust;
|
||
if (input != null) {
|
||
if (typeof input === 'string') {
|
||
input = timezoneMinutesFromString(input);
|
||
}
|
||
if (Math.abs(input) < 16) {
|
||
input = input * 60;
|
||
}
|
||
if (!this._isUTC && keepLocalTime) {
|
||
localAdjust = this._dateTzOffset();
|
||
}
|
||
this._offset = input;
|
||
this._isUTC = true;
|
||
if (localAdjust != null) {
|
||
this.subtract(localAdjust, 'm');
|
||
}
|
||
if (offset !== input) {
|
||
if (!keepLocalTime || this._changeInProgress) {
|
||
addOrSubtractDurationFromMoment(this,
|
||
moment.duration(offset - input, 'm'), 1, false);
|
||
} else if (!this._changeInProgress) {
|
||
this._changeInProgress = true;
|
||
moment.updateOffset(this, true);
|
||
this._changeInProgress = null;
|
||
}
|
||
}
|
||
} else {
|
||
return this._isUTC ? offset : this._dateTzOffset();
|
||
}
|
||
return this;
|
||
},
|
||
|
||
zoneAbbr : function () {
|
||
return this._isUTC ? 'UTC' : '';
|
||
},
|
||
|
||
zoneName : function () {
|
||
return this._isUTC ? 'Coordinated Universal Time' : '';
|
||
},
|
||
|
||
parseZone : function () {
|
||
if (this._tzm) {
|
||
this.zone(this._tzm);
|
||
} else if (typeof this._i === 'string') {
|
||
this.zone(this._i);
|
||
}
|
||
return this;
|
||
},
|
||
|
||
hasAlignedHourOffset : function (input) {
|
||
if (!input) {
|
||
input = 0;
|
||
}
|
||
else {
|
||
input = moment(input).zone();
|
||
}
|
||
|
||
return (this.zone() - input) % 60 === 0;
|
||
},
|
||
|
||
daysInMonth : function () {
|
||
return daysInMonth(this.year(), this.month());
|
||
},
|
||
|
||
dayOfYear : function (input) {
|
||
var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
|
||
return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
|
||
},
|
||
|
||
quarter : function (input) {
|
||
return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
|
||
},
|
||
|
||
weekYear : function (input) {
|
||
var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year;
|
||
return input == null ? year : this.add((input - year), 'y');
|
||
},
|
||
|
||
isoWeekYear : function (input) {
|
||
var year = weekOfYear(this, 1, 4).year;
|
||
return input == null ? year : this.add((input - year), 'y');
|
||
},
|
||
|
||
week : function (input) {
|
||
var week = this.localeData().week(this);
|
||
return input == null ? week : this.add((input - week) * 7, 'd');
|
||
},
|
||
|
||
isoWeek : function (input) {
|
||
var week = weekOfYear(this, 1, 4).week;
|
||
return input == null ? week : this.add((input - week) * 7, 'd');
|
||
},
|
||
|
||
weekday : function (input) {
|
||
var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
|
||
return input == null ? weekday : this.add(input - weekday, 'd');
|
||
},
|
||
|
||
isoWeekday : function (input) {
|
||
// behaves the same as moment#day except
|
||
// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
|
||
// as a setter, sunday should belong to the previous week.
|
||
return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
|
||
},
|
||
|
||
isoWeeksInYear : function () {
|
||
return weeksInYear(this.year(), 1, 4);
|
||
},
|
||
|
||
weeksInYear : function () {
|
||
var weekInfo = this.localeData()._week;
|
||
return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
|
||
},
|
||
|
||
get : function (units) {
|
||
units = normalizeUnits(units);
|
||
return this[units]();
|
||
},
|
||
|
||
set : function (units, value) {
|
||
units = normalizeUnits(units);
|
||
if (typeof this[units] === 'function') {
|
||
this[units](value);
|
||
}
|
||
return this;
|
||
},
|
||
|
||
// If passed a locale key, it will set the locale for this
|
||
// instance. Otherwise, it will return the locale configuration
|
||
// variables for this instance.
|
||
locale : function (key) {
|
||
var newLocaleData;
|
||
|
||
if (key === undefined) {
|
||
return this._locale._abbr;
|
||
} else {
|
||
newLocaleData = moment.localeData(key);
|
||
if (newLocaleData != null) {
|
||
this._locale = newLocaleData;
|
||
}
|
||
return this;
|
||
}
|
||
},
|
||
|
||
lang : deprecate(
|
||
'moment().lang() is deprecated. Use moment().localeData() instead.',
|
||
function (key) {
|
||
if (key === undefined) {
|
||
return this.localeData();
|
||
} else {
|
||
return this.locale(key);
|
||
}
|
||
}
|
||
),
|
||
|
||
localeData : function () {
|
||
return this._locale;
|
||
},
|
||
|
||
_dateTzOffset : function () {
|
||
// On Firefox.24 Date#getTimezoneOffset returns a floating point.
|
||
// https://github.com/moment/moment/pull/1871
|
||
return Math.round(this._d.getTimezoneOffset() / 15) * 15;
|
||
}
|
||
});
|
||
|
||
function rawMonthSetter(mom, value) {
|
||
var dayOfMonth;
|
||
|
||
// TODO: Move this out of here!
|
||
if (typeof value === 'string') {
|
||
value = mom.localeData().monthsParse(value);
|
||
// TODO: Another silent failure?
|
||
if (typeof value !== 'number') {
|
||
return mom;
|
||
}
|
||
}
|
||
|
||
dayOfMonth = Math.min(mom.date(),
|
||
daysInMonth(mom.year(), value));
|
||
mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
|
||
return mom;
|
||
}
|
||
|
||
function rawGetter(mom, unit) {
|
||
return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();
|
||
}
|
||
|
||
function rawSetter(mom, unit, value) {
|
||
if (unit === 'Month') {
|
||
return rawMonthSetter(mom, value);
|
||
} else {
|
||
return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
|
||
}
|
||
}
|
||
|
||
function makeAccessor(unit, keepTime) {
|
||
return function (value) {
|
||
if (value != null) {
|
||
rawSetter(this, unit, value);
|
||
moment.updateOffset(this, keepTime);
|
||
return this;
|
||
} else {
|
||
return rawGetter(this, unit);
|
||
}
|
||
};
|
||
}
|
||
|
||
moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false);
|
||
moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false);
|
||
moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false);
|
||
// Setting the hour should keep the time, because the user explicitly
|
||
// specified which hour he wants. So trying to maintain the same hour (in
|
||
// a new timezone) makes sense. Adding/subtracting hours does not follow
|
||
// this rule.
|
||
moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true);
|
||
// moment.fn.month is defined separately
|
||
moment.fn.date = makeAccessor('Date', true);
|
||
moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true));
|
||
moment.fn.year = makeAccessor('FullYear', true);
|
||
moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true));
|
||
|
||
// add plural methods
|
||
moment.fn.days = moment.fn.day;
|
||
moment.fn.months = moment.fn.month;
|
||
moment.fn.weeks = moment.fn.week;
|
||
moment.fn.isoWeeks = moment.fn.isoWeek;
|
||
moment.fn.quarters = moment.fn.quarter;
|
||
|
||
// add aliased format methods
|
||
moment.fn.toJSON = moment.fn.toISOString;
|
||
|
||
/************************************
|
||
Duration Prototype
|
||
************************************/
|
||
|
||
|
||
function daysToYears (days) {
|
||
// 400 years have 146097 days (taking into account leap year rules)
|
||
return days * 400 / 146097;
|
||
}
|
||
|
||
function yearsToDays (years) {
|
||
// years * 365 + absRound(years / 4) -
|
||
// absRound(years / 100) + absRound(years / 400);
|
||
return years * 146097 / 400;
|
||
}
|
||
|
||
extend(moment.duration.fn = Duration.prototype, {
|
||
|
||
_bubble : function () {
|
||
var milliseconds = this._milliseconds,
|
||
days = this._days,
|
||
months = this._months,
|
||
data = this._data,
|
||
seconds, minutes, hours, years = 0;
|
||
|
||
// The following code bubbles up values, see the tests for
|
||
// examples of what that means.
|
||
data.milliseconds = milliseconds % 1000;
|
||
|
||
seconds = absRound(milliseconds / 1000);
|
||
data.seconds = seconds % 60;
|
||
|
||
minutes = absRound(seconds / 60);
|
||
data.minutes = minutes % 60;
|
||
|
||
hours = absRound(minutes / 60);
|
||
data.hours = hours % 24;
|
||
|
||
days += absRound(hours / 24);
|
||
|
||
// Accurately convert days to years, assume start from year 0.
|
||
years = absRound(daysToYears(days));
|
||
days -= absRound(yearsToDays(years));
|
||
|
||
// 30 days to a month
|
||
// TODO (iskren): Use anchor date (like 1st Jan) to compute this.
|
||
months += absRound(days / 30);
|
||
days %= 30;
|
||
|
||
// 12 months -> 1 year
|
||
years += absRound(months / 12);
|
||
months %= 12;
|
||
|
||
data.days = days;
|
||
data.months = months;
|
||
data.years = years;
|
||
},
|
||
|
||
abs : function () {
|
||
this._milliseconds = Math.abs(this._milliseconds);
|
||
this._days = Math.abs(this._days);
|
||
this._months = Math.abs(this._months);
|
||
|
||
this._data.milliseconds = Math.abs(this._data.milliseconds);
|
||
this._data.seconds = Math.abs(this._data.seconds);
|
||
this._data.minutes = Math.abs(this._data.minutes);
|
||
this._data.hours = Math.abs(this._data.hours);
|
||
this._data.months = Math.abs(this._data.months);
|
||
this._data.years = Math.abs(this._data.years);
|
||
|
||
return this;
|
||
},
|
||
|
||
weeks : function () {
|
||
return absRound(this.days() / 7);
|
||
},
|
||
|
||
valueOf : function () {
|
||
return this._milliseconds +
|
||
this._days * 864e5 +
|
||
(this._months % 12) * 2592e6 +
|
||
toInt(this._months / 12) * 31536e6;
|
||
},
|
||
|
||
humanize : function (withSuffix) {
|
||
var output = relativeTime(this, !withSuffix, this.localeData());
|
||
|
||
if (withSuffix) {
|
||
output = this.localeData().pastFuture(+this, output);
|
||
}
|
||
|
||
return this.localeData().postformat(output);
|
||
},
|
||
|
||
add : function (input, val) {
|
||
// supports only 2.0-style add(1, 's') or add(moment)
|
||
var dur = moment.duration(input, val);
|
||
|
||
this._milliseconds += dur._milliseconds;
|
||
this._days += dur._days;
|
||
this._months += dur._months;
|
||
|
||
this._bubble();
|
||
|
||
return this;
|
||
},
|
||
|
||
subtract : function (input, val) {
|
||
var dur = moment.duration(input, val);
|
||
|
||
this._milliseconds -= dur._milliseconds;
|
||
this._days -= dur._days;
|
||
this._months -= dur._months;
|
||
|
||
this._bubble();
|
||
|
||
return this;
|
||
},
|
||
|
||
get : function (units) {
|
||
units = normalizeUnits(units);
|
||
return this[units.toLowerCase() + 's']();
|
||
},
|
||
|
||
as : function (units) {
|
||
var days, months;
|
||
units = normalizeUnits(units);
|
||
|
||
if (units === 'month' || units === 'year') {
|
||
days = this._days + this._milliseconds / 864e5;
|
||
months = this._months + daysToYears(days) * 12;
|
||
return units === 'month' ? months : months / 12;
|
||
} else {
|
||
// handle milliseconds separately because of floating point math errors (issue #1867)
|
||
days = this._days + yearsToDays(this._months / 12);
|
||
switch (units) {
|
||
case 'week': return days / 7 + this._milliseconds / 6048e5;
|
||
case 'day': return days + this._milliseconds / 864e5;
|
||
case 'hour': return days * 24 + this._milliseconds / 36e5;
|
||
case 'minute': return days * 24 * 60 + this._milliseconds / 6e4;
|
||
case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000;
|
||
// Math.floor prevents floating point math errors here
|
||
case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds;
|
||
default: throw new Error('Unknown unit ' + units);
|
||
}
|
||
}
|
||
},
|
||
|
||
lang : moment.fn.lang,
|
||
locale : moment.fn.locale,
|
||
|
||
toIsoString : deprecate(
|
||
'toIsoString() is deprecated. Please use toISOString() instead ' +
|
||
'(notice the capitals)',
|
||
function () {
|
||
return this.toISOString();
|
||
}
|
||
),
|
||
|
||
toISOString : function () {
|
||
// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
|
||
var years = Math.abs(this.years()),
|
||
months = Math.abs(this.months()),
|
||
days = Math.abs(this.days()),
|
||
hours = Math.abs(this.hours()),
|
||
minutes = Math.abs(this.minutes()),
|
||
seconds = Math.abs(this.seconds() + this.milliseconds() / 1000);
|
||
|
||
if (!this.asSeconds()) {
|
||
// this is the same as C#'s (Noda) and python (isodate)...
|
||
// but not other JS (goog.date)
|
||
return 'P0D';
|
||
}
|
||
|
||
return (this.asSeconds() < 0 ? '-' : '') +
|
||
'P' +
|
||
(years ? years + 'Y' : '') +
|
||
(months ? months + 'M' : '') +
|
||
(days ? days + 'D' : '') +
|
||
((hours || minutes || seconds) ? 'T' : '') +
|
||
(hours ? hours + 'H' : '') +
|
||
(minutes ? minutes + 'M' : '') +
|
||
(seconds ? seconds + 'S' : '');
|
||
},
|
||
|
||
localeData : function () {
|
||
return this._locale;
|
||
}
|
||
});
|
||
|
||
moment.duration.fn.toString = moment.duration.fn.toISOString;
|
||
|
||
function makeDurationGetter(name) {
|
||
moment.duration.fn[name] = function () {
|
||
return this._data[name];
|
||
};
|
||
}
|
||
|
||
for (i in unitMillisecondFactors) {
|
||
if (hasOwnProp(unitMillisecondFactors, i)) {
|
||
makeDurationGetter(i.toLowerCase());
|
||
}
|
||
}
|
||
|
||
moment.duration.fn.asMilliseconds = function () {
|
||
return this.as('ms');
|
||
};
|
||
moment.duration.fn.asSeconds = function () {
|
||
return this.as('s');
|
||
};
|
||
moment.duration.fn.asMinutes = function () {
|
||
return this.as('m');
|
||
};
|
||
moment.duration.fn.asHours = function () {
|
||
return this.as('h');
|
||
};
|
||
moment.duration.fn.asDays = function () {
|
||
return this.as('d');
|
||
};
|
||
moment.duration.fn.asWeeks = function () {
|
||
return this.as('weeks');
|
||
};
|
||
moment.duration.fn.asMonths = function () {
|
||
return this.as('M');
|
||
};
|
||
moment.duration.fn.asYears = function () {
|
||
return this.as('y');
|
||
};
|
||
|
||
/************************************
|
||
Default Locale
|
||
************************************/
|
||
|
||
|
||
// Set default locale, other locale will inherit from English.
|
||
moment.locale('en', {
|
||
ordinal : function (number) {
|
||
var b = number % 10,
|
||
output = (toInt(number % 100 / 10) === 1) ? 'th' :
|
||
(b === 1) ? 'st' :
|
||
(b === 2) ? 'nd' :
|
||
(b === 3) ? 'rd' : 'th';
|
||
return number + output;
|
||
}
|
||
});
|
||
|
||
/* EMBED_LOCALES */
|
||
|
||
/************************************
|
||
Exposing Moment
|
||
************************************/
|
||
|
||
function makeGlobal(shouldDeprecate) {
|
||
/*global ender:false */
|
||
if (typeof ender !== 'undefined') {
|
||
return;
|
||
}
|
||
oldGlobalMoment = globalScope.moment;
|
||
if (shouldDeprecate) {
|
||
globalScope.moment = deprecate(
|
||
'Accessing Moment through the global scope is ' +
|
||
'deprecated, and will be removed in an upcoming ' +
|
||
'release.',
|
||
moment);
|
||
} else {
|
||
globalScope.moment = moment;
|
||
}
|
||
}
|
||
|
||
// CommonJS module is defined
|
||
if (hasModule) {
|
||
module.exports = moment;
|
||
} else if (typeof define === 'function' && define.amd) {
|
||
define('moment', function (require, exports, module) {
|
||
if (module.config && module.config() && module.config().noGlobal === true) {
|
||
// release the global variable
|
||
globalScope.moment = oldGlobalMoment;
|
||
}
|
||
|
||
return moment;
|
||
});
|
||
makeGlobal(true);
|
||
} else {
|
||
makeGlobal();
|
||
}
|
||
}).call(this);
|
||
</script>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
The `core-tooltip` element creates a hover tooltip centered for the content
|
||
it contains. It can be positioned on the top|bottom|left|right of content using
|
||
the `position` attribute.
|
||
|
||
To include HTML in the tooltip, include the `tip` attribute on the relevant
|
||
content.
|
||
|
||
<b>Example</b>:
|
||
|
||
<core-tooltip label="I'm a tooltip">
|
||
<span>Hover over me.</span>
|
||
</core-tooltip>
|
||
|
||
<b>Example</b> - positioning the tooltip to the right:
|
||
|
||
<core-tooltip label="I'm a tooltip to the right" position="right">
|
||
<core-icon-button icon="drawer"></core-icon-button>
|
||
</core-tooltip>
|
||
|
||
<b>Example</b> - no arrow and showing by default:
|
||
|
||
<core-tooltip label="Tooltip with no arrow and always on" noarrow show>
|
||
<img src="image.jpg">
|
||
</core-tooltip>
|
||
|
||
<b>Example</b> - disable the tooltip.
|
||
|
||
<core-tooltip label="Disabled label never shows" disabled>
|
||
...
|
||
</core-tooltip>
|
||
|
||
<b>Example</b> - rich tooltip using the `tip` attribute:
|
||
|
||
<core-tooltip>
|
||
<div>Example of a rich information tooltip</div>
|
||
<div tip>
|
||
<img src="profile.jpg">Foo <b>Bar</b> - <a href="#">@baz</a>
|
||
</div>
|
||
</core-tooltip>
|
||
|
||
By default, the `tip` attribute specifies the HTML content for a rich tooltip.
|
||
You can customize this attribute with the `tipAttribute` attribute:
|
||
|
||
<core-tooltip tipAttribute="htmltooltip">
|
||
<div>Example of a rich information tooltip</div>
|
||
<div htmltooltip>
|
||
...
|
||
</div>
|
||
</core-tooltip>
|
||
|
||
@group Polymer Core Elements
|
||
@element core-tooltip
|
||
@extends paper-focusable
|
||
@homepage http://www.polymer-project.org/components/core-tooltip/index.html
|
||
-->
|
||
|
||
|
||
|
||
|
||
<!-- TODO: would be nice to inherit from label to get .htmlFor, and .control,
|
||
but the latter is readonly. -->
|
||
<!-- TODO: support off center arrows. -->
|
||
<!-- TODO: detect mobile and apply the .large class, instead of manual
|
||
control. -->
|
||
<!-- TODO: possibly reuse core-overlay. -->
|
||
<polymer-element name="core-tooltip" extends="paper-focusable" attributes="noarrow position label show tipAttribute" role="tooltip" assetpath="polymer/bower_components/core-tooltip/">
|
||
<template>
|
||
|
||
<style>/* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */
|
||
|
||
:host {
|
||
box-sizing: border-box;
|
||
position: relative;
|
||
display: inline-block;
|
||
outline: none;
|
||
}
|
||
|
||
:host(:hover:not([disabled])) .core-tooltip {
|
||
visibility: visible !important;
|
||
}
|
||
|
||
:host([focused]) .core-tooltip {
|
||
visibility: visible !important;
|
||
}
|
||
|
||
.core-tooltip:not(.show) {
|
||
visibility: hidden;
|
||
}
|
||
|
||
.core-tooltip {
|
||
position: absolute;
|
||
font-size: 10px;
|
||
font-family: sans-serif;
|
||
padding: 8px;
|
||
color: white;
|
||
background-color: rgba(0,0,0,0.8);
|
||
box-sizing: border-box;
|
||
border-radius: 3px; /* TODO: not in spec. */
|
||
white-space: nowrap;
|
||
line-height: 6px;
|
||
z-index: 1002; /* TODO: this is brittle. */
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
}
|
||
|
||
:host([large]) .core-tooltip {
|
||
line-height: 14px;
|
||
font-size: 14px;
|
||
padding: 16px;
|
||
}
|
||
|
||
.core-tooltip.noarrow::after {
|
||
display: none;
|
||
}
|
||
|
||
.core-tooltip::after {
|
||
position: absolute;
|
||
border: solid transparent;
|
||
content: '';
|
||
height: 0;
|
||
width: 0;
|
||
border-width: 4px;
|
||
}
|
||
|
||
.top {
|
||
margin-bottom: 10px; /* TODO: not specified in spec */
|
||
bottom: 100%;
|
||
}
|
||
|
||
.right {
|
||
margin-left: 10px; /* TODO: not specified in spec */
|
||
left: 100%;
|
||
}
|
||
|
||
.bottom {
|
||
top: 100%;
|
||
margin-top: 10px; /* TODO: not specified in spec */
|
||
}
|
||
|
||
.left {
|
||
margin-right: 10px; /* TODO: not specified in spec */
|
||
right: 100%;
|
||
}
|
||
|
||
.core-tooltip.bottom::after {
|
||
bottom: 100%;
|
||
left: calc(50% - 4px);
|
||
border-bottom-color: rgba(0,0,0,0.8);
|
||
}
|
||
|
||
.core-tooltip.left::after {
|
||
left: 100%;
|
||
top: calc(50% - 4px);
|
||
border-left-color: rgba(0,0,0,0.8);
|
||
}
|
||
|
||
.core-tooltip.top::after {
|
||
top: 100%;
|
||
left: calc(50% - 4px);
|
||
border-top-color: rgba(0,0,0,0.8);
|
||
}
|
||
|
||
.core-tooltip.right::after {
|
||
right: 100%;
|
||
top: calc(50% - 4px);
|
||
border-right-color: rgba(0,0,0,0.8);
|
||
}
|
||
</style>
|
||
<div id="tooltip" hidden?="{{!hasTooltipContent}}" class="core-tooltip {{position}} {{ {noarrow: noarrow, show: show && !disabled} | tokenList}}">
|
||
<content id="c" select="[{{tipAttribute}}]">{{label}}</content>
|
||
</div>
|
||
|
||
<content></content>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('core-tooltip',{
|
||
|
||
/**
|
||
* A simple string label for the tooltip to display. To display a rich
|
||
* HTML tooltip instead, omit `label` and include the `tip` attribute
|
||
* on a child node of `core-tooltip`.
|
||
*
|
||
* @attribute label
|
||
* @type string
|
||
* @default null
|
||
*/
|
||
label: null,
|
||
|
||
computed: {
|
||
// Indicates whether the tooltip has a set label propety or
|
||
// an element with the `tip` attribute.
|
||
hasTooltipContent: 'label || !!tipElement'
|
||
},
|
||
|
||
publish: {
|
||
/**
|
||
* Forces the tooltip to display. If `disabled` is set, this property is ignored.
|
||
*
|
||
* @attribute show
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
show: {value: false, reflect: true},
|
||
|
||
/**
|
||
* Positions the tooltip to the top, right, bottom, left of its content.
|
||
*
|
||
* @attribute position
|
||
* @type string
|
||
* @default 'bottom'
|
||
*/
|
||
position: {value: 'bottom', reflect: true},
|
||
|
||
/**
|
||
* If true, the tooltip an arrow pointing towards the content.
|
||
*
|
||
* @attribute noarrow
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
noarrow: {value: false, reflect: true}
|
||
},
|
||
|
||
/**
|
||
* Customizes the attribute used to specify which content
|
||
* is the rich HTML tooltip.
|
||
*
|
||
* @attribute tipAttribute
|
||
* @type string
|
||
* @default 'tip'
|
||
*/
|
||
tipAttribute: 'tip',
|
||
|
||
attached: function() {
|
||
this.updatedChildren();
|
||
},
|
||
|
||
updatedChildren: function () {
|
||
this.tipElement = null;
|
||
|
||
for (var i = 0, el; el = this.$.c.getDistributedNodes()[i]; ++i) {
|
||
if (el.hasAttribute && el.hasAttribute('tip')) {
|
||
this.tipElement = el;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Job ensures we're not double calling setPosition() on DOM attach.
|
||
this.job('positionJob', this.setPosition);
|
||
|
||
// Monitor children to re-position tooltip when light dom changes.
|
||
this.onMutation(this, this.updatedChildren);
|
||
},
|
||
|
||
labelChanged: function(oldVal, newVal) {
|
||
this.job('positionJob', this.setPosition);
|
||
},
|
||
|
||
positionChanged: function(oldVal, newVal) {
|
||
this.job('positionJob', this.setPosition);
|
||
},
|
||
|
||
setPosition: function() {
|
||
var controlWidth = this.clientWidth;
|
||
var controlHeight = this.clientHeight;
|
||
var toolTipWidth = this.$.tooltip.clientWidth;
|
||
var toolTipHeight = this.$.tooltip.clientHeight;
|
||
|
||
switch (this.position) {
|
||
case 'top':
|
||
case 'bottom':
|
||
this.$.tooltip.style.left = (controlWidth - toolTipWidth) / 2 + 'px';
|
||
this.$.tooltip.style.top = null;
|
||
break;
|
||
case 'left':
|
||
case 'right':
|
||
this.$.tooltip.style.left = null;
|
||
this.$.tooltip.style.top = (controlHeight - toolTipHeight) / 2 + 'px';
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`paper-toggle-button` provides a ON/OFF switch that user can toggle the state
|
||
by tapping or by dragging the swtich.
|
||
|
||
Example:
|
||
|
||
<paper-toggle-button></paper-toggle-button>
|
||
|
||
Styling toggle button:
|
||
|
||
To change the ink color for checked state:
|
||
|
||
paper-toggle-button::shadow paper-radio-button::shadow #ink[checked] {
|
||
color: #4285f4;
|
||
}
|
||
|
||
To change the radio checked color:
|
||
|
||
paper-toggle-button::shadow paper-radio-button::shadow #onRadio {
|
||
background-color: #4285f4;
|
||
}
|
||
|
||
To change the bar color for checked state:
|
||
|
||
paper-toggle-button::shadow #toggleBar[checked] {
|
||
background-color: #4285f4;
|
||
}
|
||
|
||
To change the ink color for unchecked state:
|
||
|
||
paper-toggle-button::shadow paper-radio-button::shadow #ink {
|
||
color: #b5b5b5;
|
||
}
|
||
|
||
To change the radio unchecked color:
|
||
|
||
paper-toggle-button::shadow paper-radio-button::shadow #offRadio {
|
||
border-color: #b5b5b5;
|
||
}
|
||
|
||
To change the bar color for unchecked state:
|
||
|
||
paper-toggle-button::shadow #toggleBar {
|
||
background-color: red;
|
||
}
|
||
|
||
@group Paper Elements
|
||
@element paper-toggle-button
|
||
@homepage github.io
|
||
-->
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`paper-radio-button` is a button that can be either checked or unchecked.
|
||
User can tap the radio button to check it. But it cannot be unchecked by
|
||
tapping once checked.
|
||
|
||
Use `paper-radio-group` to group a set of radio buttons. When radio buttons
|
||
are inside a radio group, only one radio button in the group can be checked.
|
||
|
||
Example:
|
||
|
||
<paper-radio-button></paper-radio-button>
|
||
|
||
Styling radio button:
|
||
|
||
To change the ink color for checked state:
|
||
|
||
paper-radio-button::shadow #ink[checked] {
|
||
color: #4285f4;
|
||
}
|
||
|
||
To change the radio checked color:
|
||
|
||
paper-radio-button::shadow #onRadio {
|
||
background-color: #4285f4;
|
||
}
|
||
|
||
To change the ink color for unchecked state:
|
||
|
||
paper-radio-button::shadow #ink {
|
||
color: #b5b5b5;
|
||
}
|
||
|
||
To change the radio unchecked color:
|
||
|
||
paper-radio-button::shadow #offRadio {
|
||
border-color: #b5b5b5;
|
||
}
|
||
|
||
@group Paper Elements
|
||
@element paper-radio-button
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
<!--
|
||
@license
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`core-a11y-keys` provides a normalized interface for processing keyboard commands that pertain to [WAI-ARIA best
|
||
practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding). The element takes care of browser differences
|
||
with respect to Keyboard events and uses an expressive syntax to filter key presses.
|
||
|
||
Use the `keys` attribute to express what combination of keys will trigger the event to fire.
|
||
|
||
Use the `target` attribute to set up event handlers on a specific node.
|
||
The `keys-pressed` event will fire when one of the key combinations set with the `keys` attribute is pressed.
|
||
|
||
Example:
|
||
|
||
This element will call `arrowHandler` on all arrow keys:
|
||
|
||
<core-a11y-keys target="{{}}" keys="up down left right" on-keys-pressed="{{arrowHandler}}"></core-a11y-keys>
|
||
|
||
Keys Syntax:
|
||
|
||
The `keys` attribute can accepts a space seprated, `+` concatenated set of modifier keys and some common keyboard keys.
|
||
|
||
The common keys are `a-z`, `0-9` (top row and number pad), `*` (shift 8 and number pad), `F1-F12`, `Page Up`, `Page
|
||
Down`, `Left Arrow`, `Right Arrow`, `Down Arrow`, `Up Arrow`, `Home`, `End`, `Escape`, `Space`, `Tab`, and `Enter` keys.
|
||
|
||
The modifier keys are `Shift`, `Control`, and `Alt`.
|
||
|
||
All keys are expected to be lowercase and shortened:
|
||
`Left Arrow` is `left`, `Page Down` is `pagedown`, `Control` is `ctrl`, `F1` is `f1`, `Escape` is `esc` etc.
|
||
|
||
Keys Syntax Example:
|
||
|
||
Given the `keys` attribute value "ctrl+shift+f7 up pagedown esc space alt+m", the `<core-a11y-keys>` element will send
|
||
the `keys-pressed` event if any of the follow key combos are pressed: Control and Shift and F7 keys, Up Arrow key, Page
|
||
Down key, Escape key, Space key, Alt and M key.
|
||
|
||
Slider Example:
|
||
|
||
The following is an example of the set of keys that fulfil the WAI-ARIA "slider" role [best
|
||
practices](http://www.w3.org/TR/wai-aria-practices/#slider):
|
||
|
||
<core-a11y-keys target="{{}}" keys="left pagedown down" on-keys-pressed="{{decrement}}"></core-a11y-keys>
|
||
<core-a11y-keys target="{{}}" keys="right pageup up" on-keys-pressed="{{increment}}"></core-a11y-keys>
|
||
<core-a11y-keys target="{{}}" keys="home" on-keys-pressed="{{setMin}}"></core-a11y-keys>
|
||
<core-a11y-keys target="{{}}" keys="end" on-keys-pressed="{{setMax}}"></core-a11y-keys>
|
||
|
||
The `increment` function will move the slider a set amount toward the maximum value.
|
||
The `decrement` function will move the slider a set amount toward the minimum value.
|
||
The `setMin` function will move the slider to the minimum value.
|
||
The `setMax` function will move the slider to the maximum value.
|
||
|
||
Keys Syntax Grammar:
|
||
|
||
[EBNF](http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form) Grammar of the `keys` attribute.
|
||
|
||
modifier = "shift" | "ctrl" | "alt";
|
||
ascii = ? /[a-z0-9]/ ? ;
|
||
fnkey = ? f1 through f12 ? ;
|
||
arrow = "up" | "down" | "left" | "right" ;
|
||
key = "tab" | "esc" | "space" | "*" | "pageup" | "pagedown" | "home" | "end" | arrow | ascii | fnkey ;
|
||
keycombo = { modifier, "+" }, key ;
|
||
keys = keycombo, { " ", keycombo } ;
|
||
|
||
@group Core Elements
|
||
@element core-a11y-keys
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<style shim-shadowdom="">
|
||
html /deep/ core-a11y-keys {
|
||
display: none;
|
||
}
|
||
</style>
|
||
|
||
<polymer-element name="core-a11y-keys" assetpath="polymer/bower_components/core-a11y-keys/">
|
||
<script>
|
||
(function() {
|
||
/*
|
||
* Chrome uses an older version of DOM Level 3 Keyboard Events
|
||
*
|
||
* Most keys are labeled as text, but some are Unicode codepoints.
|
||
* Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html#KeySet-Set
|
||
*/
|
||
var KEY_IDENTIFIER = {
|
||
'U+0009': 'tab',
|
||
'U+001B': 'esc',
|
||
'U+0020': 'space',
|
||
'U+002A': '*',
|
||
'U+0030': '0',
|
||
'U+0031': '1',
|
||
'U+0032': '2',
|
||
'U+0033': '3',
|
||
'U+0034': '4',
|
||
'U+0035': '5',
|
||
'U+0036': '6',
|
||
'U+0037': '7',
|
||
'U+0038': '8',
|
||
'U+0039': '9',
|
||
'U+0041': 'a',
|
||
'U+0042': 'b',
|
||
'U+0043': 'c',
|
||
'U+0044': 'd',
|
||
'U+0045': 'e',
|
||
'U+0046': 'f',
|
||
'U+0047': 'g',
|
||
'U+0048': 'h',
|
||
'U+0049': 'i',
|
||
'U+004A': 'j',
|
||
'U+004B': 'k',
|
||
'U+004C': 'l',
|
||
'U+004D': 'm',
|
||
'U+004E': 'n',
|
||
'U+004F': 'o',
|
||
'U+0050': 'p',
|
||
'U+0051': 'q',
|
||
'U+0052': 'r',
|
||
'U+0053': 's',
|
||
'U+0054': 't',
|
||
'U+0055': 'u',
|
||
'U+0056': 'v',
|
||
'U+0057': 'w',
|
||
'U+0058': 'x',
|
||
'U+0059': 'y',
|
||
'U+005A': 'z',
|
||
'U+007F': 'del'
|
||
};
|
||
|
||
/*
|
||
* Special table for KeyboardEvent.keyCode.
|
||
* KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even better than that
|
||
*
|
||
* Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode#Value_of_keyCode
|
||
*/
|
||
var KEY_CODE = {
|
||
13: 'enter',
|
||
27: 'esc',
|
||
33: 'pageup',
|
||
34: 'pagedown',
|
||
35: 'end',
|
||
36: 'home',
|
||
32: 'space',
|
||
37: 'left',
|
||
38: 'up',
|
||
39: 'right',
|
||
40: 'down',
|
||
46: 'del',
|
||
106: '*'
|
||
};
|
||
|
||
/*
|
||
* KeyboardEvent.key is mostly represented by printable character made by the keyboard, with unprintable keys labeled
|
||
* nicely.
|
||
*
|
||
* However, on OS X, Alt+char can make a Unicode character that follows an Apple-specific mapping. In this case, we
|
||
* fall back to .keyCode.
|
||
*/
|
||
var KEY_CHAR = /[a-z0-9*]/;
|
||
|
||
function transformKey(key) {
|
||
var validKey = '';
|
||
if (key) {
|
||
var lKey = key.toLowerCase();
|
||
if (lKey.length == 1) {
|
||
if (KEY_CHAR.test(lKey)) {
|
||
validKey = lKey;
|
||
}
|
||
} else if (lKey == 'multiply') {
|
||
// numpad '*' can map to Multiply on IE/Windows
|
||
validKey = '*';
|
||
} else {
|
||
validKey = lKey;
|
||
}
|
||
}
|
||
return validKey;
|
||
}
|
||
|
||
var IDENT_CHAR = /U\+/;
|
||
function transformKeyIdentifier(keyIdent) {
|
||
var validKey = '';
|
||
if (keyIdent) {
|
||
if (IDENT_CHAR.test(keyIdent)) {
|
||
validKey = KEY_IDENTIFIER[keyIdent];
|
||
} else {
|
||
validKey = keyIdent.toLowerCase();
|
||
}
|
||
}
|
||
return validKey;
|
||
}
|
||
|
||
function transformKeyCode(keyCode) {
|
||
var validKey = '';
|
||
if (Number(keyCode)) {
|
||
if (keyCode >= 65 && keyCode <= 90) {
|
||
// ascii a-z
|
||
// lowercase is 32 offset from uppercase
|
||
validKey = String.fromCharCode(32 + keyCode);
|
||
} else if (keyCode >= 112 && keyCode <= 123) {
|
||
// function keys f1-f12
|
||
validKey = 'f' + (keyCode - 112);
|
||
} else if (keyCode >= 48 && keyCode <= 57) {
|
||
// top 0-9 keys
|
||
validKey = String(48 - keyCode);
|
||
} else if (keyCode >= 96 && keyCode <= 105) {
|
||
// num pad 0-9
|
||
validKey = String(96 - keyCode);
|
||
} else {
|
||
validKey = KEY_CODE[keyCode];
|
||
}
|
||
}
|
||
return validKey;
|
||
}
|
||
|
||
function keyboardEventToKey(ev) {
|
||
// fall back from .key, to .keyIdentifier, and then to .keyCode
|
||
var normalizedKey = transformKey(ev.key) || transformKeyIdentifier(ev.keyIdentifier) || transformKeyCode(ev.keyCode) || '';
|
||
return {
|
||
shift: ev.shiftKey,
|
||
ctrl: ev.ctrlKey,
|
||
meta: ev.metaKey,
|
||
alt: ev.altKey,
|
||
key: normalizedKey
|
||
};
|
||
}
|
||
|
||
/*
|
||
* Input: ctrl+shift+f7 => {ctrl: true, shift: true, key: 'f7'}
|
||
* ctrl/space => {ctrl: true} || {key: space}
|
||
*/
|
||
function stringToKey(keyCombo) {
|
||
var keys = keyCombo.split('+');
|
||
var keyObj = Object.create(null);
|
||
keys.forEach(function(key) {
|
||
if (key == 'shift') {
|
||
keyObj.shift = true;
|
||
} else if (key == 'ctrl') {
|
||
keyObj.ctrl = true;
|
||
} else if (key == 'alt') {
|
||
keyObj.alt = true;
|
||
} else {
|
||
keyObj.key = key;
|
||
}
|
||
});
|
||
return keyObj;
|
||
}
|
||
|
||
function keyMatches(a, b) {
|
||
return Boolean(a.alt) == Boolean(b.alt) && Boolean(a.ctrl) == Boolean(b.ctrl) && Boolean(a.shift) == Boolean(b.shift) && a.key === b.key;
|
||
}
|
||
|
||
/**
|
||
* Fired when a keycombo in `keys` is pressed.
|
||
*
|
||
* @event keys-pressed
|
||
*/
|
||
function processKeys(ev) {
|
||
var current = keyboardEventToKey(ev);
|
||
for (var i = 0, dk; i < this._desiredKeys.length; i++) {
|
||
dk = this._desiredKeys[i];
|
||
if (keyMatches(dk, current)) {
|
||
ev.preventDefault();
|
||
ev.stopPropagation();
|
||
this.fire('keys-pressed', current, this, false);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
function listen(node, handler) {
|
||
if (node && node.addEventListener) {
|
||
node.addEventListener('keydown', handler);
|
||
}
|
||
}
|
||
|
||
function unlisten(node, handler) {
|
||
if (node && node.removeEventListener) {
|
||
node.removeEventListener('keydown', handler);
|
||
}
|
||
}
|
||
|
||
Polymer('core-a11y-keys', {
|
||
created: function() {
|
||
this._keyHandler = processKeys.bind(this);
|
||
},
|
||
attached: function() {
|
||
listen(this.target, this._keyHandler);
|
||
},
|
||
detached: function() {
|
||
unlisten(this.target, this._keyHandler);
|
||
},
|
||
publish: {
|
||
/**
|
||
* The set of key combinations to listen for.
|
||
*
|
||
* @attribute keys
|
||
* @type string (keys syntax)
|
||
* @default ''
|
||
*/
|
||
keys: '',
|
||
/**
|
||
* The node that will fire keyboard events.
|
||
*
|
||
* @attribute target
|
||
* @type Node
|
||
* @default null
|
||
*/
|
||
target: null
|
||
},
|
||
keysChanged: function() {
|
||
// * can have multiple mappings: shift+8, * on numpad or Multiply on numpad
|
||
var normalized = this.keys.replace('*', '* shift+*');
|
||
this._desiredKeys = normalized.toLowerCase().split(' ').map(stringToKey);
|
||
},
|
||
targetChanged: function(oldTarget) {
|
||
unlisten(oldTarget, this._keyHandler);
|
||
listen(this.target, this._keyHandler);
|
||
}
|
||
});
|
||
})();
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="paper-radio-button" role="radio" tabindex="0" aria-checked="false" assetpath="polymer/bower_components/paper-radio-button/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: inline-block;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
:host(:focus) {
|
||
outline: none;
|
||
}
|
||
|
||
#radioContainer {
|
||
position: relative;
|
||
width: 16px;
|
||
height: 16px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
#radioContainer.labeled {
|
||
display: inline-block;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
#ink {
|
||
position: absolute;
|
||
top: -16px;
|
||
left: -16px;
|
||
width: 48px;
|
||
height: 48px;
|
||
color: #5a5a5a;
|
||
}
|
||
|
||
#ink[checked] {
|
||
color: #0f9d58;
|
||
}
|
||
|
||
#offRadio {
|
||
position: absolute;
|
||
top: 0px;
|
||
left: 0px;
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 50%;
|
||
border: solid 2px;
|
||
border-color: #5a5a5a;
|
||
}
|
||
|
||
#onRadio {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 50%;
|
||
background-color: #0f9d58;
|
||
-webkit-transform: scale(0);
|
||
transform: scale(0);
|
||
transition: -webkit-transform ease 0.28s;
|
||
transition: transform ease 0.28s;
|
||
}
|
||
|
||
#onRadio.fill {
|
||
-webkit-transform: scale(1.1);
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
#radioLabel {
|
||
position: relative;
|
||
display: inline-block;
|
||
vertical-align: middle;
|
||
margin-left: 10px;
|
||
white-space: normal;
|
||
pointer-events: none;
|
||
}
|
||
|
||
#radioLabel[hidden] {
|
||
display: none;
|
||
}
|
||
|
||
/* disabled state */
|
||
:host([disabled]) {
|
||
pointer-events: none;
|
||
}
|
||
|
||
:host([disabled]) #onRadio {
|
||
display: none;
|
||
}
|
||
|
||
:host([disabled]) #offRadio {
|
||
opacity: 0.33;
|
||
border-color: #5a5a5a;
|
||
}
|
||
|
||
:host([disabled][checked]) #offRadio {
|
||
opacity: 0.33;
|
||
background-color: #5a5a5a;
|
||
}
|
||
</style>
|
||
|
||
<core-a11y-keys target="{{}}" keys="space" on-keys-pressed="{{tap}}"></core-a11y-keys>
|
||
|
||
<div id="radioContainer" class="{{ {labeled: label} | tokenList }}">
|
||
|
||
<div id="offRadio"></div>
|
||
<div id="onRadio"></div>
|
||
|
||
<paper-ripple id="ink" class="circle recenteringTouch" checked?="{{!checked}}"></paper-ripple>
|
||
|
||
</div>
|
||
|
||
<div id="radioLabel" aria-hidden="true" hidden?="{{!label}}">{{label}}<content></content></div>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('paper-radio-button', {
|
||
|
||
/**
|
||
* Fired when the checked state changes due to user interaction.
|
||
*
|
||
* @event change
|
||
*/
|
||
|
||
/**
|
||
* Fired when the checked state changes.
|
||
*
|
||
* @event core-change
|
||
*/
|
||
|
||
publish: {
|
||
/**
|
||
* Gets or sets the state, `true` is checked and `false` is unchecked.
|
||
*
|
||
* @attribute checked
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
checked: {value: false, reflect: true},
|
||
|
||
/**
|
||
* The label for the radio button.
|
||
*
|
||
* @attribute label
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
label: '',
|
||
|
||
/**
|
||
* Normally the user cannot uncheck the radio button by tapping once
|
||
* checked. Setting this property to `true` makes the radio button
|
||
* toggleable from checked to unchecked.
|
||
*
|
||
* @attribute toggles
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
toggles: false,
|
||
|
||
/**
|
||
* If true, the user cannot interact with this element.
|
||
*
|
||
* @attribute disabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
disabled: {value: false, reflect: true}
|
||
},
|
||
|
||
eventDelegates: {
|
||
tap: 'tap'
|
||
},
|
||
|
||
tap: function() {
|
||
var old = this.checked;
|
||
this.toggle();
|
||
if (this.checked !== old) {
|
||
this.fire('change');
|
||
}
|
||
},
|
||
|
||
toggle: function() {
|
||
this.checked = !this.toggles || !this.checked;
|
||
},
|
||
|
||
checkedChanged: function() {
|
||
this.$.onRadio.classList.toggle('fill', this.checked);
|
||
this.setAttribute('aria-checked', this.checked ? 'true': 'false');
|
||
this.fire('core-change');
|
||
},
|
||
|
||
labelChanged: function() {
|
||
this.setAttribute('aria-label', this.label);
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="paper-toggle-button" attributes="checked" role="button" aria-pressed="false" tabindex="0" assetpath="polymer/bower_components/paper-toggle-button/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: inline-block;
|
||
}
|
||
|
||
:host(:focus) {
|
||
outline: none;
|
||
}
|
||
|
||
#toggleContainer {
|
||
position: relative;
|
||
width: 64px;
|
||
height: 16px;
|
||
}
|
||
|
||
#toggleBar {
|
||
position: absolute;
|
||
top: 8px;
|
||
left: 16px;
|
||
height: 1px;
|
||
width: 32px;
|
||
background-color: #5a5a5a;
|
||
pointer-events: none;
|
||
}
|
||
|
||
#toggleBar[checked] {
|
||
background-color: #0f9d58;
|
||
}
|
||
|
||
#toggleContainer[checked] #checkedBar {
|
||
width: 100%;
|
||
}
|
||
|
||
#toggleRadio {
|
||
position: absolute;
|
||
left: 0;
|
||
padding: 8px 48px 8px 0;
|
||
margin: -8px -48px -8px 0;
|
||
transition: -webkit-transform linear .08s;
|
||
transition: transform linear .08s;
|
||
}
|
||
|
||
#toggleRadio[checked] {
|
||
-webkit-transform: translate(48px, 0);
|
||
transform: translate(48px, 0);
|
||
padding: 8px 0 8px 48px;
|
||
margin: -8px 0 -8px -48px;
|
||
}
|
||
|
||
#toggleRadio.dragging {
|
||
-webkit-transition: none;
|
||
transition: none;
|
||
}</style>
|
||
|
||
<div id="toggleContainer">
|
||
|
||
<div id="toggleBar" checked?="{{checked}}"></div>
|
||
|
||
<paper-radio-button id="toggleRadio" toggles="" checked="{{checked}}" on-change="{{changeAction}}" on-core-change="{{stopPropagation}}" on-trackstart="{{trackStart}}" on-trackx="{{trackx}}" on-trackend="{{trackEnd}}"></paper-radio-button>
|
||
|
||
</div>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('paper-toggle-button', {
|
||
|
||
/**
|
||
* Fired when the checked state changes due to user interaction.
|
||
*
|
||
* @event change
|
||
*/
|
||
|
||
/**
|
||
* Fired when the checked state changes.
|
||
*
|
||
* @event core-change
|
||
*/
|
||
|
||
/**
|
||
* Gets or sets the state, `true` is checked and `false` is unchecked.
|
||
*
|
||
* @attribute checked
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
checked: false,
|
||
|
||
trackStart: function(e) {
|
||
this._w = this.$.toggleBar.offsetLeft + this.$.toggleBar.offsetWidth;
|
||
e.preventTap();
|
||
},
|
||
|
||
trackx: function(e) {
|
||
this._x = Math.min(this._w,
|
||
Math.max(0, this.checked ? this._w + e.dx : e.dx));
|
||
this.$.toggleRadio.classList.add('dragging');
|
||
var s = this.$.toggleRadio.style;
|
||
s.webkitTransform = s.transform = 'translate3d(' + this._x + 'px,0,0)';
|
||
},
|
||
|
||
trackEnd: function() {
|
||
var s = this.$.toggleRadio.style;
|
||
s.transform = s.webkitTransform = '';
|
||
this.$.toggleRadio.classList.remove('dragging');
|
||
var old = this.checked;
|
||
this.checked = Math.abs(this._x) > this._w / 2;
|
||
if (this.checked !== old) {
|
||
this.fire('change');
|
||
}
|
||
},
|
||
|
||
checkedChanged: function() {
|
||
this.setAttribute('aria-pressed', Boolean(this.checked));
|
||
this.fire('core-change');
|
||
},
|
||
|
||
changeAction: function(e) {
|
||
e.stopPropagation();
|
||
this.fire('change');
|
||
},
|
||
|
||
stopPropagation: function(e) {
|
||
e.stopPropagation();
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
|
||
<core-iconset-svg id="social" iconsize="24">
|
||
<svg><defs>
|
||
<g id="cake"><path d="M12,7c1.1,0,2-0.9,2-2c0-0.4-0.1-0.7-0.3-1L12,1l-1.7,3C10.1,4.3,10,4.6,10,5C10,6.1,10.9,7,12,7z M21,21v-4c0-1.1-0.9-2-2-2h-1v-3c0-1.1-0.9-2-2-2h-3V8h-2v2H8c-1.1,0-2,0.9-2,2v3H5c-1.1,0-2,0.9-2,2v4H1v2h22v-2H21z"/></g>
|
||
<g id="circles"><path d="M16.7,15c-0.8,2.3-3,4-5.7,4c-3.3,0-6-2.7-6-6c0-2.6,1.7-4.8,4-5.7C9,7.2,9,7.1,9,7c0-1,0.2-2,0.5-2.9C5.3,4.8,2,8.5,2,13c0,5,4,9,9,9c4.5,0,8.2-3.3,8.9-7.5C19,14.8,18,15,17,15C16.9,15,16.8,15,16.7,15z"/><path d="M17,1c-3.3,0-6,2.7-6,6s2.7,6,6,6c3.3,0,6-2.7,6-6S20.3,1,17,1z M17,10c-1.7,0-3-1.3-3-3s1.3-3,3-3c1.7,0,3,1.3,3,3S18.7,10,17,10z"/></g>
|
||
<g id="circles-add"><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10s10-4.5,10-10C22,6.5,17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/><path d="M13,11V8h-2v3H8v2h3v3h2v-3h3v-2H13z"/></g>
|
||
<g id="circles-extended"><path d="M12,10c2.2,0,4-1.8,4-4c0-2.2-1.8-4-4-4C9.8,2,8,3.8,8,6C8,8.2,9.8,10,12,10z M12,4c1.1,0,2,0.9,2,2c0,1.1-0.9,2-2,2c-1.1,0-2-0.9-2-2C10,4.9,10.9,4,12,4z M6,13c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C10,14.8,8.2,13,6,13z M6,19c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2c1.1,0,2,0.9,2,2C8,18.1,7.1,19,6,19z M12,11.1c-1,0-1.9,0.9-1.9,1.9s0.9,1.9,1.9,1.9c1,0,1.9-0.9,1.9-1.9S13,11.1,12,11.1z M18,13c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C22,14.8,20.2,13,18,13z M18,19c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2c1.1,0,2,0.9,2,2C20,18.1,19.1,19,18,19z"/></g>
|
||
<g id="communities"><path d="M9,12c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S10.1,12,9,12z M14,9c0-1.1-0.9-2-2-2c-1.1,0-2,0.9-2,2s0.9,2,2,2C13.1,11,14,10.1,14,9z M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8c0-4.4,3.6-8,8-8c4.4,0,8,3.6,8,8C20,16.4,16.4,20,12,20z M15,12c-1.1,0-2,0.9-2,2s0.9,2,2,2c1.1,0,2-0.9,2-2S16.1,12,15,12z"/></g>
|
||
<g id="domain"><path d="M12,7V3H2v18h20V7H12z M6,19H4v-2h2V19z M6,15H4v-2h2V15z M6,11H4V9h2V11z M6,7H4V5h2V7z M10,19H8v-2h2V19z M10,15H8v-2h2V15z M10,11H8V9h2V11z M10,7H8V5h2V7z M20,19h-8v-2h2v-2h-2v-2h2v-2h-2V9h8V19z M18,11h-2v2h2V11z M18,15h-2v2h2V15z"/></g>
|
||
<g id="group"><path d="M16,11c1.7,0,3-1.3,3-3c0-1.7-1.3-3-3-3c-1.7,0-3,1.3-3,3C13,9.7,14.3,11,16,11z M8,11c1.7,0,3-1.3,3-3c0-1.7-1.3-3-3-3C6.3,5,5,6.3,5,8C5,9.7,6.3,11,8,11z M8,13c-2.3,0-7,1.2-7,3.5V19h14v-2.5C15,14.2,10.3,13,8,13z M16,13c-0.3,0-0.6,0-1,0.1c1.2,0.8,2,2,2,3.4V19h6v-2.5C23,14.2,18.3,13,16,13z"/></g>
|
||
<g id="group-add"><path d="M8,10H5V7H3v3H0v2h3v3h2v-3h3V10z M18,11c1.7,0,3-1.3,3-3c0-1.7-1.3-3-3-3c-0.3,0-0.6,0.1-0.9,0.1C17.7,6,18,6.9,18,8s-0.3,2-0.9,2.9C17.4,10.9,17.7,11,18,11z M13,11c1.7,0,3-1.3,3-3c0-1.7-1.3-3-3-3c-1.7,0-3,1.3-3,3C10,9.7,11.3,11,13,11z M19.6,13.2c0.8,0.7,1.4,1.7,1.4,2.8v2h3v-2C24,14.5,21.6,13.5,19.6,13.2z M13,13c-2,0-6,1-6,3v2h12v-2C19,14,15,13,13,13z"/></g>
|
||
<g id="location-city"><path d="M15,11V5l-3-3L9,5v2H3v14h18V11H15z M7,19H5v-2h2V19z M7,15H5v-2h2V15z M7,11H5V9h2V11z M13,19h-2v-2h2V19z M13,15h-2v-2h2V15z M13,11h-2V9h2V11z M13,7h-2V5h2V7z M19,19h-2v-2h2V19z M19,15h-2v-2h2V15z"/></g>
|
||
<g id="mood"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z M15.5,11c0.8,0,1.5-0.7,1.5-1.5S16.3,8,15.5,8S14,8.7,14,9.5S14.7,11,15.5,11z M8.5,11c0.8,0,1.5-0.7,1.5-1.5S9.3,8,8.5,8S7,8.7,7,9.5S7.7,11,8.5,11z M12,17.5c2.3,0,4.3-1.5,5.1-3.5H6.9C7.7,16,9.7,17.5,12,17.5z"/></g>
|
||
<g id="notifications"><path d="M11.5,22c1.1,0,2-0.9,2-2h-4C9.5,21.1,10.4,22,11.5,22z M18,16v-5.5c0-3.1-2.1-5.6-5-6.3V3.5C13,2.7,12.3,2,11.5,2C10.7,2,10,2.7,10,3.5v0.7c-2.9,0.7-5,3.2-5,6.3V16l-2,2v1h17v-1L18,16z"/></g>
|
||
<g id="notifications-none"><path d="M11.5,22c1.1,0,2-0.9,2-2h-4C9.5,21.1,10.4,22,11.5,22z M18,16v-5.5c0-3.1-2.1-5.6-5-6.3V3.5C13,2.7,12.3,2,11.5,2C10.7,2,10,2.7,10,3.5v0.7c-2.9,0.7-5,3.2-5,6.3V16l-2,2v1h17v-1L18,16z M16,17H7v-6.5C7,8,9,6,11.5,6C14,6,16,8,16,10.5V17z"/></g>
|
||
<g id="notifications-off"><path d="M11.5,22c1.1,0,2-0.9,2-2h-4C9.5,21.1,10.4,22,11.5,22z M18,10.5c0-3.1-2.1-5.6-5-6.3V3.5C13,2.7,12.3,2,11.5,2C10.7,2,10,2.7,10,3.5v0.7C9.5,4.3,9,4.5,8.6,4.7l9.4,9.4V10.5z M17.7,19l2,2l1.3-1.3L4.3,3L3,4.3l2.9,2.9C5.3,8.2,5,9.3,5,10.5V16l-2,2v1H17.7z"/></g>
|
||
<g id="notifications-on"><path d="M6.6,3.6L5.2,2.2C2.8,4,1.2,6.8,1,10h2C3.2,7.3,4.5,5,6.6,3.6z M20,10h2c-0.2-3.2-1.7-6-4.1-7.8l-1.4,1.4C18.5,5,19.8,7.3,20,10z M18,10.5c0-3.1-2.1-5.6-5-6.3V3.5C13,2.7,12.3,2,11.5,2C10.7,2,10,2.7,10,3.5v0.7c-2.9,0.7-5,3.2-5,6.3V16l-2,2v1h17v-1l-2-2V10.5z M11.5,22c0.1,0,0.3,0,0.4,0c0.7-0.1,1.2-0.6,1.4-1.2c0.1-0.2,0.2-0.5,0.2-0.8h-4C9.5,21.1,10.4,22,11.5,22z"/></g>
|
||
<g id="notifications-paused"><path d="M11.5,22c1.1,0,2-0.9,2-2h-4C9.5,21.1,10.4,22,11.5,22z M18,16v-5.5c0-3.1-2.1-5.6-5-6.3V3.5C13,2.7,12.3,2,11.5,2C10.7,2,10,2.7,10,3.5v0.7c-2.9,0.7-5,3.2-5,6.3V16l-2,2v1h17v-1L18,16z M14,9.8l-2.8,3.4H14V15H9v-1.8l2.8-3.4H9V8h5V9.8z"/></g>
|
||
<g id="pages"><path d="M3,5v6h5L7,7l4,1V3H5C3.9,3,3,3.9,3,5z M8,13H3v6c0,1.1,0.9,2,2,2h6v-5l-4,1L8,13z M17,17l-4-1v5h6c1.1,0,2-0.9,2-2v-6l-5,0L17,17z M19,3h-6v5l4-1l-1,4h5V5C21,3.9,20.1,3,19,3z"/></g>
|
||
<g id="party-mode"><path d="M20,4h-3.2L15,2H9L7.2,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M12,7c1.6,0,3.1,0.8,4,2h-4c-1.7,0-3,1.3-3,3c0,0.4,0.1,0.7,0.2,1H7.1C7,12.7,7,12.3,7,12C7,9.2,9.2,7,12,7z M12,17c-1.6,0-3.1-0.8-4-2h4c1.7,0,3-1.3,3-3c0-0.4-0.1-0.7-0.2-1h2.1c0.1,0.3,0.1,0.7,0.1,1C17,14.8,14.8,17,12,17z"/></g>
|
||
<g id="people"><path d="M16,11c1.7,0,3-1.3,3-3c0-1.7-1.3-3-3-3c-1.7,0-3,1.3-3,3C13,9.7,14.3,11,16,11z M8,11c1.7,0,3-1.3,3-3c0-1.7-1.3-3-3-3C6.3,5,5,6.3,5,8C5,9.7,6.3,11,8,11z M8,13c-2.3,0-7,1.2-7,3.5V19h14v-2.5C15,14.2,10.3,13,8,13z M16,13c-0.3,0-0.6,0-1,0.1c1.2,0.8,2,2,2,3.4V19h6v-2.5C23,14.2,18.3,13,16,13z"/></g>
|
||
<g id="person"><path d="M12,12c2.2,0,4-1.8,4-4c0-2.2-1.8-4-4-4C9.8,4,8,5.8,8,8C8,10.2,9.8,12,12,12z M12,14c-2.7,0-8,1.3-8,4v2h16v-2C20,15.3,14.7,14,12,14z"/></g>
|
||
<g id="person-add"><path d="M15,12c2.2,0,4-1.8,4-4c0-2.2-1.8-4-4-4c-2.2,0-4,1.8-4,4C11,10.2,12.8,12,15,12z M6,10V7H4v3H1v2h3v3h2v-3h3v-2H6z M15,14c-2.7,0-8,1.3-8,4v2h16v-2C23,15.3,17.7,14,15,14z"/></g>
|
||
<g id="person-outline"><path d="M12,5.9c1.2,0,2.1,0.9,2.1,2.1s-0.9,2.1-2.1,2.1S9.9,9.2,9.9,8S10.8,5.9,12,5.9 M12,14.9c3,0,6.1,1.5,6.1,2.1v1.1H5.9V17C5.9,16.4,9,14.9,12,14.9 M12,4C9.8,4,8,5.8,8,8c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,5.8,14.2,4,12,4L12,4z M12,13c-2.7,0-8,1.3-8,4v3h16v-3C20,14.3,14.7,13,12,13L12,13z"/></g>
|
||
<g id="plus-one"><polygon points="10,8 8,8 8,12 4,12 4,14 8,14 8,18 10,18 10,14 14,14 14,12 10,12 "/></g>
|
||
<g id="poll"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M9,17H7v-7h2V17z M13,17h-2V7h2V17z M17,17h-2v-4h2V17z"/></g>
|
||
<g id="post-blogger"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M16,9v1c0,0.6,0.4,1,1,1c0.6,0,1,0.4,1,1v3c0,1.7-1.3,3-3,3H9c-1.7,0-3-1.3-3-3V8c0-1.7,1.3-3,3-3h4c1.7,0,3,1.3,3,3V9z M10,10h2.6c0.6,0,1-0.4,1-1c0-0.6-0.4-1-1-1H10C9.4,8,9,8.4,9,9C9,9.6,9.4,10,10,10z M14,13h-4c-0.6,0-1,0.4-1,1c0,0.6,0.4,1,1,1h4c0.6,0,1-0.4,1-1C15,13.4,14.6,13,14,13z"/></g>
|
||
<g id="post-facebook"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M19,4v3h-2c-0.6,0-1,0.4-1,1v2h3v3h-3v7h-3v-7h-2v-3h2V7.5C13,5.6,14.6,4,16.5,4H19z"/></g>
|
||
<g id="post-github"><path d="M7.2 6.6h-.1c-.5 1.4-.2 2.3-.1 2.6-.6.7-1 1.6-1 2.6 0 3.8 2.4 4.6 4.6 4.9-.2 0-.6.2-.8.8-.4.2-1.8.7-2.6-.7 0 0-.5-.8-1.3-.9 0 0-.8 0-.1.5 0 0 .6.3.9 1.3 0 0 .5 1.7 3 1.1v3.1h5v-3.5c0-1-.4-1.5-.8-1.8 2.2-.2 4.6-1 4.6-4.8 0-1.1-.4-2-1-2.6.1-.3.4-1.2-.1-2.6 0 0-.8-.3-2.7 1-.8-.2-1.6-.3-2.5-.3-.8 0-1.7.1-2.5.3-1.4-1-2.2-1-2.6-1zm12.8 15.4h-16c-1.1 0-2-.9-2-2v-16c0-1.1.9-2 2-2h16c1.1 0 2 .9 2 2v16c0 1.1-.9 2-2 2z"/></g>
|
||
<g id="post-gplus"><path d="M11.2,8.9c0-1-0.6-3-2.1-3c-0.6,0-1.3,0.4-1.3,1.7c0,1.2,0.6,2.9,2,2.9C9.8,10.5,11.2,10.4,11.2,8.9z M10.6,13.8c-0.1,0-0.2,0-0.3,0h0c-0.3,0-1.2,0.1-1.8,0.3C7.8,14.3,7,14.8,7,15.8c0,1.1,1,2.2,3,2.2c1.5,0,2.4-1,2.4-2C12.4,15.3,11.9,14.8,10.6,13.8z M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M9.1,19.2c-2.8,0-4.1-1.6-4.1-3c0-0.5,0.1-1.6,1.5-2.4c0.8-0.5,1.8-0.8,3.1-0.9c-0.2-0.2-0.3-0.5-0.3-1c0-0.2,0-0.3,0.1-0.5H9c-2,0-3.2-1.5-3.2-3c0-1.7,1.3-3.6,4.1-3.6h4.2l-0.3,0.3l-0.7,0.7L13,5.9h-0.7c0.4,0.4,0.9,1.1,0.9,2.2c0,1.4-0.7,2.1-1.6,2.7c-0.2,0.1-0.4,0.4-0.4,0.7c0,0.3,0.2,0.5,0.4,0.6c0.1,0.1,0.3,0.2,0.5,0.3c0.8,0.6,1.9,1.3,1.9,2.9C14,17.1,12.7,19.2,9.1,19.2z M19,12h-2v2h-1v-2h-2v-1h2V9h1v2h2V12z"/></g>
|
||
<g id="post-instagram"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M12,8c2.2,0,4,1.8,4,4s-1.8,4-4,4c-2.2,0-4-1.8-4-4S9.8,8,12,8z M4.5,20C4.2,20,4,19.8,4,19.5V11h2.1C6,11.3,6,11.7,6,12c0,3.3,2.7,6,6,6c3.3,0,6-2.7,6-6c0-0.3,0-0.7-0.1-1H20v8.5c0,0.3-0.2,0.5-0.5,0.5H4.5z M20,6.5C20,6.8,19.8,7,19.5,7h-2C17.2,7,17,6.8,17,6.5v-2C17,4.2,17.2,4,17.5,4h2C19.8,4,20,4.2,20,4.5V6.5z"/></g>
|
||
<g id="post-linkedin"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M8,19H5v-9h3V19z M6.5,8.3c-1,0-1.8-0.8-1.8-1.8s0.8-1.8,1.8-1.8s1.8,0.8,1.8,1.8S7.5,8.3,6.5,8.3z M19,19h-3v-5.3c0-0.8-0.7-1.5-1.5-1.5c-0.8,0-1.5,0.7-1.5,1.5V19h-3v-9h3v1.2c0.5-0.8,1.6-1.4,2.5-1.4c1.9,0,3.5,1.6,3.5,3.5V19z"/></g>
|
||
<g id="post-pinterest"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M13,16.2c-0.8,0-1.6-0.3-2.1-0.9l-1,3.2l-0.1,0.2l0,0c-0.2,0.3-0.5,0.5-0.9,0.5c-0.6,0-1.1-0.5-1.1-1.1c0-0.1,0-0.1,0-0.1l0,0l0.1-0.2l1.8-5.6c0,0-0.2-0.6-0.2-1.5c0-1.7,0.9-2.2,1.7-2.2c0.7,0,1.4,0.3,1.4,1.3c0,1.3-0.9,2-0.9,3c0,0.7,0.6,1.3,1.3,1.3c2.3,0,3.2-1.8,3.2-3.4c0-2.2-1.9-4-4.2-4c-2.3,0-4.2,1.8-4.2,4c0,0.7,0.2,1.3,0.5,1.9c0.1,0.2,0.1,0.3,0.1,0.5c0,0.6-0.4,1-1,1c-0.4,0-0.7-0.2-0.9-0.5c-0.5-0.9-0.8-1.9-0.8-3c0-3.3,2.8-6,6.2-6c3.4,0,6.2,2.7,6.2,6C18.2,13.4,16.6,16.2,13,16.2z"/></g>
|
||
<g id="post-tumblr"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M16,11h-3c0,0,0,3.8,0,3.9c0,0.7,0.1,1.1,1.1,1.1c0.9,0,1.9,0,1.9,0v3c0,0-1,0.1-2.1,0.1c-2.6,0-3.9-1.6-3.9-3.4c0-1.2,0-4.7,0-4.7H8V8.2c2.4-0.2,2.6-2,2.8-3.2H13v3h3V11z"/></g>
|
||
<g id="post-twitter"><path d="M20,2H4C2.9,2,2,2.9,2,4l0,16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M17.7,9.3c-0.1,4.6-3,7.8-7.4,8c-1.8,0.1-3.1-0.5-4.3-1.2c1.3,0.2,3-0.3,3.9-1.1c-1.3-0.1-2.1-0.8-2.5-1.9c0.4,0.1,0.8,0,1.1,0c-1.2-0.4-2-1.1-2.1-2.7c0.3,0.2,0.7,0.3,1.1,0.3c-0.9-0.5-1.5-2.4-0.8-3.6c1.3,1.4,2.9,2.6,5.5,2.8c-0.7-2.8,3.1-4.3,4.6-2.4c0.7-0.1,1.2-0.4,1.7-0.6c-0.2,0.7-0.6,1.1-1.1,1.5c0.5-0.1,1-0.2,1.4-0.4C18.7,8.5,18.2,8.9,17.7,9.3z"/></g>
|
||
<g id="public"><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M11,19.9c-3.9-0.5-7-3.9-7-7.9c0-0.6,0.1-1.2,0.2-1.8L9,15v1c0,1.1,0.9,2,2,2V19.9z M17.9,17.4c-0.3-0.8-1-1.4-1.9-1.4h-1v-3c0-0.6-0.4-1-1-1H8v-2h2c0.6,0,1-0.4,1-1V7h2c1.1,0,2-0.9,2-2V4.6c2.9,1.2,5,4.1,5,7.4C20,14.1,19.2,16,17.9,17.4z"/></g>
|
||
<g id="school"><path d="M5,13.2v4l7,3.8l7-3.8v-4L12,17L5,13.2z M12,3L1,9l11,6l9-4.9V17h2V9L12,3z"/></g>
|
||
<g id="share"><path d="M21,11l-7-7v4C7,9,4,14,3,19c2.5-3.5,6-5.1,11-5.1V18L21,11z"/></g>
|
||
<g id="share-alt"><path d="M18,16.1c-0.8,0-1.5,0.3-2,0.8l-7.1-4.2C9,12.5,9,12.2,9,12s0-0.5-0.1-0.7L16,7.2C16.5,7.7,17.2,8,18,8c1.7,0,3-1.3,3-3s-1.3-3-3-3s-3,1.3-3,3c0,0.2,0,0.5,0.1,0.7L8,9.8C7.5,9.3,6.8,9,6,9c-1.7,0-2.9,1.2-2.9,2.9c0,1.7,1.3,3,3,3c0.8,0,1.5-0.3,2-0.8l7.1,4.2c-0.1,0.3-0.1,0.5-0.1,0.7c0,1.6,1.3,2.9,2.9,2.9s2.9-1.3,2.9-2.9S19.6,16.1,18,16.1z"/></g>
|
||
<g id="whatshot"><path d="M13.5,0.7c0,0,0.7,2.6,0.7,4.8c0,2.1-1.4,3.7-3.4,3.7c-2.1,0-3.6-1.7-3.6-3.7l0-0.4C5.2,7.5,4,10.6,4,14c0,4.4,3.6,8,8,8c4.4,0,8-3.6,8-8C20,8.6,17.4,3.8,13.5,0.7z M11.7,19c-1.8,0-3.2-1.4-3.2-3.1c0-1.6,1-2.8,2.8-3.1c1.8-0.4,3.6-1.2,4.6-2.6c0.4,1.3,0.6,2.6,0.6,4C16.5,16.8,14.4,19,11.7,19z"/></g>
|
||
</defs></svg>
|
||
</core-iconset-svg>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
|
||
<core-iconset-svg id="image" iconsize="24">
|
||
<svg><defs>
|
||
<g id="add-to-photos"><path d="M4,6H2v14c0,1.1,0.9,2,2,2h14v-2H4V6z M20,2H8C6.9,2,6,2.9,6,4v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M19,11h-4v4h-2v-4H9V9h4V5h2v4h4V11z"/></g>
|
||
<g id="adjust"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S16.4,20,12,20z M15,12c0,1.7-1.3,3-3,3s-3-1.3-3-3s1.3-3,3-3S15,10.3,15,12z"/></g>
|
||
<g id="aspect-ratio"><path d="M16,10h-2v2h2V10z M16,14h-2v2h2V14z M8,10H6v2h2V10z M12,10h-2v2h2V10z M20,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18L4,18V6h16V18z"/></g>
|
||
<g id="assistant-photo"><polygon points="14.4,6 14,4 5,4 5,21 7,21 7,14 12.6,14 13,16 20,16 20,6 "/></g>
|
||
<g id="auto-awesome"><path d="M19,9l1.2-2.8L23,5l-2.8-1.2L19,1l-1.2,2.8L15,5l2.8,1.2L19,9z M11.5,9.5L9,4L6.5,9.5L1,12l5.5,2.5L9,20l2.5-5.5L17,12L11.5,9.5z M19,15l-1.2,2.7L15,19l2.8,1.2L19,23l1.2-2.8L23,19l-2.8-1.2L19,15z"/></g>
|
||
<g id="auto-awesome-mix"><path d="M3,5v14c0,1.1,0.9,2,2,2h6V3H5C3.9,3,3,3.9,3,5z M19,3h-6v8h8V5C21,3.9,20.1,3,19,3z M13,21h6c1.1,0,2-0.9,2-2v-6h-8V21z"/></g>
|
||
<g id="auto-awesome-motion"><path d="M14,2H4C2.9,2,2,2.9,2,4v10h2V4h10V2z M18,6H8C6.9,6,6,6.9,6,8v10h2V8h10V6z M20,10h-8c-1.1,0-2,0.9-2,2v8c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2v-8C22,10.9,21.1,10,20,10z"/></g>
|
||
<g id="auto-fix"><polygon points="7.5,5.6 10,7 8.6,4.5 10,2 7.5,3.4 5,2 6.4,4.5 5,7 "/></g>
|
||
<g id="auto-fix-high"><polygon points="7.5,5.6 10,7 8.6,4.5 10,2 7.5,3.4 5,2 6.4,4.5 5,7 "/></g>
|
||
<g id="auto-fix-normal"><polygon points="22,2 19.5,3.4 17,2 18.4,4.5 17,7 19.5,5.6 22,7 20.6,4.5 "/></g>
|
||
<g id="auto-fix-off"><path d="M23,1l-2.5,1.4L18,1l1.4,2.5L18,6l2.5-1.4L23,6l-1.4-2.5L23,1z M14.7,7.2l2.1,2.1l-2.4,2.4l0.8,0.8l2.6-2.6c0.4-0.4,0.4-1,0-1.4l-2.3-2.3c-0.4-0.4-1-0.4-1.4,0l-2.6,2.6l0.8,0.8L14.7,7.2z M13.9,13.9l-3.8-3.8h0L3.3,3.3L2,4.5l6.9,6.9L2.3,18c-0.4,0.4-0.4,1,0,1.4l2.3,2.3c0.4,0.4,1,0.4,1.4,0l6.6-6.6l6.9,6.9l1.3-1.3L13.9,13.9L13.9,13.9z"/></g>
|
||
<g id="auto-stories"><path d="M18,1l-5,4v16l5-3.9V1z M1,7v12c0,1.1,0.9,2,2,2h8V5H3C1.9,5,1,5.9,1,7z M21,5h-1v13.1l-0.8,0.6l-3,2.3H21c1.1,0,2-0.9,2-2V7C23,5.9,22.1,5,21,5z"/></g>
|
||
<g id="blur-circular"><path d="M10,9c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S10.6,9,10,9z M10,13c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S10.6,13,10,13z M7,9.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S7.3,9.5,7,9.5z M10,16.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S10.3,16.5,10,16.5z M7,13.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S7.3,13.5,7,13.5z M10,7.5c0.3,0,0.5-0.2,0.5-0.5S10.3,6.5,10,6.5S9.5,6.7,9.5,7S9.7,7.5,10,7.5z M14,9c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S14.6,9,14,9z M14,7.5c0.3,0,0.5-0.2,0.5-0.5S14.3,6.5,14,6.5S13.5,6.7,13.5,7S13.7,7.5,14,7.5z M17,13.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S17.3,13.5,17,13.5z M17,9.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S17.3,9.5,17,9.5z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S16.4,20,12,20z M14,16.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S14.3,16.5,14,16.5z M14,13c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S14.6,13,14,13z"/></g>
|
||
<g id="blur-linear"><path d="M5,17.5c0.8,0,1.5-0.7,1.5-1.5S5.8,14.5,5,14.5S3.5,15.2,3.5,16S4.2,17.5,5,17.5z M9,13c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S8.4,13,9,13z M9,9c0.6,0,1-0.4,1-1S9.6,7,9,7S8,7.4,8,8S8.4,9,9,9z M3,21h18v-2H3V21z M5,9.5c0.8,0,1.5-0.7,1.5-1.5S5.8,6.5,5,6.5S3.5,7.2,3.5,8S4.2,9.5,5,9.5z M5,13.5c0.8,0,1.5-0.7,1.5-1.5S5.8,10.5,5,10.5S3.5,11.2,3.5,12S4.2,13.5,5,13.5z M9,17c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S8.4,17,9,17z M17,16.5c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5s-0.5,0.2-0.5,0.5S16.7,16.5,17,16.5z M3,3v2h18V3H3z M17,8.5c0.3,0,0.5-0.2,0.5-0.5c0-0.3-0.2-0.5-0.5-0.5S16.5,7.7,16.5,8C16.5,8.3,16.7,8.5,17,8.5z M17,12.5c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5s-0.5,0.2-0.5,0.5S16.7,12.5,17,12.5z M13,9c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S12.4,9,13,9z M13,13c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S12.4,13,13,13z M13,17c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S12.4,17,13,17z"/></g>
|
||
<g id="blur-off"><path d="M14,7c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S13.4,7,14,7z M13.8,11.5c0.1,0,0.1,0,0.2,0c0.8,0,1.5-0.7,1.5-1.5S14.8,8.5,14,8.5s-1.5,0.7-1.5,1.5c0,0.1,0,0.1,0,0.2C12.6,10.9,13.1,11.4,13.8,11.5z M14,3.5c0.3,0,0.5-0.2,0.5-0.5S14.3,2.5,14,2.5S13.5,2.7,13.5,3S13.7,3.5,14,3.5z M10,3.5c0.3,0,0.5-0.2,0.5-0.5S10.3,2.5,10,2.5S9.5,2.7,9.5,3S9.7,3.5,10,3.5z M21,10.5c0.3,0,0.5-0.2,0.5-0.5S21.3,9.5,21,9.5s-0.5,0.2-0.5,0.5S20.7,10.5,21,10.5z M10,7c0.6,0,1-0.4,1-1s-0.4-1-1-1S9,5.4,9,6S9.4,7,10,7z M18,15c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S17.4,15,18,15z M18,11c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S17.4,11,18,11z M18,7c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S17.4,7,18,7z M14,20.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S14.3,20.5,14,20.5z M2.5,5.3l3.8,3.8C6.2,9,6.1,9,6,9c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1c0-0.1,0-0.2-0.1-0.3l2.8,2.8C9,12.6,8.5,13.3,8.5,14c0,0.8,0.7,1.5,1.5,1.5c0.7,0,1.4-0.5,1.5-1.3l2.8,2.8C14.2,17,14.1,17,14,17c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1c0-0.1,0-0.2-0.1-0.3l3.8,3.8l1.3-1.3L3.8,4L2.5,5.3z M10,17c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S10.6,17,10,17z M21,13.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S21.3,13.5,21,13.5z M6,13c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S6.6,13,6,13z M3,9.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S3.3,9.5,3,9.5z M10,20.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S10.3,20.5,10,20.5z M6,17c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S6.6,17,6,17z M3,13.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S3.3,13.5,3,13.5z"/></g>
|
||
<g id="blur-on"><path d="M6,13c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S6.6,13,6,13z M6,17c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S6.6,17,6,17z M6,9c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S6.6,9,6,9z M3,9.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S3.3,9.5,3,9.5z M6,5C5.4,5,5,5.4,5,6s0.4,1,1,1s1-0.4,1-1S6.6,5,6,5z M21,10.5c0.3,0,0.5-0.2,0.5-0.5S21.3,9.5,21,9.5s-0.5,0.2-0.5,0.5S20.7,10.5,21,10.5z M14,7c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S13.4,7,14,7z M14,3.5c0.3,0,0.5-0.2,0.5-0.5S14.3,2.5,14,2.5S13.5,2.7,13.5,3S13.7,3.5,14,3.5z M3,13.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S3.3,13.5,3,13.5z M10,20.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S10.3,20.5,10,20.5z M10,3.5c0.3,0,0.5-0.2,0.5-0.5S10.3,2.5,10,2.5S9.5,2.7,9.5,3S9.7,3.5,10,3.5z M10,7c0.6,0,1-0.4,1-1s-0.4-1-1-1S9,5.4,9,6S9.4,7,10,7z M10,12.5c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S10.8,12.5,10,12.5z M18,13c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S18.6,13,18,13z M18,17c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S18.6,17,18,17z M18,9c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S18.6,9,18,9z M18,5c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S18.6,5,18,5z M21,13.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S21.3,13.5,21,13.5z M14,17c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S14.6,17,14,17z M14,20.5c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5S14.3,20.5,14,20.5z M10,8.5c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S10.8,8.5,10,8.5z M10,17c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S10.6,17,10,17z M14,12.5c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S14.8,12.5,14,12.5z M14,8.5c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S14.8,8.5,14,8.5z"/></g>
|
||
<g id="brightness-1"><circle cx="12" cy="12" r="10"/></g>
|
||
<g id="brightness-2"><path d="M10,2C8.2,2,6.5,2.5,5,3.3c3,1.7,5,5,5,8.7s-2,6.9-5,8.7c1.5,0.9,3.2,1.3,5,1.3c5.5,0,10-4.5,10-10S15.5,2,10,2z"/></g>
|
||
<g id="brightness-3"><path d="M9,2C8,2,6.9,2.2,6,2.5c4.1,1.3,7,5.1,7,9.5s-2.9,8.3-7,9.5C6.9,21.8,8,22,9,22c5.5,0,10-4.5,10-10S14.5,2,9,2z"/></g>
|
||
<g id="brightness-4"><path d="M20,8.7V4h-4.7L12,0.7L8.7,4H4v4.7L0.7,12L4,15.3V20h4.7l3.3,3.3l3.3-3.3H20v-4.7l3.3-3.3L20,8.7z M12,18c-0.9,0-1.7-0.2-2.5-0.6c2.1-0.9,3.5-3,3.5-5.4s-1.4-4.5-3.5-5.4C10.3,6.2,11.1,6,12,6c3.3,0,6,2.7,6,6S15.3,18,12,18z"/></g>
|
||
<g id="brightness-5"><path d="M20,15.3l3.3-3.3L20,8.7V4h-4.7L12,0.7L8.7,4H4v4.7L0.7,12L4,15.3V20h4.7l3.3,3.3l3.3-3.3H20V15.3z M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6c3.3,0,6,2.7,6,6S15.3,18,12,18z"/></g>
|
||
<g id="brightness-6"><path d="M20,15.3l3.3-3.3L20,8.7V4h-4.7L12,0.7L8.7,4H4v4.7L0.7,12L4,15.3V20h4.7l3.3,3.3l3.3-3.3H20V15.3z M12,18V6c3.3,0,6,2.7,6,6S15.3,18,12,18z"/></g>
|
||
<g id="brightness-7"><path d="M20,8.7V4h-4.7L12,0.7L8.7,4H4v4.7L0.7,12L4,15.3V20h4.7l3.3,3.3l3.3-3.3H20v-4.7l3.3-3.3L20,8.7z M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6c3.3,0,6,2.7,6,6S15.3,18,12,18z M12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4s4-1.8,4-4C16,9.8,14.2,8,12,8z"/></g>
|
||
<g id="brush"><path d="M7,14c-1.7,0-3,1.3-3,3c0,1.3-1.2,2-2,2c0.9,1.2,2.5,2,4,2c2.2,0,4-1.8,4-4C10,15.3,8.7,14,7,14z M20.7,4.6l-1.3-1.3c-0.4-0.4-1-0.4-1.4,0l-9,9l2.8,2.8l9-9C21.1,5.7,21.1,5,20.7,4.6z"/></g>
|
||
<g id="camera"><path d="M9.4,10.5l4.8-8.3C13.5,2.1,12.7,2,12,2C9.6,2,7.4,2.8,5.7,4.3l3.7,6.3L9.4,10.5z M21.5,9c-0.9-2.9-3.1-5.3-6-6.3L11.9,9H21.5z M21.8,10h-7.5l0.3,0.5l4.8,8.3C21,17,22,14.6,22,12C22,11.3,21.9,10.6,21.8,10z M8.5,12L4.6,5.2C3,7,2,9.4,2,12c0,0.7,0.1,1.4,0.2,2h7.5L8.5,12z M2.5,15c0.9,2.9,3.1,5.3,6,6.3l3.7-6.3H2.5z M13.7,15l-3.9,6.8c0.7,0.2,1.4,0.2,2.2,0.2c2.4,0,4.6-0.8,6.3-2.3l-3.7-6.3L13.7,15z"/></g>
|
||
<g id="camera-alt"><circle cx="12" cy="12" r="3.2"/><path d="M9,2L7.2,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6c0-1.1-0.9-2-2-2h-3.2L15,2H9z M12,17c-2.8,0-5-2.2-5-5s2.2-5,5-5s5,2.2,5,5S14.8,17,12,17z"/></g>
|
||
<g id="camera-front"><path d="M12,12c1.7,0,3-1.3,3-3s-1.3-3-3-3c-1.7,0-3,1.3-3,3S10.3,12,12,12z M18,0H6C4.9,0,4,0.9,4,2v20c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V2C20,0.9,19.1,0,18,0z M11,1h2v2h-2V1z M13,22v-2H9v-2h4v-2l3,3L13,22z M18,17c0-2-4-3-6-3c-2,0-6,1-6,3V4h12V17z"/></g>
|
||
<g id="camera-rear"><path d="M18,0H6C4.9,0,4,0.9,4,2v20c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V2C20,0.9,19.1,0,18,0z M12,2c1.1,0,2,0.9,2,2s-0.9,2-2,2s-2-0.9-2-2S10.9,2,12,2z M13,22v-2H9v-2h4v-2l3,3L13,22z"/></g>
|
||
<g id="camera-roll"><path d="M14,5c0-1.1-0.9-2-2-2h-1V2c0-0.6-0.4-1-1-1H6C5.4,1,5,1.4,5,2v1H4C2.9,3,2,3.9,2,5v15c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2h8V5H14z M12,18h-2v-2h2V18z M12,9h-2V7h2V9z M16,18h-2v-2h2V18z M16,9h-2V7h2V9z M20,18h-2v-2h2V18z M20,9h-2V7h2V9z"/></g>
|
||
<g id="center-focus-strong"><path d="M12,8c-2.2,0-4,1.8-4,4s1.8,4,4,4s4-1.8,4-4S14.2,8,12,8z M5,15H3v4c0,1.1,0.9,2,2,2h4v-2H5V15z M5,5h4V3H5C3.9,3,3,3.9,3,5v4h2V5z M19,3h-4v2h4v4h2V5C21,3.9,20.1,3,19,3z M19,19h-4v2h4c1.1,0,2-0.9,2-2v-4h-2V19z"/></g>
|
||
<g id="center-focus-weak"><path d="M5,15H3v4c0,1.1,0.9,2,2,2h4v-2H5V15z M5,5h4V3H5C3.9,3,3,3.9,3,5v4h2V5z M19,3h-4v2h4v4h2V5C21,3.9,20.1,3,19,3z M19,19h-4v2h4c1.1,0,2-0.9,2-2v-4h-2V19z M12,8c-2.2,0-4,1.8-4,4s1.8,4,4,4s4-1.8,4-4S14.2,8,12,8z M12,14c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S13.1,14,12,14z"/></g>
|
||
<g id="collections"><path d="M22,16V4c0-1.1-0.9-2-2-2H8C6.9,2,6,2.9,6,4v12c0,1.1,0.9,2,2,2h12C21.1,18,22,17.1,22,16z M11,12l2,2.7l3-3.7l4,5H8L11,12z M2,6v14c0,1.1,0.9,2,2,2h14v-2H4V6H2z"/></g>
|
||
<g id="colorize"><path d="M20.7,5.6l-2.3-2.3c-0.4-0.4-1-0.4-1.4,0l-3.1,3.1l-1.9-1.9l-1.4,1.4l1.4,1.4L3,16.3V21h4.8l8.9-8.9l1.4,1.4l1.4-1.4l-1.9-1.9L20.7,7C21.1,6.7,21.1,6,20.7,5.6z M6.9,19L5,17.1L13.1,9l1.9,1.9L6.9,19z"/></g>
|
||
<g id="color-lens"><path d="M12,3c-5,0-9,4-9,9s4,9,9,9c0.8,0,1.5-0.7,1.5-1.5c0-0.4-0.1-0.7-0.4-1c-0.2-0.3-0.4-0.6-0.4-1c0-0.8,0.7-1.5,1.5-1.5H16c2.8,0,5-2.2,5-5C21,6.6,17,3,12,3z M6.5,12C5.7,12,5,11.3,5,10.5S5.7,9,6.5,9C7.3,9,8,9.7,8,10.5S7.3,12,6.5,12z M9.5,8C8.7,8,8,7.3,8,6.5S8.7,5,9.5,5C10.3,5,11,5.7,11,6.5S10.3,8,9.5,8z M14.5,8C13.7,8,13,7.3,13,6.5S13.7,5,14.5,5C15.3,5,16,5.7,16,6.5S15.3,8,14.5,8z M17.5,12c-0.8,0-1.5-0.7-1.5-1.5S16.7,9,17.5,9c0.8,0,1.5,0.7,1.5,1.5S18.3,12,17.5,12z"/></g>
|
||
<g id="compare"><path d="M10,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h5v2h2V1h-2V3z M10,18H5l5-6V18z M19,3h-5v2h5v13l-5-6v9h5c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z"/></g>
|
||
<g id="control-point"><path d="M13,7h-2v4H7v2h4v4h2v-4h4v-2h-4V7z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="control-point-duplicate"><polygon points="16,8 14,8 14,11 11,11 11,13 14,13 14,16 16,16 16,13 19,13 19,11 16,11 "/></g>
|
||
<g id="crop-16-9"><path d="M19,6H5C3.9,6,3,6.9,3,8v8c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V8C21,6.9,20.1,6,19,6z M19,16H5V8h14V16z"/></g>
|
||
<g id="crop"><path d="M17,15h2V7c0-1.1-0.9-2-2-2H9v2h8V15z M7,17V1H5v4H1v2h4v10c0,1.1,0.9,2,2,2h10v4h2v-4h4v-2H7z"/></g>
|
||
<g id="crop-3-2"><path d="M19,4H5C3.9,4,3,4.9,3,6v12c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V6C21,4.9,20.1,4,19,4z M19,18H5V6h14V18z"/></g>
|
||
<g id="crop-5-4"><path d="M19,5H5C3.9,5,3,5.9,3,7v10c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V7C21,5.9,20.1,5,19,5z M19,17H5V7h14V17z"/></g>
|
||
<g id="crop-7-5"><path d="M19,7H5C3.9,7,3,7.9,3,9v6c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V9C21,7.9,20.1,7,19,7z M19,15H5V9h14V15z"/></g>
|
||
<g id="crop-din"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19H5V5h14V19z"/></g>
|
||
<g id="crop-free"><path d="M3,5v4h2V5h4V3H5C3.9,3,3,3.9,3,5z M5,15H3v4c0,1.1,0.9,2,2,2h4v-2H5V15z M19,19h-4v2h4c1.1,0,2-0.9,2-2v-4h-2V19z M19,3h-4v2h4v4h2V5C21,3.9,20.1,3,19,3z"/></g>
|
||
<g id="crop-landscape"><path d="M19,5H5C3.9,5,3,5.9,3,7v10c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V7C21,5.9,20.1,5,19,5z M19,17H5V7h14V17z"/></g>
|
||
<g id="crop-original"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19H5V5h14V19z M14,12.3l-2.8,3.5l-2-2.4L6.5,17h11L14,12.3z"/></g>
|
||
<g id="crop-portrait"><path d="M17,3H7C5.9,3,5,3.9,5,5v14c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V5C19,3.9,18.1,3,17,3z M17,19H7V5h10V19z"/></g>
|
||
<g id="crop-square"><path d="M18,4H6C4.9,4,4,4.9,4,6v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V6C20,4.9,19.1,4,18,4z M18,18H6V6h12V18z"/></g>
|
||
<g id="dehaze"><path d="M2,15.5v2c6.7-4.4,13.3,4.4,20,0v-2C15.3,19.9,8.7,11.1,2,15.5z M2,10.5v2c6.7-4.4,13.3,4.4,20,0v-2C15.3,14.9,8.7,6.1,2,10.5z M2,5.5v2c6.7-4.4,13.3,4.4,20,0v-2C15.3,9.9,8.7,1.1,2,5.5z"/></g>
|
||
<g id="details"><path d="M3,4l9,16l9-16H3z M6.4,6h11.2L12,16L6.4,6z"/></g>
|
||
<g id="edit"><path d="M3,17.3V21h3.8L17.8,9.9l-3.8-3.8L3,17.3z M20.7,7c0.4-0.4,0.4-1,0-1.4l-2.3-2.3c-0.4-0.4-1-0.4-1.4,0l-1.8,1.8l3.7,3.8L20.7,7z"/></g>
|
||
<g id="exposure"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M5.5,7.5h2v-2H9v2h2V9H9v2H7.5V9h-2V7.5z M19,19L5,19L19,5V19z M17,17v-1.5h-5V17H17z"/></g>
|
||
<g id="exposure-minus-1"><path d="M4,11v2h8v-2H4z M19,18h-2V7.4l-3,1V6.7L18.7,5H19V18z"/></g>
|
||
<g id="exposure-minus-2"><path d="M15,16.3l2.9-3.1c0.4-0.4,0.7-0.8,1-1.2c0.3-0.4,0.6-0.8,0.8-1.2c0.2-0.4,0.4-0.8,0.5-1.2c0.1-0.4,0.2-0.8,0.2-1.2c0-0.5-0.1-1-0.3-1.5S19.8,6.3,19.4,6c-0.3-0.3-0.8-0.5-1.3-0.7C17.7,5.1,17.1,5,16.5,5c-0.7,0-1.3,0.1-1.8,0.3c-0.5,0.2-1,0.5-1.4,0.9c-0.4,0.4-0.7,0.8-0.8,1.3c-0.2,0.5-0.3,1-0.3,1.5h2.1c0-0.3,0-0.6,0.1-0.9c0.1-0.3,0.2-0.5,0.4-0.7C15,7.2,15.2,7,15.5,6.9c0.3-0.1,0.6-0.2,1-0.2c0.3,0,0.6,0.1,0.8,0.2c0.2,0.1,0.4,0.2,0.6,0.4c0.2,0.2,0.3,0.4,0.4,0.6c0.1,0.2,0.1,0.5,0.1,0.8c0,0.2,0,0.4-0.1,0.7c-0.1,0.2-0.2,0.5-0.3,0.7c-0.1,0.2-0.3,0.5-0.6,0.8c-0.2,0.3-0.5,0.6-0.9,1l-4.2,4.6V18H21v-1.7H15z M2,11v2h8v-2H2z"/></g>
|
||
<g id="exposure-plus-1"><path d="M10,7H8v4H4v2h4v4h2v-4h4v-2h-4V7z M20,18h-2V7.4l-3,1V6.7L19.7,5H20V18z"/></g>
|
||
<g id="exposure-plus-2"><path d="M16,16.3l2.9-3.1c0.4-0.4,0.7-0.8,1-1.2c0.3-0.4,0.6-0.8,0.8-1.2c0.2-0.4,0.4-0.8,0.5-1.2c0.1-0.4,0.2-0.8,0.2-1.2c0-0.5-0.1-1-0.3-1.5S20.8,6.3,20.4,6c-0.3-0.3-0.8-0.5-1.3-0.7C18.7,5.1,18.1,5,17.5,5c-0.7,0-1.3,0.1-1.8,0.3c-0.5,0.2-1,0.5-1.4,0.9c-0.4,0.4-0.7,0.8-0.8,1.3c-0.2,0.5-0.3,1-0.3,1.5h2.1c0-0.3,0-0.6,0.1-0.9c0.1-0.3,0.2-0.5,0.4-0.7C16,7.2,16.2,7,16.5,6.9c0.3-0.1,0.6-0.2,1-0.2c0.3,0,0.6,0.1,0.8,0.2c0.2,0.1,0.4,0.2,0.6,0.4c0.2,0.2,0.3,0.4,0.4,0.6c0.1,0.2,0.1,0.5,0.1,0.8c0,0.2,0,0.4-0.1,0.7c-0.1,0.2-0.2,0.5-0.3,0.7c-0.1,0.2-0.3,0.5-0.6,0.8c-0.2,0.3-0.5,0.6-0.9,1l-4.2,4.6V18H22v-1.7H16z M8,7H6v4H2v2h4v4h2v-4h4v-2H8V7z"/></g>
|
||
<g id="exposure-zero"><path d="M16.1,12.5c0,1-0.1,1.9-0.3,2.6c-0.2,0.7-0.5,1.3-0.8,1.7c-0.4,0.4-0.8,0.8-1.3,1S12.6,18,12,18c-0.6,0-1.2-0.1-1.7-0.3s-0.9-0.5-1.3-1c-0.4-0.4-0.6-1-0.8-1.7c-0.2-0.7-0.3-1.5-0.3-2.6v-2c0-1,0.1-1.9,0.3-2.5C8.4,7.2,8.6,6.7,9,6.2c0.4-0.4,0.8-0.7,1.3-0.9C10.8,5.1,11.4,5,12,5c0.6,0,1.2,0.1,1.7,0.3c0.5,0.2,0.9,0.5,1.3,0.9c0.4,0.4,0.6,1,0.8,1.7c0.2,0.7,0.3,1.5,0.3,2.5V12.5z M14,10.1c0-0.6,0-1.2-0.1-1.6c-0.1-0.4-0.2-0.8-0.4-1.1S13.1,7,12.9,6.9c-0.3-0.1-0.5-0.2-0.9-0.2c-0.3,0-0.6,0.1-0.9,0.2c-0.3,0.1-0.5,0.3-0.6,0.6s-0.3,0.6-0.4,1.1C10,9,10,9.5,10,10.1v2.7c0,0.6,0,1.2,0.1,1.6s0.2,0.8,0.4,1.1s0.4,0.5,0.6,0.6s0.5,0.2,0.9,0.2c0.3,0,0.6-0.1,0.9-0.2c0.2-0.1,0.5-0.3,0.6-0.6c0.2-0.3,0.3-0.6,0.4-1.1c0.1-0.4,0.1-1,0.1-1.6V10.1z"/></g>
|
||
<g id="filter-1"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M14,15h2V5h-4v2h2V15z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z"/></g>
|
||
<g id="filter-2"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z M17,13h-4v-2h2c1.1,0,2-0.9,2-2V7c0-1.1-0.9-2-2-2h-4v2h4v2h-2c-1.1,0-2,0.9-2,2v4h6V13z"/></g>
|
||
<g id="filter"><path d="M16,10.3l-2.8,3.5l-2-2.4L8.5,15h11L16,10.3z M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z"/></g>
|
||
<g id="filter-3"><path d="M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M17,13v-1.5c0-0.8-0.7-1.5-1.5-1.5c0.8,0,1.5-0.7,1.5-1.5V7c0-1.1-0.9-2-2-2h-4v2h4v2h-2v2h2v2h-4v2h4C16.1,15,17,14.1,17,13z"/></g>
|
||
<g id="filter-4"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M15,15h2V5h-2v4h-2V5h-2v6h4V15z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z"/></g>
|
||
<g id="filter-5"><path d="M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M17,13v-2c0-1.1-0.9-2-2-2h-2V7h4V5h-6v6h4v2h-4v2h4C16.1,15,17,14.1,17,13z"/></g>
|
||
<g id="filter-6"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z M13,15h2c1.1,0,2-0.9,2-2v-2c0-1.1-0.9-2-2-2h-2V7h4V5h-4c-1.1,0-2,0.9-2,2v6C11,14.1,11.9,15,13,15z M13,11h2v2h-2V11z"/></g>
|
||
<g id="filter-7"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z M13,15l4-8V5h-6v2h4l-4,8H13z"/></g>
|
||
<g id="filter-8"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z M13,15h2c1.1,0,2-0.9,2-2v-1.5c0-0.8-0.7-1.5-1.5-1.5c0.8,0,1.5-0.7,1.5-1.5V7c0-1.1-0.9-2-2-2h-2c-1.1,0-2,0.9-2,2v1.5c0,0.8,0.7,1.5,1.5,1.5c-0.8,0-1.5,0.7-1.5,1.5V13C11,14.1,11.9,15,13,15z M13,7h2v2h-2V7z M13,11h2v2h-2V11z"/></g>
|
||
<g id="filter-9"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z"/><path d="M15,5h-2c-1.1,0-2,0.9-2,2v2c0,1.1,0.9,2,2,2h2v2h-4v2h4c1.1,0,2-0.9,2-2V7C17,5.9,16.1,5,15,5z M15,9h-2V7h2V9z"/></g>
|
||
<g id="filter-9-plus"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M14,12V8c0-1.1-0.9-2-2-2h-1C9.9,6,9,6.9,9,8v1c0,1.1,0.9,2,2,2h1v1H9v2h3C13.1,14,14,13.1,14,12z M11,9V8h1v1H11z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,9h-2V7h-2v2h-2v2h2v2h2v-2h2v6H7V3h14V9z"/></g>
|
||
<g id="filter-b-and-w"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19l-7-8v8H5l7-8V5h7V19z"/></g>
|
||
<g id="filter-center-focus"><path d="M5,15H3v4c0,1.1,0.9,2,2,2h4v-2H5V15z M5,5h4V3H5C3.9,3,3,3.9,3,5v4h2V5z M19,3h-4v2h4v4h2V5C21,3.9,20.1,3,19,3z M19,19h-4v2h4c1.1,0,2-0.9,2-2v-4h-2V19z M12,9c-1.7,0-3,1.3-3,3s1.3,3,3,3s3-1.3,3-3S13.7,9,12,9z"/></g>
|
||
<g id="filter-drama"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z M19,18H6c-2.2,0-4-1.8-4-4s1.8-4,4-4c2.2,0,4,1.8,4,4h2c0-2.8-1.9-5.1-4.4-5.8C8.6,6.9,10.2,6,12,6c3,0,5.5,2.5,5.5,5.5V12H19c1.7,0,3,1.3,3,3S20.7,18,19,18z"/></g>
|
||
<g id="filter-frames"><path d="M20,4h-4l-4-4L8,4H4C2.9,4,2,4.9,2,6v14c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,20H4V6h4.5L12,2.5L15.5,6H20V20z M18,8H6v10h12"/></g>
|
||
<g id="filter-hdr"><path d="M14,6l-3.8,5l2.8,3.8L11.5,16C9.8,13.7,7,10,7,10l-6,8h22L14,6z"/></g>
|
||
<g id="filter-none"><path d="M3,5H1v16c0,1.1,0.9,2,2,2h16v-2H3V5z M21,1H7C5.9,1,5,1.9,5,3v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V3C23,1.9,22.1,1,21,1z M21,17H7V3h14V17z"/></g>
|
||
<g id="filter-retrolux"><path d="M13,16.4L19,7l-7-7L5,7l6,9.4v0.1C10.4,16.2,9.7,16,9,16c-2.2,0-4,1.8-4,4s1.8,4,4,4c1.8,0,3.4-1.3,3.9-3l3,3l1.4-1.4L13,18.3V16.4z M11,20c0,1.1-0.9,2-2,2s-2-0.9-2-2s0.9-2,2-2c0.5,0,1,0.2,1.4,0.6l0.6,0.6V20z"/></g>
|
||
<g id="filter-tilt-shift"><path d="M11,4.1v-2C9,2.3,7.2,3,5.7,4.3l1.4,1.4C8.2,4.8,9.5,4.3,11,4.1z M18.3,4.3C16.8,3,15,2.3,13,2.1v2c1.5,0.2,2.8,0.8,3.9,1.6L18.3,4.3z M19.9,11h2c-0.2-2-1-3.8-2.2-5.3l-1.4,1.4C19.2,8.2,19.7,9.5,19.9,11z M5.7,7.1L4.3,5.7C3,7.2,2.3,9,2.1,11h2C4.3,9.5,4.8,8.2,5.7,7.1z M4.1,13h-2c0.2,2,1,3.8,2.2,5.3l1.4-1.4C4.8,15.8,4.3,14.5,4.1,13z M15,12c0-1.7-1.3-3-3-3s-3,1.3-3,3s1.3,3,3,3S15,13.7,15,12z M18.3,16.9l1.4,1.4c1.2-1.5,2-3.3,2.2-5.3h-2C19.7,14.5,19.2,15.8,18.3,16.9z M13,19.9v2c2-0.2,3.8-1,5.3-2.2l-1.4-1.4C15.8,19.2,14.5,19.7,13,19.9z M5.7,19.7c1.5,1.2,3.3,2,5.3,2.2v-2c-1.5-0.2-2.8-0.8-3.9-1.6L5.7,19.7z"/></g>
|
||
<g id="filter-vintage"><path d="M18.7,12.4c-0.3-0.2-0.6-0.3-0.9-0.4c0.3-0.1,0.6-0.2,0.9-0.4c1.9-1.1,3-3.1,3-5.2c-1.8-1-4.1-1.1-6,0c-0.3,0.2-0.5,0.3-0.8,0.5C15,6.6,15,6.3,15,6c0-2.2-1.2-4.2-3-5.2c-1.8,1-3,3-3,5.2c0,0.3,0,0.6,0.1,0.9C8.8,6.7,8.6,6.6,8.3,6.4c-1.9-1.1-4.2-1-6,0c0,2.1,1.1,4.1,3,5.2c0.3,0.2,0.6,0.3,0.9,0.4c-0.3,0.1-0.6,0.2-0.9,0.4c-1.9,1.1-3,3.1-3,5.2c1.8,1,4.1,1.1,6,0c0.3-0.2,0.5-0.3,0.8-0.5C9,17.4,9,17.7,9,18c0,2.2,1.2,4.2,3,5.2c1.8-1,3-3,3-5.2c0-0.3,0-0.6-0.1-0.9c0.2,0.2,0.5,0.4,0.8,0.5c1.9,1.1,4.2,1,6,0C21.7,15.5,20.6,13.5,18.7,12.4z M12,16c-2.2,0-4-1.8-4-4s1.8-4,4-4c2.2,0,4,1.8,4,4S14.2,16,12,16z"/></g>
|
||
<g id="flare"><path d="M7,11H1v2h6V11z M9.2,7.8L7.1,5.6L5.6,7.1l2.1,2.1L9.2,7.8z M13,1h-2v6h2V1z M18.4,7.1l-1.4-1.4l-2.1,2.1l1.4,1.4L18.4,7.1z M17,11v2h6v-2H17z M12,9c-1.7,0-3,1.3-3,3s1.3,3,3,3s3-1.3,3-3S13.7,9,12,9z M14.8,16.2l2.1,2.1l1.4-1.4l-2.1-2.1L14.8,16.2z M5.6,16.9l1.4,1.4l2.1-2.1l-1.4-1.4L5.6,16.9z M11,23h2v-6h-2V23z"/></g>
|
||
<g id="flash-auto"><path d="M3,2v12h3v9l7-12H9l4-9H3z M19,2h-2l-3.2,9h1.9l0.7-2h3.2l0.7,2h1.9L19,2z M16.9,7.6L18,4l1.1,3.6H16.9z"/></g>
|
||
<g id="flash-off"><path d="M3.3,3L2,4.3l5,5V13h3v9l3.6-6.1l4.1,4.1l1.3-1.3L3.3,3z M17,10h-4l4-8H7v2.2l8.5,8.5L17,10z"/></g>
|
||
<g id="flash-on"><polygon points="7,2 7,13 10,13 10,22 17,10 13,10 17,2 "/></g>
|
||
<g id="flip"><path d="M15,21h2v-2h-2V21z M19,9h2V7h-2V9z M3,5v14c0,1.1,0.9,2,2,2h4v-2H5V5h4V3H5C3.9,3,3,3.9,3,5z M19,3v2h2C21,3.9,20.1,3,19,3z M11,23h2V1h-2V23z M19,17h2v-2h-2V17z M15,5h2V3h-2V5z M19,13h2v-2h-2V13z M19,21c1.1,0,2-0.9,2-2h-2V21z"/></g>
|
||
<g id="gradient"><rect x="11" y="9" width="2" height="2"/><rect x="9" y="11" width="2" height="2"/><rect x="13" y="11" width="2" height="2"/><rect x="15" y="9" width="2" height="2"/><rect x="7" y="9" width="2" height="2"/><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M9,18H7v-2h2V18z M13,18h-2v-2h2V18z M17,18h-2v-2h2V18z M19,11h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2H9v-2H7v2H5v-2h2v-2H5V5h14V11z"/></g>
|
||
<g id="grain"><path d="M10,12c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C12,12.9,11.1,12,10,12z M6,8c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C8,8.9,7.1,8,6,8z M6,16c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C8,16.9,7.1,16,6,16z M18,8c1.1,0,2-0.9,2-2c0-1.1-0.9-2-2-2s-2,0.9-2,2C16,7.1,16.9,8,18,8z M14,16c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C16,16.9,15.1,16,14,16z M18,12c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C20,12.9,19.1,12,18,12z M14,8c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C16,8.9,15.1,8,14,8z M10,4C8.9,4,8,4.9,8,6c0,1.1,0.9,2,2,2s2-0.9,2-2C12,4.9,11.1,4,10,4z"/></g>
|
||
<g id="grid-off"><path d="M8,4v1.5l2,2V4h4v4h-3.5l2,2H14v1.5l2,2V10h4v4h-3.5l2,2H20v1.5l2,2V4c0-1.1-0.9-2-2-2H4.5l2,2H8z M16,4h4v4h-4V4z M21.4,21.4L21.4,21.4L20,20L4,4L2.6,2.6L1.3,1.3L0,2.5l2,2V20c0,1.1,0.9,2,2,2h15.5l2,2l1.3-1.3L21.4,21.4z M10,12.5l1.5,1.5H10V12.5z M4,6.5L5.5,8H4V6.5z M8,20l-4,0v-4h4V20z M8,14H4v-4h3.5L8,10.5V14z M14,20l-4,0v-4h3.5l0.5,0.5V20z M16,20v-1.5l1.5,1.5L16,20z"/></g>
|
||
<g id="grid-on"><path d="M20,2H4C2.9,2,2,2.9,2,4v16c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M8,20l-4,0v-4h4V20z M8,14H4v-4h4V14z M8,8H4V4h4V8z M14,20l-4,0v-4h4V20z M14,14h-4v-4h4V14z M14,8h-4V4h4V8z M20,20l-4,0v-4h4V20z M20,14h-4v-4h4V14z M20,8h-4V4h4V8z"/></g>
|
||
<g id="hdr-off"><path d="M20.7,11.8c0.2-0.2,0.3-0.6,0.3-1c0-0.2,0-0.4-0.1-0.6c0-0.2-0.1-0.3-0.2-0.4s-0.2-0.2-0.3-0.3c-0.1-0.1-0.3-0.1-0.5-0.1h-1.1v2.7h1.1C20.3,12.2,20.5,12.1,20.7,11.8z"/><path d="M11.6,15.5c0.3,0,0.8,0,1-0.1c0.2-0.1,0.4-0.2,0.5-0.4c0,0,0,0,0,0l-2.3-2.3v2.9H11.6z"/><path d="M15.3,11.8c0-0.6-0.1-1.1-0.3-1.6c-0.2-0.5-0.4-0.9-0.7-1.2c-0.3-0.3-0.7-0.6-1.1-0.7S12.4,8,11.8,8h-0.5l4,4V11.8z M2.5,4.3L6.2,8h-1v3.6H2.8V8H1v9h1.8v-3.9h2.4V17H7V8.8l2,2V17h2.6c0.5,0,1.2-0.1,1.6-0.3c0.4-0.2,0.7-0.4,1-0.7l4.9,4.9l1.3-1.3L3.8,3L2.5,4.3z M10.8,12.6l2.3,2.3c0,0,0,0,0,0c-0.1,0.2-0.3,0.3-0.5,0.4c-0.2,0.1-0.7,0.1-1,0.1h-0.8V12.6z M21.5,13.2c0.2-0.1,0.4-0.2,0.5-0.4c0.2-0.2,0.3-0.3,0.4-0.5c0.1-0.2,0.2-0.4,0.3-0.7c0.1-0.3,0.1-0.6,0.1-0.9c0-0.4-0.1-0.8-0.2-1.2c-0.1-0.3-0.3-0.6-0.6-0.8s-0.5-0.4-0.9-0.5C20.7,8.1,20.3,8,19.9,8H17v5.7l1.8,1.8v-1.8h0.9l1.4,3.3H23v-0.1L21.5,13.2z M20.7,11.8c-0.2,0.2-0.5,0.4-0.8,0.4h-1.1V9.5H20c0.2,0,0.3,0,0.5,0.1c0.1,0.1,0.2,0.2,0.3,0.3s0.1,0.3,0.2,0.4c0,0.2,0.1,0.4,0.1,0.6C21,11.3,20.9,11.6,20.7,11.8z"/></g>
|
||
<g id="hdr-on"><path d="M5.2,11.6H2.8V8H1v9h1.8v-3.9h2.4V17H7V8H5.2V11.6z M14.3,9c-0.3-0.3-0.7-0.6-1.1-0.7S12.4,8,11.8,8H9v9h2.6c0.5,0,1.2-0.1,1.6-0.3c0.4-0.2,0.8-0.4,1.1-0.7c0.3-0.3,0.5-0.7,0.7-1.2c0.2-0.5,0.2-1,0.2-1.6v-1.4c0-0.6-0.1-1.1-0.3-1.6C14.9,9.7,14.6,9.3,14.3,9z M13.5,13.2c0,0.4,0,0.8-0.1,1c-0.1,0.3-0.1,0.5-0.3,0.7s-0.3,0.3-0.5,0.4c-0.2,0.1-0.7,0.1-1,0.1h-0.8v-6h1c0.3,0,0.6,0,0.8,0.1c0.2,0.1,0.4,0.2,0.5,0.4c0.1,0.2,0.2,0.4,0.3,0.7c0.1,0.3,0.1,0.6,0.1,1.1V13.2z M21.5,13.2c0.2-0.1,0.4-0.2,0.5-0.4c0.2-0.2,0.3-0.3,0.4-0.5c0.1-0.2,0.2-0.4,0.3-0.7c0.1-0.3,0.1-0.6,0.1-0.9c0-0.4-0.1-0.8-0.2-1.2c-0.1-0.3-0.3-0.6-0.6-0.8s-0.5-0.4-0.9-0.5C20.7,8.1,20.3,8,19.9,8H17v9h1.8v-3.3h0.9l1.4,3.3H23v-0.1L21.5,13.2z M20.7,11.8c-0.2,0.2-0.5,0.4-0.8,0.4h-1.1V9.5H20c0.2,0,0.3,0,0.5,0.1c0.1,0.1,0.2,0.2,0.3,0.3s0.1,0.3,0.2,0.4c0,0.2,0.1,0.4,0.1,0.6C21,11.3,20.9,11.6,20.7,11.8z"/></g>
|
||
<g id="hdr-plus-off"><path d="M16.5,16h0.1v-0.1l-1.2-2.9c0.2-0.1,0.3-0.2,0.4-0.3c0.1-0.1,0.2-0.3,0.3-0.4c0.1-0.2,0.2-0.3,0.2-0.5c0-0.2,0.1-0.4,0.1-0.7c0-0.3-0.1-0.7-0.2-0.9c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.7-0.4C14.9,9,14.6,9,14.3,9H12v2.5L16.5,16z M13.4,10.2h0.9c0.1,0,0.3,0,0.4,0.1c0.1,0,0.2,0.1,0.3,0.2c0.1,0.1,0.1,0.2,0.1,0.3c0,0.1,0,0.3,0,0.4c0,0.3-0.1,0.6-0.2,0.8c-0.1,0.2-0.4,0.3-0.6,0.3h-0.9V10.2z M12,14l-1-1l-1.4-1.4l-1.4-1.4L2.3,4.3L1,5.5L4.5,9H3.6v2.8H1.4V9H0v7h1.4v-3h2.2v3H5V9.5l1.1,1.1V16h2c0.4,0,0.9-0.1,1.3-0.2c0.3-0.1,0.6-0.3,0.9-0.6c0.1-0.1,0.1-0.2,0.2-0.2l5,5l1.3-1.3l-3.3-3.3L12,14z M9.3,14.4c-0.1,0.1-0.2,0.2-0.4,0.3c-0.2,0.1-0.5,0.1-0.8,0.1H7.5v-2.8l2,2C9.4,14.2,9.4,14.3,9.3,14.4z M21,12.5v-2h-1.5v2h-2V14h2v2H21v-2h2v-1.5H21z"/></g>
|
||
<g id="hdr-plus-on"><path d="M15.9,12.8c0.1-0.1,0.2-0.3,0.3-0.4c0.1-0.2,0.2-0.3,0.2-0.5c0-0.2,0.1-0.4,0.1-0.7c0-0.3-0.1-0.7-0.2-0.9c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.7-0.4C14.9,9,14.6,9,14.3,9H12v7h1.4v-2.6h0.7l1.1,2.6h1.5v-0.1l-1.2-2.9C15.6,13,15.8,12.9,15.9,12.8z M14.9,12c-0.1,0.2-0.4,0.3-0.6,0.3h-0.9v-2.1h0.9c0.1,0,0.3,0,0.4,0.1c0.1,0,0.2,0.1,0.3,0.2c0.1,0.1,0.1,0.2,0.1,0.3c0,0.1,0,0.3,0,0.4C15.1,11.5,15,11.8,14.9,12z M21,12.5v-2h-1.5v2h-2V14h2v2H21v-2h2v-1.5H21z M3.6,11.8H1.4V9H0v7h1.4v-3h2.2v3H5V9H3.6V11.8z M10.3,9.8C10,9.5,9.7,9.3,9.4,9.2S8.7,9,8.3,9H6.1v7h2c0.4,0,0.9-0.1,1.3-0.2c0.3-0.1,0.6-0.3,0.9-0.6c0.2-0.3,0.4-0.6,0.5-0.9c0.1-0.4,0.2-0.8,0.2-1.3V12c0-0.5-0.1-0.9-0.2-1.3S10.5,10,10.3,9.8z M9.6,13c0,0.3,0,0.6-0.1,0.8c0,0.2-0.1,0.4-0.2,0.6c-0.1,0.1-0.2,0.2-0.4,0.3c-0.2,0.1-0.5,0.1-0.8,0.1H7.5v-4.6h0.8c0.2,0,0.4,0,0.6,0.1c0.2,0.1,0.3,0.2,0.4,0.3c0.1,0.1,0.2,0.3,0.2,0.5c0,0.2,0.1,0.5,0.1,0.8V13z"/></g>
|
||
<g id="hdr-strong"><path d="M17,6c-3.3,0-6,2.7-6,6s2.7,6,6,6s6-2.7,6-6S20.3,6,17,6z"/><path d="M5,8c-2.2,0-4,1.8-4,4s1.8,4,4,4s4-1.8,4-4S7.2,8,5,8z M5,14c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S6.1,14,5,14z"/></g>
|
||
<g id="hdr-weak"><path d="M5,8c-2.2,0-4,1.8-4,4s1.8,4,4,4s4-1.8,4-4S7.2,8,5,8z M17,6c-3.3,0-6,2.7-6,6s2.7,6,6,6s6-2.7,6-6S20.3,6,17,6z M17,16c-2.2,0-4-1.8-4-4s1.8-4,4-4c2.2,0,4,1.8,4,4S19.2,16,17,16z"/></g>
|
||
<g id="healing"><path d="M17.7,12l4-4c0.4-0.4,0.4-1,0-1.4l-4.3-4.3c-0.4-0.4-1-0.4-1.4,0l-4,4l-4-4C7.8,2.1,7.5,2,7.3,2S6.8,2.1,6.6,2.3L2.3,6.6C1.9,7,1.9,7.7,2.3,8l4,4l-4,4c-0.4,0.4-0.4,1,0,1.4l4.3,4.3c0.4,0.4,1,0.4,1.4,0l4-4l4,4c0.2,0.2,0.5,0.3,0.7,0.3c0.3,0,0.5-0.1,0.7-0.3l4.3-4.3c0.4-0.4,0.4-1,0-1.4L17.7,12z M12,9c0.6,0,1,0.4,1,1s-0.4,1-1,1c-0.6,0-1-0.4-1-1S11.4,9,12,9z M7.3,11L3.7,7.3l3.6-3.6l3.6,3.6L7.3,11z M10,13c-0.6,0-1-0.4-1-1s0.4-1,1-1c0.6,0,1,0.4,1,1S10.6,13,10,13z M12,15c-0.6,0-1-0.4-1-1s0.4-1,1-1c0.6,0,1,0.4,1,1S12.6,15,12,15z M14,11c0.6,0,1,0.4,1,1s-0.4,1-1,1c-0.6,0-1-0.4-1-1S13.4,11,14,11z M16.7,20.3L13,16.7l3.6-3.6l3.6,3.6L16.7,20.3z"/></g>
|
||
<g id="image"><path d="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5L8.5,13.5z"/></g>
|
||
<g id="iso"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M5.5,7.5h2v-2H9v2h2V9H9v2H7.5V9h-2V7.5z M19,19L5,19L19,5V19z M17,17v-1.5h-5V17H17z"/></g>
|
||
<g id="landscape"><path d="M14,6l-3.8,5l2.9,3.8L11.5,16C9.8,13.8,7,10,7,10l-6,8h22L14,6z"/></g>
|
||
<g id="movie-creation"><path d="M18,4l2,4h-3l-2-4h-2l2,4h-3l-2-4H8l2,4H7L5,4H4C2.9,4,2,4.9,2,6l0,12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V4H18z"/></g>
|
||
<g id="palette"><path d="M12,3c-5,0-9,4-9,9s4,9,9,9c0.8,0,1.5-0.7,1.5-1.5c0-0.4-0.1-0.7-0.4-1c-0.2-0.3-0.4-0.6-0.4-1c0-0.8,0.7-1.5,1.5-1.5H16c2.8,0,5-2.2,5-5C21,6.6,17,3,12,3z M6.5,12C5.7,12,5,11.3,5,10.5S5.7,9,6.5,9C7.3,9,8,9.7,8,10.5S7.3,12,6.5,12z M9.5,8C8.7,8,8,7.3,8,6.5S8.7,5,9.5,5C10.3,5,11,5.7,11,6.5S10.3,8,9.5,8z M14.5,8C13.7,8,13,7.3,13,6.5S13.7,5,14.5,5C15.3,5,16,5.7,16,6.5S15.3,8,14.5,8z M17.5,12c-0.8,0-1.5-0.7-1.5-1.5S16.7,9,17.5,9c0.8,0,1.5,0.7,1.5,1.5S18.3,12,17.5,12z"/></g>
|
||
<g id="panorama"><polygon points="21,13.5 21,13.5 21,13.5 "/></g>
|
||
<g id="panorama-fisheye"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S16.4,20,12,20z"/></g>
|
||
<g id="panorama-horizontal"><path d="M20,6.5v10.9c-2.6-0.8-5.3-1.2-8-1.2c-2.7,0-5.4,0.4-8,1.2V6.5c2.6,0.8,5.3,1.2,8,1.2C14.7,7.7,17.4,7.3,20,6.5 M21.4,4c-0.1,0-0.2,0-0.3,0.1c-2.9,1.1-6,1.6-9.1,1.6S5.8,5.2,2.9,4.1C2.8,4,2.7,4,2.6,4C2.2,4,2,4.2,2,4.6v14.7C2,19.8,2.2,20,2.6,20c0.1,0,0.2,0,0.3-0.1c2.9-1.1,6-1.6,9.1-1.6s6.2,0.5,9.1,1.6c0.1,0,0.2,0.1,0.3,0.1c0.3,0,0.6-0.2,0.6-0.6V4.6C22,4.2,21.8,4,21.4,4L21.4,4z"/></g>
|
||
<g id="panorama-vertical"><path d="M19.9,21.1c-1.1-2.9-1.6-6-1.6-9.1s0.5-6.2,1.6-9.1C20,2.8,20,2.7,20,2.6C20,2.2,19.8,2,19.4,2H4.6C4.2,2,4,2.2,4,2.6c0,0.1,0,0.2,0.1,0.3c1.1,2.9,1.6,6,1.6,9.1s-0.5,6.2-1.6,9.1C4,21.2,4,21.3,4,21.4C4,21.8,4.2,22,4.6,22h14.7c0.4,0,0.6-0.2,0.6-0.6C20,21.3,20,21.2,19.9,21.1z M6.5,20c0.8-2.6,1.2-5.3,1.2-8c0-2.7-0.4-5.4-1.2-8h10.9c-0.8,2.6-1.2,5.3-1.2,8c0,2.7,0.4,5.4,1.2,8H6.5z"/></g>
|
||
<g id="panorama-wide-angle"><path d="M12,6c2.4,0,4.7,0.2,7.3,0.6C19.8,8.4,20,10.2,20,12s-0.2,3.6-0.7,5.4C16.7,17.8,14.4,18,12,18s-4.7-0.2-7.3-0.6C4.2,15.6,4,13.8,4,12s0.2-3.6,0.7-5.4C7.3,6.2,9.6,6,12,6 M12,4C9.3,4,6.8,4.2,4,4.7L3.1,4.9L2.9,5.8C2.3,7.9,2,9.9,2,12s0.3,4.1,0.9,6.2l0.3,0.9L4,19.3c2.7,0.5,5.2,0.7,8,0.7s5.2-0.2,8-0.7l0.9-0.2l0.3-0.9c0.6-2.1,0.9-4.1,0.9-6.2s-0.3-4.1-0.9-6.2l-0.3-0.9L20,4.7C17.2,4.2,14.7,4,12,4L12,4z"/></g>
|
||
<g id="photo"><path d="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5L8.5,13.5z"/></g>
|
||
<g id="photo-album"><path d="M18,2H6C4.9,2,4,2.9,4,4v16c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2z M6,4h5v8l-2.5-1.5L6,12V4z M6,19l3-3.9l2.1,2.6l3-3.9L18,19H6z"/></g>
|
||
<g id="photo-library"><path d="M22,16V4c0-1.1-0.9-2-2-2H8C6.9,2,6,2.9,6,4v12c0,1.1,0.9,2,2,2h12C21.1,18,22,17.1,22,16z M11,12l2,2.7l3-3.7l4,5H8L11,12z M2,6v14c0,1.1,0.9,2,2,2h14v-2H4V6H2z"/></g>
|
||
<g id="photosphere"><path d="M22.1,7.6C20.4,3.7,16.5,1,12,1S3.6,3.7,1.9,7.6C1.3,7.9,0.6,8.2,0,8.5v7c0.6,0.3,1.3,0.6,1.9,0.9C3.6,20.3,7.5,23,12,23s8.4-2.7,10.1-6.6c0.7-0.3,1.3-0.6,1.9-0.9v-7C23.4,8.2,22.7,7.9,22.1,7.6z M19.9,6.8c-1.2-0.4-2.5-0.7-3.8-0.9c-0.4-1.1-0.8-2.1-1.3-2.9C16.9,3.6,18.7,5,19.9,6.8z M12,2.5c0.8,0,1.8,1.1,2.5,3.1c-0.8-0.1-1.7-0.1-2.5-0.1s-1.7,0.1-2.5,0.1C10.2,3.6,11.2,2.5,12,2.5z M9.2,2.9c-0.5,0.8-1,1.8-1.3,2.9C6.6,6.1,5.3,6.4,4.1,6.8C5.3,5,7.1,3.6,9.2,2.9z M4.1,17.2c1.2,0.4,2.5,0.7,3.8,0.9c0.4,1.1,0.8,2.1,1.3,2.9C7.1,20.4,5.3,19,4.1,17.2z M12,21.5c-0.8,0-1.8-1.1-2.5-3.1c0.8,0.1,1.7,0.1,2.5,0.1s1.7-0.1,2.5-0.1C13.8,20.4,12.8,21.5,12,21.5z M14.8,21.1c0.5-0.8,1-1.8,1.3-2.9c1.3-0.2,2.5-0.5,3.8-0.9C18.7,19,16.9,20.4,14.8,21.1z M22.5,14.6l-0.3,0.1c-1.1,0.5-2.2,0.9-3.4,1.3L15,11.6L12,15l-4-5l-4.4,5.5C3,15.2,2.4,15,1.8,14.7l-0.3-0.1V9.4l0.3-0.1c6.4-3,14-3,20.4,0l0.3,0.1V14.6z"/></g>
|
||
<g id="portrait"><path d="M12,12.2c1.2,0,2.2-1,2.2-2.2c0-1.2-1-2.2-2.2-2.2c-1.2,0-2.2,1-2.2,2.2C9.8,11.2,10.8,12.2,12,12.2z M16.5,16.2c0-1.5-3-2.2-4.5-2.2s-4.5,0.8-4.5,2.2V17h9V16.2z M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19L5,19V5h14V19z"/></g>
|
||
<g id="slideshow"><path d="M10,8v8l5-4L10,8z M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19L5,19V5h14V19z"/></g>
|
||
<g id="switch-camera"><path d="M20,4h-3.2L15,2H9L7.2,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M15,15.5V13H9v2.5L5.5,12L9,8.5V11h6V8.5l3.5,3.5L15,15.5z"/></g>
|
||
<g id="switch-video"><path d="M18,9.5V6c0-0.6-0.4-1-1-1H3C2.4,5,2,5.4,2,6v12c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-3.5l4,4v-13L18,9.5z M13,15.5V13H7v2.5L3.5,12L7,8.5V11h6V8.5l3.5,3.5L13,15.5z"/></g>
|
||
<g id="tag-faces"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z M15.5,11c0.8,0,1.5-0.7,1.5-1.5S16.3,8,15.5,8C14.7,8,14,8.7,14,9.5S14.7,11,15.5,11z M8.5,11c0.8,0,1.5-0.7,1.5-1.5S9.3,8,8.5,8C7.7,8,7,8.7,7,9.5S7.7,11,8.5,11z M12,17.5c2.3,0,4.3-1.5,5.1-3.5H6.9C7.7,16,9.7,17.5,12,17.5z"/></g>
|
||
<g id="timelapse"><path d="M16.2,7.8C15.1,6.6,13.5,6,12,6v6l-4.2,4.2c2.3,2.3,6.1,2.3,8.5,0C18.6,13.9,18.6,10.1,16.2,7.8z M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8c0-4.4,3.6-8,8-8c4.4,0,8,3.6,8,8C20,16.4,16.4,20,12,20z"/></g>
|
||
<g id="timer-10"><path d="M0,7.7v1.7l3-1V18h2V6H4.7L0,7.7z M23.8,14.4c-0.1-0.3-0.4-0.5-0.6-0.7c-0.3-0.2-0.6-0.4-1-0.5s-0.8-0.3-1.4-0.4c-0.3-0.1-0.6-0.2-0.9-0.2c-0.2-0.1-0.4-0.2-0.5-0.3c-0.1-0.1-0.2-0.2-0.3-0.3C19,11.8,19,11.7,19,11.6s0-0.3,0.1-0.4c0.1-0.1,0.1-0.2,0.3-0.3c0.1-0.1,0.3-0.2,0.5-0.2c0.2-0.1,0.4-0.1,0.6-0.1c0.3,0,0.5,0,0.7,0.1c0.2,0.1,0.3,0.2,0.5,0.3c0.1,0.1,0.2,0.3,0.3,0.4c0.1,0.2,0.1,0.3,0.1,0.5h1.9c0-0.4-0.1-0.8-0.2-1.1S23.3,10,23,9.8s-0.7-0.4-1.1-0.6C21.5,9.1,21,9,20.5,9c-0.5,0-1,0.1-1.4,0.2c-0.4,0.1-0.8,0.3-1.1,0.6c-0.3,0.2-0.5,0.5-0.7,0.8c-0.2,0.3-0.2,0.7-0.2,1c0,0.4,0.1,0.7,0.2,1c0.2,0.3,0.4,0.5,0.6,0.7c0.3,0.2,0.6,0.4,1,0.5c0.4,0.1,0.8,0.3,1.3,0.4c0.4,0.1,0.7,0.2,1,0.3c0.2,0.1,0.4,0.2,0.6,0.3S22,15,22,15.1c0,0.1,0.1,0.2,0.1,0.4c0,0.3-0.1,0.6-0.4,0.8c-0.3,0.2-0.7,0.3-1.2,0.3c-0.2,0-0.4,0-0.6-0.1c-0.2-0.1-0.4-0.1-0.6-0.2S19,16,18.9,15.8c-0.1-0.2-0.2-0.4-0.2-0.7h-1.9c0,0.4,0.1,0.7,0.2,1.1c0.2,0.3,0.4,0.7,0.7,0.9c0.3,0.3,0.7,0.5,1.2,0.7s1,0.3,1.6,0.3c0.5,0,1-0.1,1.4-0.2c0.4-0.1,0.8-0.3,1.1-0.5c0.3-0.2,0.5-0.5,0.7-0.8s0.2-0.7,0.2-1.1C24,15,23.9,14.6,23.8,14.4z M13.8,7c-0.3-0.4-0.7-0.7-1.2-0.9c-0.5-0.2-1-0.3-1.6-0.3c-0.6,0-1.1,0.1-1.6,0.3C8.9,6.3,8.5,6.6,8.2,7C7.8,7.5,7.6,8,7.4,8.6C7.2,9.3,7.1,10.1,7.1,11v1.9c0,0.9,0.1,1.7,0.3,2.4c0.2,0.7,0.5,1.2,0.8,1.6c0.3,0.4,0.8,0.7,1.2,0.9s1,0.3,1.6,0.3c0.6,0,1.1-0.1,1.6-0.3c0.5-0.2,0.9-0.5,1.2-0.9c0.3-0.4,0.6-0.9,0.8-1.6c0.2-0.7,0.3-1.5,0.3-2.4V11c0-0.9-0.1-1.7-0.3-2.4C14.4,8,14.2,7.5,13.8,7z M12.9,13.2c0,0.6,0,1.1-0.1,1.5c-0.1,0.4-0.2,0.8-0.4,1c-0.2,0.3-0.4,0.5-0.6,0.6c-0.2,0.1-0.5,0.2-0.8,0.2c-0.3,0-0.6-0.1-0.8-0.2C10,16.2,9.8,16,9.6,15.8c-0.2-0.3-0.3-0.6-0.4-1c-0.1-0.4-0.1-0.9-0.1-1.5v-2.5c0-0.6,0-1.1,0.1-1.5c0.1-0.4,0.2-0.7,0.4-1C9.7,8,9.9,7.8,10.2,7.7c0.2-0.1,0.5-0.2,0.8-0.2c0.3,0,0.6,0.1,0.8,0.2C12,7.8,12.2,8,12.4,8.2c0.2,0.3,0.3,0.6,0.4,1c0.1,0.4,0.1,0.9,0.1,1.5V13.2z"/></g>
|
||
<g id="timer"><path d="M15,1H9v2h6V1z M11,14h2V8h-2V14z M19,7.4L20.5,6C20,5.5,19.5,5,19,4.5L17.6,6c-1.5-1.2-3.5-2-5.6-2c-5,0-9,4-9,9c0,5,4,9,9,9s9-4,9-9C21,10.9,20.3,8.9,19,7.4z M12,20c-3.9,0-7-3.1-7-7c0-3.9,3.1-7,7-7c3.9,0,7,3.1,7,7C19,16.9,15.9,20,12,20z"/></g>
|
||
<g id="timer-3"><path d="M11.6,13c-0.2-0.2-0.4-0.5-0.6-0.7c-0.3-0.2-0.6-0.4-0.9-0.5c0.3-0.1,0.6-0.3,0.8-0.5c0.2-0.2,0.4-0.4,0.6-0.6c0.2-0.2,0.3-0.5,0.3-0.7c0.1-0.2,0.1-0.5,0.1-0.7c0-0.6-0.1-1-0.3-1.5c-0.2-0.4-0.4-0.8-0.8-1.1c-0.3-0.3-0.7-0.5-1.2-0.6C9.2,6,8.7,5.9,8.1,5.9C7.5,5.9,7,6,6.6,6.1S5.7,6.5,5.4,6.8C5,7.1,4.8,7.5,4.6,7.9C4.4,8.3,4.3,8.7,4.3,9.2h2c0-0.3,0-0.5,0.1-0.7c0.1-0.2,0.2-0.4,0.4-0.5C7,7.8,7.2,7.7,7.4,7.6c0.2-0.1,0.5-0.1,0.7-0.1c0.6,0,1.1,0.2,1.4,0.5c0.3,0.3,0.4,0.8,0.4,1.3c0,0.3,0,0.5-0.1,0.7c-0.1,0.2-0.2,0.4-0.4,0.6C9.2,10.7,9,10.9,8.8,11c-0.2,0.1-0.5,0.1-0.9,0.1H6.7v1.6h1.2c0.3,0,0.6,0,0.9,0.1c0.3,0.1,0.5,0.2,0.7,0.4c0.2,0.2,0.3,0.4,0.4,0.6c0.1,0.2,0.2,0.5,0.2,0.9c0,0.6-0.2,1.1-0.5,1.4c-0.4,0.3-0.8,0.5-1.5,0.5c-0.3,0-0.6,0-0.8-0.1c-0.2-0.1-0.4-0.2-0.6-0.4c-0.2-0.2-0.3-0.3-0.4-0.6c-0.1-0.2-0.1-0.5-0.1-0.7h-2c0,0.5,0.1,1,0.3,1.5c0.2,0.4,0.5,0.8,0.9,1c0.4,0.3,0.8,0.5,1.2,0.6s1,0.2,1.5,0.2c0.6,0,1.1-0.1,1.6-0.2c0.5-0.2,0.9-0.4,1.3-0.7c0.4-0.3,0.6-0.7,0.8-1.1c0.2-0.4,0.3-0.9,0.3-1.5c0-0.3,0-0.6-0.1-0.9C11.9,13.5,11.8,13.2,11.6,13z M20.9,14.4c-0.1-0.3-0.4-0.5-0.6-0.7s-0.6-0.4-1-0.5c-0.4-0.1-0.8-0.3-1.4-0.4c-0.3-0.1-0.6-0.2-0.9-0.2c-0.2-0.1-0.4-0.2-0.5-0.3c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.1-0.2-0.1-0.4s0-0.3,0.1-0.4c0.1-0.1,0.1-0.2,0.3-0.3c0.1-0.1,0.3-0.2,0.5-0.2c0.2-0.1,0.4-0.1,0.6-0.1c0.3,0,0.5,0,0.7,0.1c0.2,0.1,0.3,0.2,0.5,0.3c0.1,0.1,0.2,0.3,0.3,0.4c0.1,0.2,0.1,0.3,0.1,0.5H21c0-0.4-0.1-0.8-0.2-1.1c-0.2-0.3-0.4-0.6-0.7-0.9S19.4,9.4,19,9.2C18.6,9.1,18.1,9,17.6,9c-0.5,0-1,0.1-1.4,0.2c-0.4,0.1-0.8,0.3-1.1,0.6s-0.5,0.5-0.7,0.8c-0.2,0.3-0.2,0.7-0.2,1c0,0.4,0.1,0.7,0.2,1c0.2,0.3,0.4,0.5,0.6,0.7c0.3,0.2,0.6,0.4,1,0.5c0.4,0.1,0.8,0.3,1.3,0.4c0.4,0.1,0.7,0.2,1,0.3c0.2,0.1,0.4,0.2,0.6,0.3s0.2,0.2,0.3,0.3c0,0.1,0.1,0.2,0.1,0.4c0,0.3-0.1,0.6-0.4,0.8c-0.3,0.2-0.7,0.3-1.2,0.3c-0.2,0-0.4,0-0.6-0.1c-0.2-0.1-0.4-0.1-0.6-0.2c-0.2-0.1-0.3-0.3-0.4-0.4c-0.1-0.2-0.2-0.4-0.2-0.7h-1.9c0,0.4,0.1,0.7,0.2,1.1c0.2,0.3,0.4,0.7,0.7,0.9c0.3,0.3,0.7,0.5,1.2,0.7s1,0.3,1.6,0.3c0.5,0,1-0.1,1.4-0.2c0.4-0.1,0.8-0.3,1.1-0.5c0.3-0.2,0.5-0.5,0.7-0.8c0.2-0.3,0.2-0.7,0.2-1.1C21.1,15,21,14.6,20.9,14.4z"/></g>
|
||
<g id="timer-auto"><path d="M12,4C9.8,4,8,5.8,8,8c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,5.8,14.2,4,12,4L12,4z M12,14c-2.7,0-8,1.3-8,4v2h16v-2C20,15.3,14.7,14,12,14L12,14z"/></g>
|
||
<g id="timer-off"><path d="M19,4.5L17.6,6c-1.5-1.2-3.5-2-5.6-2C10.2,4,8.5,4.5,7,5.5l1.5,1.5C9.5,6.3,10.7,6,12,6c3.9,0,7,3.1,7,7c0,1.3-0.3,2.5-0.9,3.5l1.5,1.5c0.9-1.4,1.5-3.1,1.5-4.9c0-2.1-0.7-4.1-2-5.6L20.5,6L19,4.5z M15,1H9v2h6V1z M11,9.4l2,2V8h-2V9.4z M3,4L1.7,5.3L4.5,8C3.6,9.5,3,11.2,3,13c0,5,4,9,9,9c1.8,0,3.6-0.6,5-1.5l2.5,2.5l1.3-1.3L13,14L3,4z M12,20c-3.9,0-7-3.1-7-7c0-1.3,0.4-2.5,1-3.5l9.6,9.6C14.5,19.6,13.3,20,12,20z"/></g>
|
||
<g id="unknown-1"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M5.5,7.5h2v-2H9v2h2V9H9v2H7.5V9h-2V7.5z M19,19L5,19L19,5V19z M17,17v-1.5h-5V17H17z"/></g>
|
||
<g id="unknown-2"><path d="M12,16h5v-1.5h-5V16z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M6,8h2V6h1.5v2h2v1.5h-2v2H8v-2H6V8z M12,20c-2.2,0-4.2-0.9-5.7-2.3L17.7,6.3C19.1,7.8,20,9.8,20,12C20,16.4,16.4,20,12,20z"/></g>
|
||
<g id="unknown-3"><path d="M13,8h-2v3H8v2h3v3h2v-3h3v-2h-3V8z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8c0-4.4,3.6-8,8-8c4.4,0,8,3.6,8,8C20,16.4,16.4,20,12,20z"/></g>
|
||
<g id="unknown-4"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8c0-4.4,3.6-8,8-8c4.4,0,8,3.6,8,8C20,16.4,16.4,20,12,20z M8,13h8v-2H8V13z"/></g>
|
||
<g id="unknown-5"><path d="M12,10H4v2h8V10z M12,2L12,2l0,2c4.4,0,8,3.6,8,8c0,4.4-3.6,8-8,8c-2.2,0-4.2-0.9-5.7-2.3l-1.4,1.4C6.7,20.9,9.2,22,12,22c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z"/></g>
|
||
<g id="unknown-6"><path d="M16,10h-2v2h2V10z M16,14h-2v2h2V14z M8,10H6v2h2V10z M12,10h-2v2h2V10z M20,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18L4,18V6h16V18z"/></g>
|
||
<g id="unknown-7"><path d="M14,16h5v-5h3l-5.5-5.5L11,11h3V16z M11,20h11v-2H11V20z M5.5,7l-3.2,9h1.9l0.7-2h3.2l0.7,2h1.9L7.5,7H5.5z M5.4,12.6L6.5,9l1.1,3.6H5.4z"/></g>
|
||
<g id="warning"><path d="M1,21h22L12,2L1,21z M13,18h-2v-2h2V18z M13,14h-2v-4h2V14z"/></g>
|
||
<g id="wb-auto"><path d="M6.9,12.6h2.3L8,9L6.9,12.6z M22,7l-1.2,6.3L19.3,7h-1.6l-1.5,6.3L15,7h-0.8C12.8,5.2,10.5,4,8,4c-4.4,0-8,3.6-8,8s3.6,8,8,8c3.1,0,5.8-1.8,7.2-4.4l0.1,0.4H17l1.5-6.1L20,16h1.8l2-9H22z M10.3,16l-0.7-2H6.4l-0.7,2H3.8L7,7h2l3.2,9H10.3z"/></g>
|
||
<g id="wb-cloudy"><path d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z"/></g>
|
||
<g id="wb-incandescent"><path d="M3.5,18.5L5,20l1.8-1.8l-1.4-1.4L3.5,18.5z M11,22.4c0.3,0,2,0,2,0v-2.9h-2V22.4z M4,10.5H1v2h3V10.5z M15,6.3V1.5H9v4.8c-1.8,1-3,3-3,5.2c0,3.3,2.7,6,6,6s6-2.7,6-6C18,9.3,16.8,7.3,15,6.3z M20,10.5v2h3v-2H20z M17.2,18.2L19,20l1.4-1.4l-1.8-1.8L17.2,18.2z"/></g>
|
||
<g id="wb-irradescent"><path d="M5,14.5h14v-6H5V14.5z M11,0.6v2.9h2V0.6H11z M19,3l-1.8,1.8l1.4,1.4l1.8-1.8L19,3z M13,22.4v-2.9h-2v2.9C11.3,22.5,13,22.4,13,22.4z M20.5,18.5l-1.8-1.8l-1.4,1.4L19,20L20.5,18.5z M3.5,4.5l1.8,1.8l1.4-1.4L5,3L3.5,4.5z M5,20l1.8-1.8l-1.4-1.4l-1.8,1.8L5,20z"/></g>
|
||
<g id="wb-sunny"><path d="M6.8,4.8L5,3L3.5,4.5l1.8,1.8L6.8,4.8z M4,10.5H1v2h3V10.5z M13,0.6h-2v2.9h2V0.6z M20.5,4.5L19,3l-1.8,1.8l1.4,1.4L20.5,4.5z M17.2,18.2L19,20l1.4-1.4l-1.8-1.8L17.2,18.2z M20,10.5v2h3v-2H20z M12,5.5c-3.3,0-6,2.7-6,6s2.7,6,6,6s6-2.7,6-6S15.3,5.5,12,5.5z M11,22.4c0.3,0,2,0,2,0v-2.9h-2V22.4z M3.5,18.5L5,20l1.8-1.8l-1.4-1.4L3.5,18.5z"/></g>
|
||
</defs></svg>
|
||
</core-iconset-svg>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
|
||
<core-iconset-svg id="hardware" iconsize="24">
|
||
<svg><defs>
|
||
<g id="cast"><path d="M21,3H3C1.9,3,1,3.9,1,5v3h2V5h18v14h-7v2h7c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z M1,18v3h3C4,19.3,2.7,18,1,18z M1,14v2c2.8,0,5,2.2,5,5h2C8,17.1,4.9,14,1,14z M1,10v2c5,0,9,4,9,9h2C12,14.9,7.1,10,1,10z"/></g>
|
||
<g id="cast-connected"><path d="M1,18v3h3C4,19.3,2.7,18,1,18z M1,14v2c2.8,0,5,2.2,5,5h2C8,17.1,4.9,14,1,14z M19,7H5v1.6c4,1.3,7.1,4.4,8.4,8.4H19V7z M1,10v2c5,0,9,4,9,9h2C12,14.9,7.1,10,1,10z M21,3H3C1.9,3,1,3.9,1,5v3h2V5h18v14h-7v2h7c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z"/></g>
|
||
<g id="chromecast"><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,4c3,0,5.5,1.6,6.9,4H12c-1.9,0-3.6,1.4-3.9,3.2L5.7,7.1C7.2,5.2,9.4,4,12,4z M15,12c0,1.7-1.3,3-3,3c-1.7,0-3-1.3-3-3c0-1.7,1.3-3,3-3C13.7,9,15,10.3,15,12z M4,12c0-1.5,0.4-2.8,1.1-4l3.5,6l0,0c0.7,1.2,2,2,3.4,2c0.5,0,0.9-0.1,1.3-0.2l-2.4,4.1C7,19.4,4,16,4,12z M12,20l3.5-6l0,0c0.3-0.6,0.6-1.3,0.6-2c0-1.2-0.5-2.3-1.4-3h4.8c0.4,0.9,0.6,1.9,0.6,3C20,16.4,16.4,20,12,20z"/></g>
|
||
<g id="desktop-mac"><path d="M21,2H3C1.9,2,1,2.9,1,4v12c0,1.1,0.9,2,2,2h7l-2,3v1h8v-1l-2-3h7c1.1,0,2-0.9,2-2V4C23,2.9,22.1,2,21,2z M21,14H3V4h18V14z"/></g>
|
||
<g id="desktop-windows"><path d="M21,2H3C1.9,2,1,2.9,1,4v12c0,1.1,0.9,2,2,2h7v2H8v2h8v-2h-2v-2h7c1.1,0,2-0.9,2-2V4C23,2.9,22.1,2,21,2z M21,16H3V4h18V16z"/></g>
|
||
<g id="dock"><path d="M8,23h8v-2H8V23z M16,1L8,1C6.9,1,6,1.9,6,3v14c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V3C18,1.9,17.1,1,16,1z M16,15H8V5h8V15z"/></g>
|
||
<g id="gamepad"><path d="M15,7.5V2H9v5.5l3,3L15,7.5z M7.5,9H2v6h5.5l3-3L7.5,9z M9,16.5V22h6v-5.5l-3-3L9,16.5z M16.5,9l-3,3l3,3H22V9H16.5z"/></g>
|
||
<g id="glass"><path d="M13,11v2.5h5.9c-0.6,3.5-3.4,6-6.9,6c-4.1,0-7.5-3.4-7.5-7.5S7.9,4.5,12,4.5c2.1,0,3.9,0.9,5.2,2.3l1.8-1.8C17.2,3.2,14.8,2,12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,9.5-4.5,9.5-10v-1H13z"/></g>
|
||
<g id="headset"><path d="M12,1c-5,0-9,4-9,9v7c0,1.7,1.3,3,3,3h3v-8H5v-2c0-3.9,3.1-7,7-7c3.9,0,7,3.1,7,7v2h-4v8h3c1.7,0,3-1.3,3-3v-7C21,5,17,1,12,1z"/></g>
|
||
<g id="headset-mic"><path d="M12,1c-5,0-9,4-9,9v7c0,1.7,1.3,3,3,3h3v-8H5v-2c0-3.9,3.1-7,7-7c3.9,0,7,3.1,7,7v2h-4v8h4v1h-7v2h6c1.7,0,3-1.3,3-3V10C21,5,17,1,12,1z"/></g>
|
||
<g id="keyboard"><path d="M20,5H4C2.9,5,2,5.9,2,7l0,10c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V7C22,5.9,21.1,5,20,5z M11,8h2v2h-2V8z M11,11h2v2h-2V11z M8,8h2v2H8V8z M8,11h2v2H8V11z M7,13H5v-2h2V13z M7,10H5V8h2V10z M16,17H8v-2h8V17z M16,13h-2v-2h2V13z M16,10h-2V8h2V10z M19,13h-2v-2h2V13z M19,10h-2V8h2V10z"/></g>
|
||
<g id="keyboard-alt"><path d="M15.5,10c0.8,0,1.5-0.7,1.5-1.5S16.3,7,15.5,7S14,7.7,14,8.5S14.7,10,15.5,10z M8.5,10C9.3,10,10,9.3,10,8.5S9.3,7,8.5,7C7.7,7,7,7.7,7,8.5S7.7,10,8.5,10z M12,17c2.6,0,4.8-1.7,5.7-4H6.3C7.2,15.3,9.4,17,12,17z M12,1C6.5,1,2,5.5,2,11c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,5.5,17.5,1,12,1z M12,19c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,19,12,19z"/></g>
|
||
<g id="keyboard-arrow-down"><polygon points="7.4,7.8 12,12.4 16.6,7.8 18,9.2 12,15.2 6,9.2 "/></g>
|
||
<g id="keyboard-arrow-left"><polygon points="15.4,16.1 10.8,11.5 15.4,6.9 14,5.5 8,11.5 14,17.5 "/></g>
|
||
<g id="keyboard-arrow-right"><polygon points="8.6,16.3 13.2,11.8 8.6,7.2 10,5.8 16,11.8 10,17.8 "/></g>
|
||
<g id="keyboard-arrow-up"><polygon points="7.4,15.4 12,10.8 16.6,15.4 18,14 12,8 6,14 "/></g>
|
||
<g id="keyboard-backspace"><polygon points="21,11 6.8,11 10.4,7.4 9,6 3,12 9,18 10.4,16.6 6.8,13 21,13 "/></g>
|
||
<g id="keyboard-capslock"><path d="M12,8.4l4.6,4.6l1.4-1.4l-6-6l-6,6L7.4,13L12,8.4z M6,18h12v-2H6V18z"/></g>
|
||
<g id="keyboard-control"><path d="M6,10c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2c1.1,0,2-0.9,2-2C8,10.9,7.1,10,6,10z M18,10c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2c1.1,0,2-0.9,2-2C20,10.9,19.1,10,18,10z M12,10c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2c1.1,0,2-0.9,2-2C14,10.9,13.1,10,12,10z"/></g>
|
||
<g id="keyboard-hide"><path d="M20,3H4C2.9,3,2,3.9,2,5l0,10c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V5C22,3.9,21.1,3,20,3z M11,6h2v2h-2V6z M11,9h2v2h-2V9z M8,6h2v2H8V6z M8,9h2v2H8V9z M7,11H5V9h2V11z M7,8H5V6h2V8z M16,15H8v-2h8V15z M16,11h-2V9h2V11z M16,8h-2V6h2V8z M19,11h-2V9h2V11z M19,8h-2V6h2V8z M12,23l4-4H8L12,23z"/></g>
|
||
<g id="keyboard-return"><polygon points="19,7 19,11 5.8,11 9.4,7.4 8,6 2,12 8,18 9.4,16.6 5.8,13 21,13 21,7 "/></g>
|
||
<g id="keyboard-tab"><path d="M11.6,7.4l3.6,3.6H1v2h14.2l-3.6,3.6L13,18l6-6l-6-6L11.6,7.4z M20,6v12h2V6H20z"/></g>
|
||
<g id="keyboard-voice"><path d="M12,15c1.7,0,3-1.3,3-3l0-6c0-1.7-1.3-3-3-3c-1.7,0-3,1.3-3,3v6C9,13.7,10.3,15,12,15z M17.3,12c0,3-2.5,5.1-5.3,5.1c-2.8,0-5.3-2.1-5.3-5.1H5c0,3.4,2.7,6.2,6,6.7V22h2v-3.3c3.3-0.5,6-3.3,6-6.7H17.3z"/></g>
|
||
<g id="laptop"><path d="M20,18c1.1,0,2-0.9,2-2l0-10c0-1.1-0.9-2-2-2H4C2.9,4,2,4.9,2,6v10c0,1.1,0.9,2,2,2H0v2h24v-2H20z M4,6h16v10H4V6z"/></g>
|
||
<g id="laptop-chromebook"><path d="M22,18V3H2v15H0v2h24v-2H22z M14,18h-4v-1h4V18z M20,15H4V5h16V15z"/></g>
|
||
<g id="laptop-mac"><path d="M20,18c1.1,0,2-0.9,2-2l0-11c0-1.1-0.9-2-2-2H4C2.9,3,2,3.9,2,5v11c0,1.1,0.9,2,2,2H0c0,1.1,0.9,2,2,2h20c1.1,0,2-0.9,2-2H20z M4,5h16v11H4V5z M12,19c-0.6,0-1-0.4-1-1s0.4-1,1-1c0.6,0,1,0.4,1,1S12.6,19,12,19z"/></g>
|
||
<g id="laptop-windows"><path d="M20,18v-1c1.1,0,2-0.9,2-2l0-10c0-1.1-0.9-2-2-2H4C2.9,3,2,3.9,2,5v10c0,1.1,0.9,2,2,2v1H0v2h24v-2H20z M4,5h16v10H4V5z"/></g>
|
||
<g id="memory"><path d="M15,9H9v6h6V9z M13,13h-2v-2h2V13z M21,11V9h-2V7c0-1.1-0.9-2-2-2h-2V3h-2v2h-2V3H9v2H7C5.9,5,5,5.9,5,7v2H3v2h2v2H3v2h2v2c0,1.1,0.9,2,2,2h2v2h2v-2h2v2h2v-2h2c1.1,0,2-0.9,2-2v-2h2v-2h-2v-2H21z M17,17H7V7h10V17z"/></g>
|
||
<g id="mouse"><path d="M13,1.1V9h7C20,4.9,16.9,1.6,13,1.1z M4,15c0,4.4,3.6,8,8,8c4.4,0,8-3.6,8-8v-4H4V15z M11,1.1C7.1,1.6,4,4.9,4,9h7V1.1z"/></g>
|
||
<g id="nest-protect"><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6c3.3,0,6,2.7,6,6S15.3,18,12,18z"/><circle cx="12" cy="12" r="4"/></g>
|
||
<g id="nest-thermostat"><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10c5.5,0,10-4.5,10-10C22,6.5,17.5,2,12,2z M12,5c1.6,0,3,0.5,4.2,1.4L14,8.6C13.4,8.2,12.7,8,12,8c-2.2,0-4,1.8-4,4c0,1.1,0.4,2.1,1.2,2.8l-2.1,2.1C5.8,15.7,5,13.9,5,12C5,8.1,8.1,5,12,5z M16.9,16.9l-2.1-2.1c0.7-0.7,1.2-1.7,1.2-2.8c0-0.7-0.2-1.4-0.6-2l2.2-2.2C18.5,9,19,10.4,19,12C19,13.9,18.2,15.7,16.9,16.9z"/></g>
|
||
<g id="phone-android"><path d="M16,1H8C6.3,1,5,2.3,5,4v16c0,1.7,1.3,3,3,3h8c1.7,0,3-1.3,3-3V4C19,2.3,17.7,1,16,1z M14,21h-4v-1h4V21z M17.2,18H6.8V4h10.5V18z"/></g>
|
||
<g id="phone-iphone"><path d="M15.5,1h-8C6.1,1,5,2.1,5,3.5v17C5,21.9,6.1,23,7.5,23h8c1.4,0,2.5-1.1,2.5-2.5v-17C18,2.1,16.9,1,15.5,1z M11.5,22c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5c0.8,0,1.5,0.7,1.5,1.5S12.3,22,11.5,22z M16,18H7V4h9V18z"/></g>
|
||
<g id="phonelink"><path d="M4,6h18V4H4C2.9,4,2,4.9,2,6v11H0v3h14v-3H4V6z M23,8h-6c-0.5,0-1,0.5-1,1v10c0,0.5,0.5,1,1,1h6c0.5,0,1-0.5,1-1V9C24,8.5,23.5,8,23,8z M22,17h-4v-7h4V17z"/></g>
|
||
<g id="phonelink-off"><path d="M22,6V4H6.8l2,2H22z M1.9,1.6L0.6,2.9l1.8,1.8C2.2,5.1,2,5.5,2,6v11H0v3h17.7l2.4,2.4l1.3-1.3L3.9,3.6L1.9,1.6z M4,6.3L14.7,17H4V6.3z M23,8h-6c-0.5,0-1,0.5-1,1v4.2l2,2V10h4v7h-2.2l3,3H23c0.5,0,1-0.5,1-1V9C24,8.5,23.5,8,23,8z"/></g>
|
||
<g id="security"><path d="M12,1L3,5v6c0,5.6,3.8,10.7,9,12c5.2-1.3,9-6.4,9-12V5L12,1z M12,12h7c-0.5,4.1-3.3,7.8-7,8.9V12l-7,0V6.3l7-3.1V12z"/></g>
|
||
<g id="smartphone"><path d="M17,1L7,1C5.9,1,5,1.9,5,3v18c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V3C19,1.9,18.1,1,17,1z M17,19H7V5h10V19z"/></g>
|
||
<g id="speaker"><path d="M17,2H7C5.9,2,5,2.9,5,4v16c0,1.1,0.9,2,2,2l10,0c1.1,0,2-0.9,2-2V4C19,2.9,18.1,2,17,2z M12,4c1.1,0,2,0.9,2,2s-0.9,2-2,2c-1.1,0-2-0.9-2-2S10.9,4,12,4z M12,20c-2.8,0-5-2.2-5-5s2.2-5,5-5c2.8,0,5,2.2,5,5S14.8,20,12,20z M12,12c-1.7,0-3,1.3-3,3c0,1.7,1.3,3,3,3c1.7,0,3-1.3,3-3C15,13.3,13.7,12,12,12z"/></g>
|
||
<g id="tablet"><path d="M21,4H3C1.9,4,1,4.9,1,6v12c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2l0-12C23,4.9,22.1,4,21,4z M19,18H5V6h14V18z"/></g>
|
||
<g id="tablet-android"><path d="M18,0H6C4.3,0,3,1.3,3,3v18c0,1.7,1.3,3,3,3h12c1.7,0,3-1.3,3-3V3C21,1.3,19.7,0,18,0z M14,22h-4v-1h4V22z M19.2,19H4.8V3h14.5V19z"/></g>
|
||
<g id="tablet-mac"><path d="M18.5,0h-14C3.1,0,2,1.1,2,2.5v19C2,22.9,3.1,24,4.5,24h14c1.4,0,2.5-1.1,2.5-2.5v-19C21,1.1,19.9,0,18.5,0z M11.5,23c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5c0.8,0,1.5,0.7,1.5,1.5S12.3,23,11.5,23z M19,19H4V3h15V19z"/></g>
|
||
<g id="tv"><path d="M21,3H3C1.9,3,1,3.9,1,5v12c0,1.1,0.9,2,2,2h5v2h8v-2h5c1.1,0,2-0.9,2-2l0-12C23,3.9,22.1,3,21,3z M21,17H3V5h18V17z"/></g>
|
||
<g id="watch"><path d="M20,12c0-2.5-1.2-4.8-3-6.3L16,0H8L7,5.7C5.2,7.2,4,9.5,4,12s1.2,4.8,3,6.3L8,24h8l1-5.7C18.8,16.8,20,14.5,20,12z M6,12c0-3.3,2.7-6,6-6c3.3,0,6,2.7,6,6s-2.7,6-6,6C8.7,18,6,15.3,6,12z"/></g>
|
||
</defs></svg>
|
||
</core-iconset-svg>
|
||
|
||
|
||
<polymer-element name="domain-icon" attributes="domain state" constructor="DomainIcon" assetpath="polymer/">
|
||
<template>
|
||
<core-icon icon="{{icon(domain, state)}}"></core-icon>
|
||
</template>
|
||
<script>
|
||
Polymer('domain-icon',{
|
||
|
||
icon: function(domain, state) {
|
||
switch(domain) {
|
||
case "homeassistant":
|
||
return "home";
|
||
|
||
case "group":
|
||
return "social:communities";
|
||
|
||
case "device_tracker":
|
||
return "social:person";
|
||
|
||
case "wemo":
|
||
return "settings-input-svideo";
|
||
|
||
case "chromecast":
|
||
if(state && state != "idle") {
|
||
return "hardware:cast-connected";
|
||
} else {
|
||
return "hardware:cast";
|
||
}
|
||
|
||
case "process":
|
||
return "hardware:memory"
|
||
|
||
case "sun":
|
||
return "image:wb-sunny"
|
||
|
||
case "light":
|
||
return "image:wb-incandescent"
|
||
|
||
default:
|
||
return "bookmark-outline";
|
||
}
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="state-badge" attributes="stateObj" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
position: relative;
|
||
display: inline-block;
|
||
width: 45px;
|
||
background-color: #4fc3f7;
|
||
color: white;
|
||
border-radius: 50%;
|
||
transition: all .3s ease-in-out;
|
||
}
|
||
|
||
div {
|
||
height: 45px;
|
||
text-align: center;
|
||
}
|
||
|
||
#picture {
|
||
border-radius: 50%;
|
||
}
|
||
|
||
domain-icon {
|
||
margin: 0 auto;
|
||
}
|
||
|
||
/* Color the icon if light or sun is on */
|
||
domain-icon[data-domain=light][data-state=on],
|
||
domain-icon[data-domain=sun][data-state=above_horizon] {
|
||
color: #fff176;
|
||
}
|
||
</style>
|
||
|
||
<div horizontal="" layout="" center="">
|
||
<domain-icon id="icon" domain="{{stateObj.domain}}" state="{{stateObj.state}}">
|
||
</domain-icon>
|
||
<div fit="" id="picture" style="{{'background-image: url('+stateObj.attributes.entity_picture+')'}}"></div>
|
||
</div>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('state-badge',{
|
||
observe: {
|
||
'stateObj.state': 'stateChanged',
|
||
'stateObj.attributes.entity_picture': 'entityPictureChanged'
|
||
},
|
||
|
||
stateChanged: function(oldVal, newVal) {
|
||
var state = this.stateObj;
|
||
|
||
// for domain light, set color of icon to light color if available
|
||
if(state.domain == "light" && newVal == "on" &&
|
||
state.attributes.brightness && state.attributes.xy_color) {
|
||
|
||
var rgb = this.xyBriToRgb(state.attributes.xy_color[0],
|
||
state.attributes.xy_color[1],
|
||
state.attributes.brightness);
|
||
this.style.color = "rgb(" + rgb.map(Math.floor).join(",") + ")";
|
||
} else {
|
||
this.style.color = 'white';
|
||
}
|
||
},
|
||
|
||
// from http://stackoverflow.com/questions/22894498/philips-hue-convert-xy-from-api-to-hex-or-rgb
|
||
xyBriToRgb: function (x, y, bri) {
|
||
z = 1.0 - x - y;
|
||
Y = bri / 255.0; // Brightness of lamp
|
||
X = (Y / y) * x;
|
||
Z = (Y / y) * z;
|
||
r = X * 1.612 - Y * 0.203 - Z * 0.302;
|
||
g = -X * 0.509 + Y * 1.412 + Z * 0.066;
|
||
b = X * 0.026 - Y * 0.072 + Z * 0.962;
|
||
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
|
||
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
|
||
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
|
||
maxValue = Math.max(r,g,b);
|
||
r /= maxValue;
|
||
g /= maxValue;
|
||
b /= maxValue;
|
||
r = r * 255; if (r < 0) { r = 255 };
|
||
g = g * 255; if (g < 0) { g = 255 };
|
||
b = b * 255; if (b < 0) { b = 255 };
|
||
return [r, g, b]
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="state-card" attributes="stateObj cb_turn_on, cb_turn_off cb_edit" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
background-color: #fff;
|
||
border-radius: 2px;
|
||
box-shadow: rgba(0, 0, 0, 0.098) 0px 2px 4px, rgba(0, 0, 0, 0.098) 0px 0px 3px;
|
||
transition: all 0.30s ease-out;
|
||
|
||
position: relative;
|
||
background-color: white;
|
||
padding: 16px;
|
||
width: 100%;
|
||
}
|
||
|
||
state-badge {
|
||
float: left;
|
||
cursor: pointer;
|
||
}
|
||
|
||
state-badge:hover {
|
||
background-color: #039be5;
|
||
}
|
||
|
||
.name, .state.text {
|
||
text-transform: capitalize;
|
||
font-weight: 300;
|
||
font-size: 1.3rem;
|
||
}
|
||
|
||
.state {
|
||
text-align: right;
|
||
}
|
||
|
||
.info {
|
||
margin-left: 60px;
|
||
}
|
||
|
||
.time-ago {
|
||
color: darkgrey;
|
||
margin-top: -2px;
|
||
}
|
||
|
||
/* the splash while enabling */
|
||
paper-toggle-button::shadow paper-radio-button::shadow #ink[checked] {
|
||
color: #0091ea;
|
||
}
|
||
|
||
/* filling of circle when checked */
|
||
paper-toggle-button::shadow paper-radio-button::shadow #onRadio {
|
||
background-color: #039be5;
|
||
}
|
||
|
||
/* line when checked */
|
||
paper-toggle-button::shadow #toggleBar[checked] {
|
||
background-color: #039be5;
|
||
}
|
||
</style>
|
||
|
||
<div horizontal="" justified="" layout="">
|
||
|
||
<div class="entity">
|
||
<state-badge stateobj="{{stateObj}}" on-click="{{editClicked}}">
|
||
</state-badge>
|
||
|
||
<div class="info">
|
||
<div class="name">
|
||
{{stateObj.entityDisplay}}
|
||
</div>
|
||
|
||
<div class="time-ago">
|
||
<core-tooltip label="{{stateObj.last_changed}}" position="bottom">
|
||
{{lastChangedFromNow}}
|
||
</core-tooltip>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<template if="{{!stateUnknown}}">
|
||
<template if="{{stateObj.canToggle}}">
|
||
<div class="state toggle" self-center="" flex="">
|
||
<paper-toggle-button checked="{{toggleChecked}}">
|
||
</paper-toggle-button>
|
||
</div>
|
||
</template>
|
||
<template if="{{!stateObj.canToggle}}">
|
||
<div class="state text">{{stateObj.stateDisplay}}</div>
|
||
</template>
|
||
</template>
|
||
|
||
<template if="{{stateUnknown}}">
|
||
<div class="state" self-center="" flex="">Updating..</div>
|
||
</template>
|
||
|
||
</div>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('state-card',{
|
||
// attributes
|
||
stateObj: {},
|
||
|
||
cb_turn_on: null,
|
||
cb_turn_off: null,
|
||
cb_edit: null,
|
||
stateUnknown: false,
|
||
toggleChecked: -1,
|
||
|
||
computed: {
|
||
lastChangedFromNow: "stateObj.last_changed | parseLastChangedFromNow",
|
||
},
|
||
|
||
observe: {
|
||
'stateObj.state': 'stateChanged'
|
||
},
|
||
|
||
parseLastChangedFromNow: function(lastChanged) {
|
||
return moment(lastChanged, "HH:mm:ss DD-MM-YYYY").fromNow()
|
||
},
|
||
|
||
toggleCheckedChanged: function(oldVal, newVal) {
|
||
// to filter out init
|
||
if(oldVal === -1) {
|
||
return;
|
||
}
|
||
|
||
if(newVal && this.stateObj.state == "off") {
|
||
this.turn_on();
|
||
} else if(!newVal && this.stateObj.state == "on") {
|
||
this.turn_off();
|
||
}
|
||
},
|
||
|
||
stateChanged: function(oldVal, newVal) {
|
||
this.stateUnknown = newVal == null;
|
||
this.toggleChecked = newVal == "on"
|
||
},
|
||
|
||
turn_on: function() {
|
||
if(this.cb_turn_on) {
|
||
this.cb_turn_on(this.stateObj.entity_id);
|
||
|
||
// unset state while we wait for an update
|
||
var delayUnsetSate = function() {
|
||
this.stateObj.state = null;
|
||
}
|
||
setTimeout(delayUnsetSate.bind(this), 500);
|
||
}
|
||
},
|
||
|
||
turn_off: function() {
|
||
if(this.cb_turn_off) {
|
||
this.cb_turn_off(this.stateObj.entity_id);
|
||
|
||
// unset state while we wait for an update
|
||
var delayUnsetSate = function() {
|
||
this.stateObj.state = null;
|
||
}
|
||
setTimeout(delayUnsetSate.bind(this), 500);
|
||
}
|
||
},
|
||
|
||
editClicked: function() {
|
||
if(this.cb_edit) {
|
||
this.cb_edit(this.stateObj.entity_id);
|
||
}
|
||
},
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="states-cards" attributes="api filter" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
display: block;
|
||
width: 100%;
|
||
}
|
||
|
||
state-card {
|
||
display: inline-block;
|
||
}
|
||
|
||
@media all and (min-width: 764px) {
|
||
:host {
|
||
padding-bottom: 8px;
|
||
}
|
||
|
||
state-card {
|
||
width: calc(50% - 42px);
|
||
margin: 8px 0 0 8px;
|
||
}
|
||
}
|
||
|
||
@media all and (min-width: 1100px) {
|
||
state-card {
|
||
width: calc(33% - 37px);
|
||
|
||
}
|
||
}
|
||
|
||
</style>
|
||
|
||
<div horizontal="" layout="" wrap="">
|
||
<template repeat="{{state in states}}">
|
||
<state-card stateobj="{{state}}" cb_turn_on="{{api.turn_on}}" cb_turn_off="{{api.turn_off}}" cb_edit="{{editCallback}}">
|
||
</state-card>
|
||
</template>
|
||
|
||
</div>
|
||
</template>
|
||
<script>
|
||
Polymer('states-cards',{
|
||
raw_states: [],
|
||
states: [],
|
||
filter: null,
|
||
filter_substates: null,
|
||
|
||
filterChanged: function(oldVal, newVal) {
|
||
this.refilterStates();
|
||
},
|
||
|
||
ready: function() {
|
||
this.editCallback = this.editCallback.bind(this);
|
||
},
|
||
|
||
domReady: function() {
|
||
this.raw_states = this.api.states
|
||
|
||
this.api.addEventListener('states-updated', this.statesUpdated.bind(this))
|
||
|
||
this.refilterStates();
|
||
},
|
||
|
||
statesUpdated: function() {
|
||
this.raw_states = this.api.states;
|
||
|
||
this.refilterStates();
|
||
},
|
||
|
||
refilterStates: function() {
|
||
if(this.filter == null) {
|
||
// all states except groups
|
||
this.states = this.raw_states.filter(function(state) {
|
||
return state.domain != 'group'
|
||
});
|
||
|
||
} else {
|
||
var filter_state = this.api.getState(this.filter);
|
||
|
||
var map_states = function(entity_id) {
|
||
return this.api.getState(entity_id);
|
||
}.bind(this)
|
||
|
||
// take the parent state and append it's children
|
||
this.states = [filter_state].concat(
|
||
filter_state.attributes.entity_id.map(map_states))
|
||
}
|
||
},
|
||
|
||
editCallback: function(entityId) {
|
||
this.api.showEditStateDialog(entityId);
|
||
},
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="home-assistant-main" attributes="api" assetpath="polymer/">
|
||
<template>
|
||
<style type="text/css">
|
||
|
||
:host {
|
||
font-family: 'RobotoDraft', sans-serif;
|
||
}
|
||
|
||
core-header-panel {
|
||
height: 100%;
|
||
overflow: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
background-color: #E5E5E5;
|
||
}
|
||
|
||
core-toolbar {
|
||
background: #03a9f4;
|
||
font-size: 1.3rem;
|
||
color: white;
|
||
}
|
||
|
||
paper-tab {
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
</style>
|
||
|
||
<core-header-panel fullbleed="">
|
||
|
||
<core-toolbar class="medium-tall">
|
||
<div flex="">
|
||
Home Assistant
|
||
</div>
|
||
<paper-icon-button icon="refresh" on-click="{{handleRefreshClick}}"></paper-icon-button>
|
||
<paper-icon-button icon="settings-remote" on-click="{{handleServiceClick}}"></paper-icon-button>
|
||
<paper-menu-button icon="more-vert" halign="right">
|
||
<paper-item label="Set State">
|
||
<a on-click="{{handleAddStateClick}}"></a>
|
||
</paper-item>
|
||
<paper-item label="Trigger Event">
|
||
<a on-click="{{handleEventClick}}"></a>
|
||
</paper-item>
|
||
<paper-item label="Log Out">
|
||
<a on-click="{{handleLogOutClick}}"></a>
|
||
</paper-item>
|
||
</paper-menu-button>
|
||
|
||
<div class="bottom fit" horizontal="" layout="">
|
||
<paper-tabs id="tabsHolder" noink="" flex="" selected="0" on-core-select="{{tabClicked}}">
|
||
|
||
<paper-tab>ALL</paper-tab>
|
||
|
||
<template repeat="{{state in api.states}}">
|
||
<template if="{{state.isCustomGroup}}">
|
||
<paper-tab data-entity="{{state.entity_id}}">
|
||
{{state.entityDisplay}}
|
||
</paper-tab>
|
||
</template>
|
||
</template>
|
||
|
||
</paper-tabs>
|
||
</div>
|
||
</core-toolbar>
|
||
|
||
<div class="content" flex="">
|
||
<states-cards api="{{api}}" filter="{{selectedTab}}"></states-cards>
|
||
</div>
|
||
|
||
</core-header-panel>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('home-assistant-main',{
|
||
selectedTab: null,
|
||
|
||
tabClicked: function(ev) {
|
||
if(ev.detail.isSelected) {
|
||
// will be null for ALL tab
|
||
this.selectedTab = ev.detail.item.getAttribute('data-entity');
|
||
}
|
||
},
|
||
|
||
handleRefreshClick: function() {
|
||
this.api.fetchAll();
|
||
},
|
||
|
||
handleEventClick: function() {
|
||
this.api.showFireEventDialog();
|
||
},
|
||
|
||
handleServiceClick: function() {
|
||
this.api.showCallServiceDialog();
|
||
},
|
||
|
||
handleAddStateClick: function() {
|
||
this.api.showSetStateDialog();
|
||
},
|
||
|
||
handleLogOutClick: function() {
|
||
this.api.logOut();
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
</div>
|
||
<div hidden>
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`paper-toast` provides lightweight feedback about an operation in a small popup
|
||
at the base of the screen on mobile and at the lower left on desktop. Toasts are
|
||
above all other elements on screen, including the FAB.
|
||
|
||
Toasts automatically disappear after a timeout or after user interaction
|
||
elsewhere on the screen, whichever comes first. Toasts can be swiped off
|
||
screen. There can be only one on the screen at a time.
|
||
|
||
Example:
|
||
|
||
<paper-toast text="Your draft has been discarded." onclick="discardDraft(el)"></paper-toast>
|
||
|
||
<script>
|
||
function discardDraft(el) {
|
||
el.show();
|
||
}
|
||
</script>
|
||
|
||
An action button can be presented in the toast.
|
||
|
||
Example (using Polymer's data-binding features):
|
||
|
||
<paper-toast id="toast2" text="Connection timed out. Showing limited messages.">
|
||
<div style="color: blue;" on-tap="{{retry}}">Retry</div>
|
||
</paper-toast>
|
||
|
||
Positioning toast:
|
||
|
||
A standard toast appears near the lower left of the screen. You can change the
|
||
position by overriding bottom and left positions.
|
||
|
||
paper-toast {
|
||
bottom: 40px;
|
||
left: 10px;
|
||
}
|
||
|
||
To make it fit at the bottom of the screen:
|
||
|
||
paper-toast {
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
}
|
||
|
||
When the screen size is smaller than the `responsiveWidth` (default to 480px),
|
||
the toast will automatically fits at the bottom of the screen.
|
||
|
||
@group Paper Elements
|
||
@element paper-toast
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
<!--
|
||
/**
|
||
* @group Polymer Core Elements
|
||
* @element core-media-query
|
||
* @status beta
|
||
* @homepage github.io
|
||
*
|
||
* core-media-query can be used to data bind to a CSS media query.
|
||
* The "query" property is a bare CSS media query.
|
||
* The "queryMatches" property will be a boolean representing if the page matches that media query.
|
||
*
|
||
* core-media-query uses media query listeners to dynamically update the "queryMatches" property.
|
||
* A "core-media-change" event also fires when queryMatches changes.
|
||
*
|
||
* Example:
|
||
*
|
||
* <core-media-query query="max-width: 640px" queryMatches="{{phoneScreen}}"></core-media-query>
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* Fired when the media query state changes
|
||
*
|
||
* @event core-media-change
|
||
*/
|
||
-->
|
||
|
||
|
||
<polymer-element name="core-media-query" attributes="query queryMatches" assetpath="polymer/bower_components/core-media-query/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
display: none;
|
||
}
|
||
</style>
|
||
</template>
|
||
<script>
|
||
Polymer('core-media-query', {
|
||
|
||
/**
|
||
* The Boolean return value of the media query
|
||
*
|
||
* @attribute queryMatches
|
||
* @type Boolean
|
||
* @default false
|
||
*/
|
||
queryMatches: false,
|
||
|
||
/**
|
||
* The CSS media query to evaulate
|
||
*
|
||
* @attribute query
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
query: '',
|
||
ready: function() {
|
||
this._mqHandler = this.queryHandler.bind(this);
|
||
this._mq = null;
|
||
},
|
||
queryChanged: function() {
|
||
if (this._mq) {
|
||
this._mq.removeListener(this._mqHandler);
|
||
}
|
||
var query = this.query;
|
||
if (query[0] !== '(') {
|
||
query = '(' + this.query + ')';
|
||
}
|
||
this._mq = window.matchMedia(query);
|
||
this._mq.addListener(this._mqHandler);
|
||
this.queryHandler(this._mq);
|
||
},
|
||
queryHandler: function(mq) {
|
||
this.queryMatches = mq.matches;
|
||
this.asyncFire('core-media-change', mq);
|
||
}
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="paper-toast" attributes="text duration opened responsiveWidth swipeDisabled" role="status" assetpath="polymer/bower_components/paper-toast/">
|
||
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: inline-block;
|
||
background: #323232;
|
||
color: #f1f1f1;
|
||
min-height: 48px;
|
||
min-width: 288px;
|
||
padding: 16px 24px 12px;
|
||
box-sizing: border-box;
|
||
-moz-box-sizing: border-box;
|
||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
|
||
border-radius: 2px;
|
||
bottom: 12px;
|
||
left: 12px;
|
||
font-size: 14px;
|
||
cursor: default;
|
||
}
|
||
|
||
:host(.capsule) {
|
||
border-radius: 24px;
|
||
}
|
||
|
||
:host(.fit-bottom) {
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
min-width: 0;
|
||
border-radius: 0;
|
||
}
|
||
|
||
:host(.core-transition.dragging) {
|
||
transition: none;
|
||
}
|
||
|
||
:host(.core-transition.fade-out-down),
|
||
:host(.core-transition.fade-out-up),
|
||
:host(.core-transition.fade-out-right),
|
||
:host(.core-transition.fade-out-left) {
|
||
opacity: 0;
|
||
transition: -webkit-transform 0.08s ease-in-out, opacity 0.08s ease-in-out;
|
||
transition: transform 0.08s ease-in-out, opacity 0.08s ease-in-out;
|
||
}
|
||
|
||
:host(.core-transition.fade-out-down) {
|
||
-webkit-transform: translate(0, 100%);
|
||
transform: translate(0, 100%);
|
||
}
|
||
|
||
:host(.core-transition.fade-out-up) {
|
||
-webkit-transform: translate(0, -100%);
|
||
transform: translate(0, -100%);
|
||
}
|
||
|
||
:host(.core-transition.fade-out-right) {
|
||
-webkit-transform: translate(100%, 0);
|
||
transform: translate(100%, 0);
|
||
}
|
||
|
||
:host(.core-transition.fade-out-left) {
|
||
-webkit-transform: translate(-100%, 0);
|
||
transform: translate(-100%, 0);
|
||
}
|
||
|
||
.toast-container {
|
||
overflow: hidden;
|
||
}
|
||
|
||
.toast-action {
|
||
padding-left: 24px;
|
||
cursor: pointer;
|
||
text-transform: uppercase;
|
||
}
|
||
</style>
|
||
|
||
<core-overlay autofocusdisabled="" opened="{{opened}}" target="{{}}" sizingtarget="{{$.container}}" transition="core-transition-bottom"></core-overlay>
|
||
|
||
<div class="toast-container" horizontal="" layout="">
|
||
|
||
<div class="toast-text" flex="">{{text}}</div>
|
||
|
||
<div class="toast-text toast-action" on-tap="{{dismiss}}">
|
||
<content></content>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<core-media-query query="max-width: {{responsiveWidth}}" querymatches="{{narrowMode}}"></core-media-query>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
(function() {
|
||
|
||
var currentToast;
|
||
|
||
Polymer('paper-toast', {
|
||
|
||
/**
|
||
* The text shows in a toast.
|
||
*
|
||
* @attribute text
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
text: '',
|
||
|
||
/**
|
||
* The duration in milliseconds to show the toast.
|
||
*
|
||
* @attribute duration
|
||
* @type number
|
||
* @default 3000
|
||
*/
|
||
duration: 3000,
|
||
|
||
/**
|
||
* Set opened to true to show the toast and to false to hide it.
|
||
*
|
||
* @attribute opened
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
opened: false,
|
||
|
||
/**
|
||
* Min-width when the toast changes to narrow layout. In narrow layout,
|
||
* the toast fits at the bottom of the screen when opened.
|
||
*
|
||
* @attribute responsiveWidth
|
||
* @type string
|
||
* @default '480px'
|
||
*/
|
||
responsiveWidth: '480px',
|
||
|
||
/**
|
||
* If true, the toast can't be swiped.
|
||
*
|
||
* @attribute swipeDisabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
swipeDisabled: false,
|
||
|
||
eventDelegates: {
|
||
trackstart: 'trackStart',
|
||
track: 'track',
|
||
trackend: 'trackEnd',
|
||
transitionend: 'transitionEnd'
|
||
},
|
||
|
||
narrowModeChanged: function() {
|
||
this.classList.toggle('fit-bottom', this.narrowMode);
|
||
},
|
||
|
||
openedChanged: function() {
|
||
if (this.opened) {
|
||
this.dismissJob = this.job(this.dismissJob, this.dismiss, this.duration);
|
||
} else {
|
||
this.dismissJob && this.dismissJob.stop();
|
||
this.dismiss();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Toggle the opened state of the toast.
|
||
* @method toggle
|
||
*/
|
||
toggle: function() {
|
||
this.opened = !this.opened;
|
||
},
|
||
|
||
/**
|
||
* Show the toast for the specified duration
|
||
* @method show
|
||
*/
|
||
show: function() {
|
||
if (currentToast) {
|
||
currentToast.dismiss();
|
||
}
|
||
currentToast = this;
|
||
this.opened = true;
|
||
},
|
||
|
||
/**
|
||
* Dismiss the toast and hide it.
|
||
* @method dismiss
|
||
*/
|
||
dismiss: function() {
|
||
if (this.dragging) {
|
||
this.shouldDismiss = true;
|
||
} else {
|
||
this.opened = false;
|
||
if (currentToast === this) {
|
||
currentToast = null;
|
||
}
|
||
}
|
||
},
|
||
|
||
trackStart: function(e) {
|
||
if (!this.swipeDisabled) {
|
||
e.preventTap();
|
||
this.vertical = e.yDirection;
|
||
this.w = this.offsetWidth;
|
||
this.h = this.offsetHeight;
|
||
this.dragging = true;
|
||
this.classList.add('dragging');
|
||
}
|
||
},
|
||
|
||
track: function(e) {
|
||
if (this.dragging) {
|
||
var s = this.style;
|
||
if (this.vertical) {
|
||
var y = e.dy;
|
||
s.opacity = (this.h - Math.abs(y)) / this.h;
|
||
s.webkitTransform = s.transform = 'translate3d(0, ' + y + 'px, 0)';
|
||
} else {
|
||
var x = e.dx;
|
||
s.opacity = (this.w - Math.abs(x)) / this.w;
|
||
s.webkitTransform = s.transform = 'translate3d(' + x + 'px, 0, 0)';
|
||
}
|
||
}
|
||
},
|
||
|
||
trackEnd: function(e) {
|
||
if (this.dragging) {
|
||
this.classList.remove('dragging');
|
||
this.style.opacity = null;
|
||
this.style.webkitTransform = this.style.transform = null;
|
||
var cl = this.classList;
|
||
if (this.vertical) {
|
||
cl.toggle('fade-out-down', e.yDirection === 1 && e.dy > 0);
|
||
cl.toggle('fade-out-up', e.yDirection === -1 && e.dy < 0);
|
||
} else {
|
||
cl.toggle('fade-out-right', e.xDirection === 1 && e.dx > 0);
|
||
cl.toggle('fade-out-left', e.xDirection === -1 && e.dx < 0);
|
||
}
|
||
this.dragging = false;
|
||
}
|
||
},
|
||
|
||
transitionEnd: function() {
|
||
var cl = this.classList;
|
||
if (cl.contains('fade-out-right') || cl.contains('fade-out-left') ||
|
||
cl.contains('fade-out-down') || cl.contains('fade-out-up')) {
|
||
this.dismiss();
|
||
cl.remove('fade-out-right', 'fade-out-left',
|
||
'fade-out-down', 'fade-out-up');
|
||
} else if (this.shouldDismiss) {
|
||
this.dismiss();
|
||
}
|
||
this.shouldDismiss = false;
|
||
}
|
||
|
||
});
|
||
|
||
})();
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
Provides a dialog overlay.
|
||
|
||
Child elements that include a `dismissive` attribute are positioned in the lower left corner of the dialog. Elements that use the `affirmative` attribute are positioned in the lower right corner.
|
||
|
||
Child elements that include the `dismissive` or `affirmative` attribute will automatically toggle the dialog when clicked.
|
||
|
||
One child element should have the `autofocus` attribute so that the Enter key will automatically take action. This is
|
||
especially important for screen reader environments.
|
||
|
||
Example:
|
||
|
||
<paper-dialog heading="Title for dialog">
|
||
<p>Lorem ipsum ....</p>
|
||
<p>Id qui scripta ...</p>
|
||
<paper-button label="More Info..." dismissive></paper-button>
|
||
<paper-button label="Decline" affirmative></paper-button>
|
||
<paper-button label="Accept" affirmative autofocus></paper-button>
|
||
</paper-dialog>
|
||
|
||
#### Transitions
|
||
|
||
`<paper-dialog>` can be used with `<paper-transition>` to transition the overlay open and close.
|
||
|
||
To use a transition, import `paper-dialog-transition.html` alongside paper-dialog:
|
||
|
||
<link rel="import" href="paper-dialog/paper-dialog-transition.html">
|
||
|
||
Then set the `transition` attribute:
|
||
|
||
<paper-dialog heading="Title for dialog" transition="paper-dialog-transition-center">
|
||
|
||
<paper-dialog heading="Title for dialog" transition="paper-dialog-transition-bottom">
|
||
|
||
@group Paper Elements
|
||
@element paper-dialog
|
||
@homepage github.io
|
||
-->
|
||
<!--
|
||
Fired when the dialog's `opened` property changes.
|
||
|
||
@event core-overlay-open
|
||
@param {Object} detail
|
||
@param {Object} detail.opened the opened state
|
||
-->
|
||
|
||
|
||
|
||
|
||
<polymer-element name="paper-dialog" attributes="opened heading transition autoCloseDisabled backdrop layered closeSelector" role="dialog" assetpath="polymer/bower_components/paper-dialog/">
|
||
|
||
<template>
|
||
|
||
<style>/*
|
||
* @license
|
||
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
* Code distributed by Google as part of the polymer project is also
|
||
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
background: white;
|
||
color: rgba(0, 0, 0, 0.87);
|
||
}
|
||
|
||
#shadow {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
bottom: 0;
|
||
right: 0;
|
||
z-index: -1;
|
||
}
|
||
|
||
#container {
|
||
overflow: hidden;
|
||
}
|
||
|
||
#main {
|
||
height: auto;
|
||
-webkit-order: 1;
|
||
-ms-flex-order: 1;
|
||
order: 1;
|
||
padding: 24px;
|
||
overflow: auto;
|
||
}
|
||
|
||
h1 {
|
||
margin: 0;
|
||
}
|
||
|
||
#actions {
|
||
-webkit-order: 2;
|
||
-ms-flex-order: 2;
|
||
order: 2;
|
||
padding: 4px 16px 20px;
|
||
}
|
||
|
||
polyfill-next-selector { content: ':host > *'; }
|
||
::content > * {
|
||
font: inherit;
|
||
}
|
||
</style>
|
||
|
||
<div id="shadow">
|
||
<paper-shadow z="3" hasposition=""></paper-shadow>
|
||
</div>
|
||
|
||
<core-overlay id="overlay" opened="{{opened}}" autoclosedisabled?="{{autoCloseDisabled}}" backdrop?="{{backdrop}}" layered?="{{layered}}" target="{{}}" sizingtarget="{{$.container}}" closeselector="{{closeSelector}}" transition="{{transition}}" margin="20"></core-overlay>
|
||
|
||
<div id="container" layout="" vertical="">
|
||
|
||
<div id="actions" layout="" horizontal="">
|
||
<content select="[dismissive]"></content>
|
||
<div flex="" auto=""></div>
|
||
<content select="[affirmative]"></content>
|
||
</div>
|
||
|
||
<div id="main" flex="" auto="">
|
||
<h1>{{heading}}</h1>
|
||
<content></content>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
|
||
Polymer('paper-dialog', {
|
||
|
||
/**
|
||
* Set opened to true to show the dialog and to false to hide it.
|
||
* A dialog may be made intially opened by setting its opened attribute.
|
||
|
||
* @attribute opened
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
opened: false,
|
||
|
||
/**
|
||
* If true, the dialog has a backdrop darkening the rest of the screen.
|
||
* The backdrop element is attached to the document body and may be styled
|
||
* with the class `core-overlay-backdrop`. When opened the `core-opened`
|
||
* class is applied.
|
||
*
|
||
* @attribute backdrop
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
backdrop: false,
|
||
|
||
/**
|
||
* If true, the dialog is guaranteed to display above page content.
|
||
*
|
||
* @attribute layered
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
layered: false,
|
||
|
||
/**
|
||
* By default a dialog will close automatically if the user
|
||
* taps outside it or presses the escape key. Disable this
|
||
* behavior by setting the `autoCloseDisabled` property to true.
|
||
* @attribute autoCloseDisabled
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
autoCloseDisabled: false,
|
||
|
||
/**
|
||
* This property specifies a selector matching elements that should
|
||
* close the dialog on tap.
|
||
*
|
||
* @attribute closeSelector
|
||
* @type string
|
||
* @default ""
|
||
*/
|
||
closeSelector: '[dismissive],[affirmative]',
|
||
|
||
/**
|
||
* @attribute heading
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
heading: '',
|
||
|
||
/**
|
||
* Set this property to the id of a `core-transition` element to specify
|
||
* the transition to use when opening/closing this dialog.
|
||
*
|
||
* @attribute transition
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
transition: '',
|
||
|
||
/**
|
||
* Toggle the dialog's opened state.
|
||
* @method toggle
|
||
*/
|
||
toggle: function() {
|
||
this.$.overlay.toggle();
|
||
},
|
||
|
||
headingChanged: function() {
|
||
this.setAttribute('aria-label', this.heading);
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
|
||
</polymer-element>
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="paper-dialog-transition" extends="core-transition-css" assetpath="polymer/bower_components/paper-dialog/">
|
||
|
||
<template>
|
||
<style no-shim="">/* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */
|
||
|
||
:host(.paper-dialog-transition) {
|
||
outline: none;
|
||
opacity: 0;
|
||
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
-webkit-transition: -webkit-transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
:host(.paper-dialog-transition.core-opened) {
|
||
opacity: 1;
|
||
transform: none;
|
||
-webkit-transform: none;
|
||
}
|
||
|
||
:host(.paper-dialog-transition-bottom) {
|
||
transform: scale(0.9) translateY(200%);
|
||
-webkit-transform: scale(0.9) translateY(200%);
|
||
}
|
||
|
||
:host(.paper-dialog-transition-center.core-opened) {
|
||
animation: paper-dialog-transition-center-keyframes 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
-webkit-animation: paper-dialog-transition-center-keyframes 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
@keyframes paper-dialog-transition-center-keyframes {
|
||
0% {
|
||
transform: scale(0.5) translateY(0);
|
||
-webkit-transform: scale(0.5) translateY(0);
|
||
}
|
||
90% {
|
||
transform: scale(1) translateY(-10px);
|
||
-webkit-transform: scale(1) translateY(-10px);
|
||
}
|
||
100% {
|
||
transform: scale(1) translateY(0);
|
||
-webkit-transform: scale(1) translateY(0);
|
||
}
|
||
}
|
||
|
||
@-webkit-keyframes paper-dialog-transition-center-keyframes {
|
||
0% {
|
||
transform: scale(0.5) translateY(0);
|
||
-webkit-transform: scale(0.5) translateY(0);
|
||
}
|
||
90% {
|
||
transform: scale(1) translateY(-10px);
|
||
-webkit-transform: scale(1) translateY(-10px);
|
||
}
|
||
100% {
|
||
transform: scale(1) translateY(0);
|
||
-webkit-transform: scale(1) translateY(0);
|
||
}
|
||
}
|
||
</style>
|
||
</template>
|
||
|
||
<script>
|
||
Polymer('paper-dialog-transition',{
|
||
baseClass: 'paper-dialog-transition'
|
||
});
|
||
</script>
|
||
|
||
</polymer-element>
|
||
|
||
<paper-dialog-transition id="paper-dialog-transition-bottom" transitiontype="bottom"></paper-dialog-transition>
|
||
<paper-dialog-transition id="paper-dialog-transition-center" transitiontype="center"></paper-dialog-transition>
|
||
|
||
|
||
|
||
|
||
|
||
<polymer-element name="events-list" attributes="api cbEventClicked" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
display: block;
|
||
}
|
||
|
||
.eventContainer {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
</style>
|
||
|
||
<template if="{{cbEventClicked}}">
|
||
<style>
|
||
a {
|
||
text-decoration: underline;
|
||
cursor: pointer;
|
||
}
|
||
</style>
|
||
</template>
|
||
|
||
<div>
|
||
<template repeat="{{event in events}}">
|
||
<div class="eventContainer">
|
||
<a on-click="{{handleClick}}">{{event.event}}</a>
|
||
({{event.listener_count}} listeners)
|
||
</div>
|
||
</template>
|
||
|
||
</div>
|
||
</template>
|
||
<script>
|
||
Polymer('events-list',{
|
||
cbEventClicked: null,
|
||
events: [],
|
||
|
||
domReady: function() {
|
||
this.events = this.api.events
|
||
|
||
this.api.addEventListener('events-updated', this.eventsUpdated.bind(this))
|
||
},
|
||
|
||
eventsUpdated: function() {
|
||
this.events = this.api.events;
|
||
},
|
||
|
||
handleClick: function(ev) {
|
||
if(this.cbEventClicked) {
|
||
this.cbEventClicked(ev.path[0].innerHTML);
|
||
}
|
||
},
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="event-fire-dialog" attributes="api" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
paper-input:first-child {
|
||
padding-top: 0;
|
||
}
|
||
|
||
.eventContainer {
|
||
margin-left: 30px;
|
||
}
|
||
|
||
@media all and (max-width: 620px) {
|
||
.eventContainer {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
</style>
|
||
|
||
<paper-dialog id="dialog" heading="Fire Event" transition="paper-dialog-transition-bottom" backdrop="true">
|
||
<div layout="" horizontal="">
|
||
<div>
|
||
<paper-input id="inputType" label="Event Type" floatinglabel="true" autofocus required></paper-input>
|
||
<paper-input id="inputData" label="Event Data (JSON, optional)" floatinglabel="true" multiline=""></paper-input>
|
||
</div>
|
||
<div class="eventContainer">
|
||
<b>Available events:</b>
|
||
<events-list api="{{api}}" cbeventclicked="{{eventSelected}}">
|
||
</events-list></div>
|
||
</div>
|
||
<paper-button dismissive="">Cancel</paper-button>
|
||
<paper-button affirmative="" on-click="{{clickFireEvent}}">Fire Event</paper-button>
|
||
</paper-dialog>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('event-fire-dialog',{
|
||
ready: function() {
|
||
// to ensure callback methods work..
|
||
this.eventSelected = this.eventSelected.bind(this)
|
||
},
|
||
|
||
show: function(eventType, eventData) {
|
||
this.setEventType(eventType);
|
||
this.setEventData(eventData);
|
||
|
||
this.$.dialog.toggle();
|
||
},
|
||
|
||
setEventType: function(eventType) {
|
||
this.$.inputType.value = eventType;
|
||
},
|
||
|
||
setEventData: function(eventData) {
|
||
this.$.inputData.value = eventData;
|
||
},
|
||
|
||
eventSelected: function(eventType) {
|
||
this.setEventType(eventType);
|
||
},
|
||
|
||
clickFireEvent: function() {
|
||
this.api.fire_event(
|
||
this.$.inputType.value,
|
||
this.$.inputData.value
|
||
)
|
||
}
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
|
||
-->
|
||
|
||
<!--
|
||
Use to create nested menus inside of `core-menu` elements.
|
||
|
||
<core-menu selected="0">
|
||
|
||
<core-submenu icon="settings" label="Topics">
|
||
<core-item label="Topic 1"></core-item>
|
||
<core-item label="Topic 2"></core-item>
|
||
</core-submenu>
|
||
|
||
<core-submenu icon="settings" label="Favorites">
|
||
<core-item label="Favorite 1"></core-item>
|
||
<core-item label="Favorite 2"></core-item>
|
||
<core-item label="Favorite 3"></core-item>
|
||
</core-submenu>
|
||
|
||
</core-menu>
|
||
|
||
There is a margin set on the submenu to indent the items.
|
||
You can override the margin by doing:
|
||
|
||
core-submenu::shadow #submenu {
|
||
margin-left: 20px;
|
||
}
|
||
|
||
To style the item for the submenu, do something like this:
|
||
|
||
core-submenu::shadow > #submenuItem {
|
||
color: blue;
|
||
}
|
||
|
||
To style all the `core-item`s in the light DOM:
|
||
|
||
polyfill-next-selector { content: 'core-submenu > #submenu > core-item'; }
|
||
core-submenu > core-item {
|
||
color: red;
|
||
}
|
||
|
||
The above will style `Topic1` and `Topic2` to have font color red.
|
||
|
||
<core-submenu icon="settings" label="Topics">
|
||
<core-item label="Topic1"></core-item>
|
||
<core-item label="Topic2"></core-item>
|
||
</core-submenu>
|
||
|
||
@group Polymer Core Elements
|
||
@element core-submenu
|
||
@extends core-item
|
||
-->
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`core-item` is a simple line-item object: a label and/or an icon that can also
|
||
act as a link.
|
||
|
||
Example:
|
||
|
||
<core-item icon="settings" label="Settings"></core-item>
|
||
|
||
To use as a link, put <a> element in the item.
|
||
|
||
Example:
|
||
|
||
<core-item icon="settings" label="Settings">
|
||
<a href="#settings" target="_self"></a>
|
||
</core-item>
|
||
|
||
@group Polymer Core Elements
|
||
@element core-item
|
||
@homepage github.io
|
||
-->
|
||
|
||
|
||
|
||
<polymer-element name="core-item" attributes="label icon src" horizontal="" center="" layout="" assetpath="polymer/bower_components/core-item/">
|
||
<template>
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
:host {
|
||
display: block;
|
||
position: relative;
|
||
min-height: 40px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
:host(.font-scalable) {
|
||
min-height: 2.5em;
|
||
}
|
||
|
||
:host(.core-selected) {
|
||
font-weight: bold;
|
||
}
|
||
|
||
#icon {
|
||
margin: 0 16px 0 4px;
|
||
}
|
||
|
||
:host(.font-scalable) #icon {
|
||
margin: 0 1em 0 0.25em;
|
||
height: 1.5em;
|
||
width: 1.5em;
|
||
}
|
||
|
||
polyfill-next-selector { content: ':host > a'; }
|
||
::content > a {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
/* IE10 styling to ensure link is clickable. Cannot be completely
|
||
transparent or minifiers change it to `transparent` which does not work. */
|
||
background-color: rgba(0, 0, 0, 0.000001);
|
||
}
|
||
</style>
|
||
<template if="{{icon || src}}">
|
||
<core-icon src="{{src}}" id="icon" icon="{{icon}}" hidden?="{{!src && !icon}}"></core-icon>
|
||
</template>
|
||
<div id="label">{{label}}</div>
|
||
<content></content>
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('core-item', {
|
||
|
||
/**
|
||
* The URL of an image for the icon.
|
||
*
|
||
* @attribute src
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
|
||
/**
|
||
* Specifies the icon from the Polymer icon set.
|
||
*
|
||
* @attribute icon
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
|
||
/**
|
||
* Specifies the label for the menu item.
|
||
*
|
||
* @attribute label
|
||
* @type string
|
||
* @default ''
|
||
*/
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<!--
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
-->
|
||
|
||
<!--
|
||
`core-collapse` creates a collapsible block of content. By default, the content
|
||
will be collapsed. Use `opened` to show/hide the content.
|
||
|
||
<button on-click="{{toggle}}">toggle collapse</button>
|
||
|
||
<core-collapse id="collapse">
|
||
...
|
||
</core-collapse>
|
||
|
||
...
|
||
|
||
toggle: function() {
|
||
this.$.collapse.toggle();
|
||
}
|
||
|
||
@group Polymer Core Elements
|
||
@element core-collapse
|
||
-->
|
||
|
||
|
||
|
||
<style shim-shadowdom="">/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||
*/
|
||
|
||
html /deep/ core-collapse {
|
||
display: block;
|
||
}
|
||
|
||
html /deep/ .core-collapse-closed {
|
||
display: none;
|
||
}
|
||
</style>
|
||
|
||
<polymer-element name="core-collapse" attributes="target horizontal opened duration fixedSize" assetpath="polymer/bower_components/core-collapse/">
|
||
<template>
|
||
|
||
<content></content>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('core-collapse', {
|
||
|
||
/**
|
||
* Fired when the `core-collapse`'s `opened` property changes.
|
||
*
|
||
* @event core-collapse-open
|
||
*/
|
||
|
||
/**
|
||
* Fired when the target element has been resized as a result of the opened
|
||
* state changing.
|
||
*
|
||
* @event core-resize
|
||
*/
|
||
|
||
/**
|
||
* The target element.
|
||
*
|
||
* @attribute target
|
||
* @type object
|
||
* @default null
|
||
*/
|
||
target: null,
|
||
|
||
/**
|
||
* If true, the orientation is horizontal; otherwise is vertical.
|
||
*
|
||
* @attribute horizontal
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
horizontal: false,
|
||
|
||
/**
|
||
* Set opened to true to show the collapse element and to false to hide it.
|
||
*
|
||
* @attribute opened
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
opened: false,
|
||
|
||
/**
|
||
* Collapsing/expanding animation duration in second.
|
||
*
|
||
* @attribute duration
|
||
* @type number
|
||
* @default 0.33
|
||
*/
|
||
duration: 0.33,
|
||
|
||
/**
|
||
* If true, the size of the target element is fixed and is set
|
||
* on the element. Otherwise it will try to
|
||
* use auto to determine the natural size to use
|
||
* for collapsing/expanding.
|
||
*
|
||
* @attribute fixedSize
|
||
* @type boolean
|
||
* @default false
|
||
*/
|
||
fixedSize: false,
|
||
|
||
created: function() {
|
||
this.transitionEndListener = this.transitionEnd.bind(this);
|
||
},
|
||
|
||
ready: function() {
|
||
this.target = this.target || this;
|
||
},
|
||
|
||
domReady: function() {
|
||
this.async(function() {
|
||
this.afterInitialUpdate = true;
|
||
});
|
||
},
|
||
|
||
detached: function() {
|
||
if (this.target) {
|
||
this.removeListeners(this.target);
|
||
}
|
||
},
|
||
|
||
targetChanged: function(old) {
|
||
if (old) {
|
||
this.removeListeners(old);
|
||
}
|
||
if (!this.target) {
|
||
return;
|
||
}
|
||
this.isTargetReady = !!this.target;
|
||
this.classList.toggle('core-collapse-closed', this.target !== this);
|
||
this.target.style.overflow = 'hidden';
|
||
this.horizontalChanged();
|
||
this.addListeners(this.target);
|
||
// set core-collapse-closed class initially to hide the target
|
||
this.toggleClosedClass(true);
|
||
this.update();
|
||
},
|
||
|
||
addListeners: function(node) {
|
||
node.addEventListener('transitionend', this.transitionEndListener);
|
||
},
|
||
|
||
removeListeners: function(node) {
|
||
node.removeEventListener('transitionend', this.transitionEndListener);
|
||
},
|
||
|
||
horizontalChanged: function() {
|
||
this.dimension = this.horizontal ? 'width' : 'height';
|
||
},
|
||
|
||
openedChanged: function() {
|
||
this.update();
|
||
this.fire('core-collapse-open', this.opened);
|
||
},
|
||
|
||
/**
|
||
* Toggle the opened state.
|
||
*
|
||
* @method toggle
|
||
*/
|
||
toggle: function() {
|
||
this.opened = !this.opened;
|
||
},
|
||
|
||
setTransitionDuration: function(duration) {
|
||
var s = this.target.style;
|
||
s.transition = duration ? (this.dimension + ' ' + duration + 's') : null;
|
||
if (duration === 0) {
|
||
this.async('transitionEnd');
|
||
}
|
||
},
|
||
|
||
transitionEnd: function() {
|
||
if (this.opened && !this.fixedSize) {
|
||
this.updateSize('auto', null);
|
||
}
|
||
this.setTransitionDuration(null);
|
||
this.toggleClosedClass(!this.opened);
|
||
this.asyncFire('core-resize', null, this.target);
|
||
},
|
||
|
||
toggleClosedClass: function(closed) {
|
||
this.hasClosedClass = closed;
|
||
this.target.classList.toggle('core-collapse-closed', closed);
|
||
},
|
||
|
||
updateSize: function(size, duration, forceEnd) {
|
||
this.setTransitionDuration(duration);
|
||
this.calcSize();
|
||
var s = this.target.style;
|
||
var nochange = s[this.dimension] === size;
|
||
s[this.dimension] = size;
|
||
// transitonEnd will not be called if the size has not changed
|
||
if (forceEnd && nochange) {
|
||
this.transitionEnd();
|
||
}
|
||
},
|
||
|
||
update: function() {
|
||
if (!this.target) {
|
||
return;
|
||
}
|
||
if (!this.isTargetReady) {
|
||
this.targetChanged();
|
||
}
|
||
this.horizontalChanged();
|
||
this[this.opened ? 'show' : 'hide']();
|
||
},
|
||
|
||
calcSize: function() {
|
||
return this.target.getBoundingClientRect()[this.dimension] + 'px';
|
||
},
|
||
|
||
getComputedSize: function() {
|
||
return getComputedStyle(this.target)[this.dimension];
|
||
},
|
||
|
||
show: function() {
|
||
this.toggleClosedClass(false);
|
||
// for initial update, skip the expanding animation to optimize
|
||
// performance e.g. skip calcSize
|
||
if (!this.afterInitialUpdate) {
|
||
this.transitionEnd();
|
||
return;
|
||
}
|
||
if (!this.fixedSize) {
|
||
this.updateSize('auto', null);
|
||
var s = this.calcSize();
|
||
if (s == '0px') {
|
||
this.transitionEnd();
|
||
return;
|
||
}
|
||
this.updateSize(0, null);
|
||
}
|
||
this.async(function() {
|
||
this.updateSize(this.size || s, this.duration, true);
|
||
});
|
||
},
|
||
|
||
hide: function() {
|
||
// don't need to do anything if it's already hidden
|
||
if (this.hasClosedClass && !this.fixedSize) {
|
||
return;
|
||
}
|
||
if (this.fixedSize) {
|
||
// save the size before hiding it
|
||
this.size = this.getComputedSize();
|
||
} else {
|
||
this.updateSize(this.calcSize(), null);
|
||
}
|
||
this.async(function() {
|
||
this.updateSize(0, this.duration);
|
||
});
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="core-submenu" attributes="selected selectedItem label icon src valueattr" assetpath="polymer/bower_components/core-menu/">
|
||
<template>
|
||
|
||
<style>/*
|
||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
|
||
The complete set of authors may be found at http://polymer.github.io/AUTHORS
|
||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
|
||
Code distributed by Google as part of the polymer project is also
|
||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
|
||
*/
|
||
|
||
:host {
|
||
display: block;
|
||
height: auto;
|
||
}
|
||
|
||
:host(.core-selected, [active]) {
|
||
font-weight: initial;
|
||
}
|
||
|
||
core-item {
|
||
cursor: default;
|
||
}
|
||
|
||
::content > core-item {
|
||
cursor: default;
|
||
}
|
||
|
||
:host(.font-scalable) > core-item {
|
||
min-height: 2.5em;
|
||
}
|
||
|
||
:host(.font-scalable) > core-item::shadow core-icon {
|
||
margin: 0 1em 0 0.25em;
|
||
height: 1.5em;
|
||
width: 1.5em;
|
||
}
|
||
|
||
#submenu {
|
||
margin: 0 0 0 44px;
|
||
}
|
||
|
||
:host(.font-scalable) > #submenu {
|
||
margin: 0 0 0 2.75em;
|
||
}
|
||
</style>
|
||
|
||
<core-item id="submenuItem" src="{{src}}" label="{{label}}" icon="{{icon}}" class="{{ {'core-selected' : active} | tokenList}}" on-tap="{{activate}}">
|
||
<content select=".item-content"></content>
|
||
</core-item>
|
||
|
||
<core-menu id="submenu" selected="{{selected}}" selecteditem="{{selectedItem}}" valueattr="{{valueattr}}">
|
||
<content></content>
|
||
</core-menu>
|
||
|
||
<core-collapse target="{{$.submenu}}" opened="{{opened}}"></core-collapse>
|
||
|
||
</template>
|
||
<script>
|
||
|
||
Polymer('core-submenu', {
|
||
|
||
publish: {
|
||
active: {value: false, reflect: true}
|
||
},
|
||
|
||
opened: false,
|
||
|
||
get items() {
|
||
return this.$.submenu.items;
|
||
},
|
||
|
||
hasItems: function() {
|
||
return !!this.items.length;
|
||
},
|
||
|
||
unselectAllItems: function() {
|
||
this.$.submenu.selected = null;
|
||
this.$.submenu.clearSelection();
|
||
},
|
||
|
||
activeChanged: function() {
|
||
if (this.hasItems()) {
|
||
this.opened = this.active;
|
||
}
|
||
if (!this.active) {
|
||
this.unselectAllItems();
|
||
}
|
||
},
|
||
|
||
toggle: function() {
|
||
this.opened = !this.opened;
|
||
},
|
||
|
||
activate: function() {
|
||
if (this.hasItems() && this.active) {
|
||
this.toggle();
|
||
this.unselectAllItems();
|
||
}
|
||
}
|
||
|
||
});
|
||
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
|
||
|
||
|
||
<polymer-element name="services-list" attributes="api cbServiceClicked" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
display: block;
|
||
}
|
||
|
||
core-menu {
|
||
margin-top: 0;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
a {
|
||
display: block;
|
||
}
|
||
</style>
|
||
|
||
<template if="{{cbServiceClicked}}">
|
||
<style>
|
||
a, core-submenu {
|
||
text-decoration: underline;
|
||
cursor: pointer;
|
||
}
|
||
</style>
|
||
</template>
|
||
|
||
<div>
|
||
<core-menu selected="0">
|
||
|
||
<template repeat="{{serv in services}}">
|
||
<core-submenu icon="{{serv.domain | getIcon}}" label="{{serv.domain}}">
|
||
<template repeat="{{service in serv.services}}">
|
||
<a on-click="{{serviceClicked}}" data-domain="{{serv.domain}}">{{service}}</a>
|
||
</template>
|
||
</core-submenu>
|
||
</template>
|
||
|
||
</core-menu>
|
||
|
||
</div>
|
||
</template>
|
||
<script>
|
||
Polymer('services-list',{
|
||
services: [],
|
||
cbServiceClicked: null,
|
||
|
||
domReady: function() {
|
||
this.services = this.api.services
|
||
|
||
this.api.addEventListener('services-updated', this.servicesUpdated.bind(this))
|
||
},
|
||
|
||
getIcon: function(domain) {
|
||
return (new DomainIcon).icon(domain);
|
||
},
|
||
|
||
servicesUpdated: function() {
|
||
this.services = this.api.services;
|
||
},
|
||
|
||
serviceClicked: function(ev) {
|
||
if(this.cbServiceClicked) {
|
||
var target = ev.path[0];
|
||
var domain = target.getAttributeNode("data-domain").value;
|
||
var service = target.innerHTML;
|
||
|
||
this.cbServiceClicked(domain, service);
|
||
}
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="service-call-dialog" attributes="api" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
paper-input:first-child {
|
||
padding-top: 0;
|
||
}
|
||
|
||
.serviceContainer {
|
||
margin-left: 30px;
|
||
}
|
||
|
||
@media all and (max-width: 620px) {
|
||
.serviceContainer {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
</style>
|
||
|
||
<paper-dialog id="dialog" heading="Call Service" transition="paper-dialog-transition-bottom" backdrop="true">
|
||
<div layout="" horizontal="">
|
||
<div>
|
||
<paper-input id="inputDomain" label="Domain" floatinglabel="true" autofocus required></paper-input>
|
||
<paper-input id="inputService" label="Service" floatinglabel="true" required></paper-input>
|
||
<paper-input id="inputData" label="Service Data (JSON, optional)" floatinglabel="true" multiline=""></paper-input>
|
||
</div>
|
||
<div class="serviceContainer">
|
||
<b>Available services:</b>
|
||
<services-list api="{{api}}" cbserviceclicked="{{serviceSelected}}">
|
||
</services-list></div>
|
||
</div>
|
||
<paper-button dismissive="">Cancel</paper-button>
|
||
<paper-button affirmative="" on-click="{{clickCallService}}">Call Service</paper-button>
|
||
</paper-dialog>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('service-call-dialog',{
|
||
ready: function() {
|
||
// to ensure callback methods work..
|
||
this.serviceSelected = this.serviceSelected.bind(this)
|
||
},
|
||
|
||
show: function(domain, service, serviceData) {
|
||
this.setService(domain, service);
|
||
this.$.inputData.value = serviceData;
|
||
this.$.dialog.toggle();
|
||
},
|
||
|
||
setService: function(domain, service) {
|
||
this.$.inputDomain.value = domain;
|
||
this.$.inputService.value = service;
|
||
},
|
||
|
||
serviceSelected: function(domain, service) {
|
||
this.setService(domain, service);
|
||
},
|
||
|
||
clickCallService: function() {
|
||
this.api.call_service(
|
||
this.$.inputDomain.value,
|
||
this.$.inputService.value,
|
||
this.$.inputData.value
|
||
)
|
||
}
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<polymer-element name="entity-list" attributes="api cbEntityClicked" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
:host {
|
||
display: block;
|
||
}
|
||
|
||
.entityContainer {
|
||
font-size: 1rem;
|
||
}
|
||
</style>
|
||
|
||
<template if="{{cbEntityClicked}}">
|
||
<style>
|
||
a {
|
||
text-decoration: underline;
|
||
cursor: pointer;
|
||
}
|
||
</style>
|
||
</template>
|
||
|
||
<div>
|
||
<template repeat="{{state in states}}">
|
||
<div class="eventContainer">
|
||
<a on-click="{{handleClick}}">{{state.entity_id}}</a>
|
||
</div>
|
||
</template>
|
||
|
||
</div>
|
||
</template>
|
||
<script>
|
||
Polymer('entity-list',{
|
||
cbEventClicked: null,
|
||
states: [],
|
||
|
||
domReady: function() {
|
||
this.api.addEventListener('states-updated', this.statesUpdated.bind(this))
|
||
this.statesUpdated()
|
||
},
|
||
|
||
statesUpdated: function() {
|
||
this.states = this.api.states;
|
||
},
|
||
|
||
handleClick: function(ev) {
|
||
if(this.cbEntityClicked) {
|
||
this.cbEntityClicked(ev.path[0].innerHTML);
|
||
}
|
||
},
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="state-set-dialog" attributes="api" assetpath="polymer/">
|
||
<template>
|
||
<style>
|
||
paper-input:first-child {
|
||
padding-top: 0;
|
||
}
|
||
|
||
.stateContainer {
|
||
margin-left: 30px;
|
||
}
|
||
|
||
@media all and (max-width: 620px) {
|
||
.stateContainer {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
</style>
|
||
|
||
<paper-dialog id="dialog" heading="Set State" transition="paper-dialog-transition-center" backdrop="true">
|
||
<div layout="" horizontal="">
|
||
<div>
|
||
<paper-input id="inputEntityID" label="Entity ID" floatinglabel="true" autofocus required></paper-input>
|
||
<paper-input id="inputState" label="State" floatinglabel="true" required></paper-input>
|
||
<paper-input id="inputData" label="State attributes (JSON, optional)" floatinglabel="true" multiline=""></paper-input>
|
||
</div>
|
||
<div class="stateContainer">
|
||
<b>Current entities:</b>
|
||
<entity-list api="{{api}}" cbentityclicked="{{entitySelected}}"></entity-list>
|
||
</div>
|
||
</div>
|
||
<paper-button dismissive="">Cancel</paper-button>
|
||
<paper-button affirmative="" on-click="{{clickSetState}}">Set State</paper-button>
|
||
</paper-dialog>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('state-set-dialog',{
|
||
ready: function() {
|
||
// to ensure callback methods work..
|
||
this.entitySelected = this.entitySelected.bind(this)
|
||
},
|
||
|
||
show: function(entityId, state, stateData) {
|
||
this.setEntityId(entityId);
|
||
this.setState(state);
|
||
this.setStateData(stateData);
|
||
|
||
this.$.dialog.toggle();
|
||
},
|
||
|
||
setEntityId: function(entityId) {
|
||
this.$.inputEntityID.value = entityId;
|
||
},
|
||
|
||
setState: function(state) {
|
||
this.$.inputState.value = state;
|
||
},
|
||
|
||
setStateData: function(stateData) {
|
||
var value = stateData ? JSON.stringify(stateData, null, ' ') : "";
|
||
|
||
this.$.inputData.value = value;
|
||
},
|
||
|
||
entitySelected: function(entityId) {
|
||
this.setEntityId(entityId);
|
||
|
||
var state = this.api.getState(entityId);
|
||
this.setState(state.state);
|
||
this.setStateData(state.attributes);
|
||
},
|
||
|
||
clickSetState: function() {
|
||
this.api.set_state(
|
||
this.$.inputEntityID.value,
|
||
this.$.inputState.value,
|
||
JSON.parse(this.$.inputData.value)
|
||
);
|
||
}
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
|
||
|
||
<polymer-element name="home-assistant-api" attributes="auth" assetpath="polymer/">
|
||
<template>
|
||
<paper-toast id="toast" role="alert" text=""></paper-toast>
|
||
<event-fire-dialog id="eventDialog" api="{{api}}"></event-fire-dialog>
|
||
<service-call-dialog id="serviceDialog" api="{{api}}"></service-call-dialog>
|
||
<state-set-dialog id="stateDialog" api="{{api}}"></state-set-dialog>
|
||
</template>
|
||
<script>
|
||
|
||
State = function(json, api) {
|
||
this.api = api;
|
||
|
||
this.attributes = json.attributes;
|
||
|
||
this.entity_id = json.entity_id;
|
||
var parts = json.entity_id.split(".");
|
||
this.domain = parts[0];
|
||
this.entity = parts[1];
|
||
|
||
if(this.attributes.friendly_name) {
|
||
this.entityDisplay = this.attributes.friendly_name;
|
||
} else {
|
||
this.entityDisplay = this.entity.replace(/_/g, " ");
|
||
}
|
||
|
||
this.state = json.state;
|
||
this.last_changed = json.last_changed;
|
||
};
|
||
|
||
Object.defineProperties(State.prototype, {
|
||
"stateDisplay": {
|
||
get: function() {
|
||
return this.state.replace(/_/g, " ");
|
||
}
|
||
},
|
||
|
||
"isCustomGroup": {
|
||
get: function() {
|
||
return this.domain == "group" && !this.attributes.auto;
|
||
}
|
||
},
|
||
|
||
"canToggle": {
|
||
get: function() {
|
||
// groups that have the on/off state or if there is a turn_on service
|
||
return ((this.domain == 'group' &&
|
||
(this.state == 'on' || this.state == 'off')) ||
|
||
this.api.hasService(this.domain, 'turn_on'));
|
||
}
|
||
}
|
||
});
|
||
|
||
Polymer('home-assistant-api',{
|
||
auth: "not-set",
|
||
states: [],
|
||
services: [],
|
||
events: [],
|
||
stateUpdateTimeout: null,
|
||
|
||
computed: {
|
||
ha_headers: '{"HA-access": auth}'
|
||
},
|
||
|
||
created: function() {
|
||
this.api = this;
|
||
|
||
// so we can pass these methods safely as callbacks
|
||
this.turn_on = this.turn_on.bind(this);
|
||
this.turn_off = this.turn_off.bind(this);
|
||
},
|
||
|
||
// local methods
|
||
getState: function(entityId) {
|
||
var found = this.states.filter(function(state) {
|
||
return state.entity_id == entityId;
|
||
}, this);
|
||
|
||
return found.length > 0 ? found[0] : null;
|
||
},
|
||
|
||
hasService: function(domain, service) {
|
||
var found = this.services.filter(function(serv) {
|
||
return serv.domain == domain && serv.services.indexOf(service) !== -1;
|
||
}, this);
|
||
|
||
return found.length > 0;
|
||
},
|
||
|
||
_laterFetchStates: function() {
|
||
if(this.stateUpdateTimeout) {
|
||
clearTimeout(this.stateUpdateTimeout);
|
||
}
|
||
|
||
// update states in 60 seconds
|
||
this.stateUpdateTimeout = setTimeout(this.fetchStates.bind(this), 60000);
|
||
},
|
||
|
||
_sortStates: function(states) {
|
||
states.sort(function(one, two) {
|
||
if (one.entity_id > two.entity_id) {
|
||
return 1;
|
||
} else if (one.entity_id < two.entity_id) {
|
||
return -1;
|
||
} else {
|
||
return 0;
|
||
}
|
||
})
|
||
},
|
||
|
||
_pushNewState: function(new_state) {
|
||
var state;
|
||
var stateFound = false;
|
||
|
||
for(var i = 0; i < this.states.length; i++) {
|
||
if(this.states[i].entity_id == new_state.entity_id) {
|
||
state = this.states[i];
|
||
state.attributes = new_state.attributes;
|
||
state.last_changed = new_state.last_changed;
|
||
state.state = new_state.state;
|
||
|
||
stateFound = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(!stateFound) {
|
||
this.states.push(new State(new_state, this));
|
||
this._sortStates(this.states);
|
||
}
|
||
|
||
this.fire('states-updated')
|
||
},
|
||
|
||
// call api methods
|
||
fetchAll: function() {
|
||
this.fetchStates();
|
||
this.fetchServices();
|
||
this.fetchEvents();
|
||
},
|
||
|
||
fetchState: function(entityId) {
|
||
var successStateUpdate = function(new_state) {
|
||
this._pushNewState(new_state);
|
||
}
|
||
|
||
this.call_api("GET", "states/" + entityId, null, successStateUpdate.bind(this));
|
||
},
|
||
|
||
fetchStates: function(onSuccess, onError) {
|
||
var successStatesUpdate = function(newStates) {
|
||
this._sortStates(newStates);
|
||
|
||
this.states = newStates.map(function(json) {
|
||
return new State(json, this);
|
||
}.bind(this));
|
||
|
||
this.fire('states-updated')
|
||
|
||
this._laterFetchStates();
|
||
|
||
if(onSuccess) {
|
||
onSuccess(this.states);
|
||
}
|
||
}
|
||
|
||
this.call_api(
|
||
"GET", "states", null, successStatesUpdate.bind(this), onError);
|
||
},
|
||
|
||
fetchEvents: function(onSuccess, onError) {
|
||
var successEventsUpdated = function(events) {
|
||
this.events = this.events;
|
||
|
||
this.fire('events-updated')
|
||
|
||
if(onSuccess) {
|
||
onSuccess(events);
|
||
}
|
||
}
|
||
|
||
this.call_api(
|
||
"GET", "events", null, successEventsUpdated.bind(this), onError);
|
||
},
|
||
|
||
fetchServices: function(onSuccess, onError) {
|
||
var successServicesUpdated = function(services) {
|
||
this.services = services;
|
||
|
||
this.fire('services-updated')
|
||
|
||
if(onSuccess) {
|
||
onSuccess(this.services);
|
||
}
|
||
}
|
||
|
||
this.call_api(
|
||
"GET", "services", null, successServicesUpdated.bind(this), onError);
|
||
},
|
||
|
||
turn_on: function(entity_id) {
|
||
this.call_service("homeassistant", "turn_on", {entity_id: entity_id});
|
||
},
|
||
|
||
turn_off: function(entity_id) {
|
||
this.call_service("homeassistant", "turn_off", {entity_id: entity_id})
|
||
},
|
||
|
||
set_state: function(entity_id, state, attributes) {
|
||
var payload = {state: state}
|
||
|
||
if(attributes) {
|
||
payload.attributes = attributes;
|
||
}
|
||
|
||
var successToast = function(new_state) {
|
||
this.showToast("State of "+entity_id+" set to "+state+".");
|
||
this._pushNewState(new_state);
|
||
}
|
||
|
||
this.call_api("POST", "states/" + entity_id,
|
||
payload, successToast.bind(this));
|
||
},
|
||
|
||
call_service: function(domain, service, parameters) {
|
||
var successToast = function() {
|
||
if(service == "turn_on" && parameters.entity_id) {
|
||
this.showToast("Turned on " + parameters.entity_id + '.');
|
||
} else if(service == "turn_off") {
|
||
this.showToast("Turned off " + parameters.entity_id + '.');
|
||
} else {
|
||
this.showToast("Service "+domain+"/"+service+" called.");
|
||
}
|
||
|
||
// if we call a service on an entity_id, update the state
|
||
if(parameters && parameters.entity_id) {
|
||
var update_func;
|
||
|
||
// if entity_id is a string, update 1 state, else all.
|
||
if(typeof(parameters.entity_id === "string")) {
|
||
// if it is a group, fetch all
|
||
if(parameters.entity_id.slice(0,6) == "group.") {
|
||
update_func = this.fetchStates
|
||
} else {
|
||
update_func = function() {
|
||
this.fetchState(parameters.entity_id);
|
||
}
|
||
}
|
||
} else {
|
||
update_func = this.fetchStates
|
||
}
|
||
|
||
setTimeout(update_func.bind(this), 1000);
|
||
}
|
||
}
|
||
|
||
this.call_api("POST", "services/" + domain + "/" + service,
|
||
parameters, successToast.bind(this));
|
||
},
|
||
|
||
fire_event: function(eventType, eventData) {
|
||
eventData = eventData ? JSON.parse(eventData) : "";
|
||
|
||
var successToast = function() {
|
||
this.showToast("Event "+eventType+" fired.");
|
||
}
|
||
|
||
this.call_api("POST", "events/" + eventType,
|
||
eventData, successToast.bind(this));
|
||
},
|
||
|
||
call_api: function(method, path, parameters, onSuccess, onError) {
|
||
var req = new XMLHttpRequest();
|
||
req.open(method, "/api/" + path, true)
|
||
req.setRequestHeader("HA-access", this.auth);
|
||
|
||
req.onreadystatechange = function() {
|
||
|
||
if(req.readyState == 4) {
|
||
if(req.status > 199 && req.status < 300) {
|
||
if(onSuccess) {
|
||
onSuccess(JSON.parse(req.responseText));
|
||
}
|
||
} else {
|
||
if(onError) {
|
||
var data = req.responseText ? JSON.parse(req.responseText) : {};
|
||
onError(data);
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
}.bind(this)
|
||
|
||
if(parameters) {
|
||
req.send(JSON.stringify(parameters));
|
||
} else {
|
||
req.send();
|
||
}
|
||
},
|
||
|
||
// show dialogs
|
||
showEditStateDialog: function(entityId) {
|
||
var state = this.getState(entityId);
|
||
|
||
this.showSetStateDialog(entityId, state.state, state.attributes)
|
||
},
|
||
|
||
showSetStateDialog: function(entityId, state, stateAttributes) {
|
||
entityId = entityId || "";
|
||
state = state || "";
|
||
stateAttributes = stateAttributes || null;
|
||
|
||
this.$.stateDialog.show(entityId, state, stateAttributes);
|
||
},
|
||
|
||
showFireEventDialog: function(eventType, eventData) {
|
||
eventType = eventType || "";
|
||
eventData = eventData || "";
|
||
|
||
this.$.eventDialog.show(eventType, eventData);
|
||
},
|
||
|
||
showCallServiceDialog: function(domain, service, serviceData) {
|
||
domain = domain || "";
|
||
service = service || "";
|
||
serviceData = serviceData || "";
|
||
|
||
this.$.serviceDialog.show(domain, service, serviceData);
|
||
},
|
||
|
||
showToast: function(message) {
|
||
this.$.toast.text = message;
|
||
this.$.toast.show();
|
||
},
|
||
|
||
logOut: function() {
|
||
this.auth = "";
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|
||
</div>
|
||
|
||
<polymer-element name="splash-login" attributes="auth" assetpath="polymer/">
|
||
<template>
|
||
<style type="text/css">
|
||
|
||
:host {
|
||
font-family: 'RobotoDraft', sans-serif;
|
||
height: 100%;
|
||
overflow: auto;
|
||
}
|
||
|
||
.login paper-button {
|
||
margin-left: 242px;
|
||
}
|
||
|
||
.login .interact {
|
||
height: 110px;
|
||
}
|
||
|
||
</style>
|
||
|
||
<home-assistant-api auth="{{auth}}" id="api"></home-assistant-api>
|
||
|
||
<template if="{{state == 'no_auth'}}">
|
||
<div layout="" horizontal="" center="" fit="" class="login">
|
||
<div layout="" vertical="" center="" flex="">
|
||
<img src="/static/favicon-192x192.png">
|
||
<h1>Home Assistant</h1>
|
||
|
||
<div class="interact" layout="" vertical="">
|
||
<div id="loginform">
|
||
<paper-input id="passwordInput" label="Password" type="password" value="{{auth}}" on-keyup="{{passwordKeyup}}" autofocus>
|
||
</paper-input>
|
||
<paper-button on-click="{{validatePassword}}">Log In</paper-button>
|
||
</div>
|
||
|
||
<div id="validateMessage" hidden>Validating password...</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<template if="{{state == 'valid_auth'}}">
|
||
<home-assistant-main api="{{api}}"></home-assistant-main>
|
||
</template>
|
||
|
||
</template>
|
||
<script>
|
||
Polymer('splash-login',{
|
||
|
||
// can be no_auth, valid_auth
|
||
state: "no_auth",
|
||
auth: "",
|
||
|
||
ready: function() {
|
||
this.api = this.$.api;
|
||
},
|
||
|
||
domReady: function() {
|
||
document.getElementById('init').remove();
|
||
|
||
if(this.auth) {
|
||
this.validatePassword();
|
||
}
|
||
},
|
||
|
||
authChanged: function(oldVal, newVal) {
|
||
// log out functionality
|
||
if(newVal == "" && this.state == "valid_auth") {
|
||
this.state = "no_auth";
|
||
this.$.validateMessage.innerHTML = "Validating password...";
|
||
}
|
||
},
|
||
|
||
passwordKeyup: function(ev) {
|
||
if(ev.keyCode == 13) {
|
||
this.validatePassword();
|
||
}
|
||
},
|
||
|
||
validatePassword: function() {
|
||
this.$.passwordInput.commit();
|
||
this.$.loginform.setAttribute('hidden', null);
|
||
this.$.validateMessage.removeAttribute('hidden');
|
||
|
||
var passwordValid = function(result) {
|
||
this.$.validateMessage.innerHTML = "Loading data...";
|
||
this.api.fetchEvents();
|
||
|
||
this.api.fetchStates(function() {
|
||
this.state = "valid_auth";
|
||
}.bind(this));
|
||
}
|
||
|
||
var passwordInvalid = function(result) {
|
||
if(result && result.message) {
|
||
this.$.passwordInput.error = result.message;
|
||
} else {
|
||
this.$.passwordInput.error = "Unexpected result from API";
|
||
}
|
||
this.auth = null;
|
||
this.$.passwordInput.setAttribute('required', true);
|
||
this.$.loginform.removeAttribute('hidden');
|
||
this.$.validateMessage.setAttribute('hidden', null);
|
||
this.$.passwordInput.focus();
|
||
}
|
||
|
||
this.api.fetchServices(passwordValid.bind(this), passwordInvalid.bind(this));
|
||
}
|
||
|
||
});
|
||
</script>
|
||
</polymer-element>
|