1/** 2@license 3Copyright (c) 2015 The Polymer Project Authors. All rights reserved. 4This code may only be used under the BSD style license found at 5http://polymer.github.io/LICENSE.txt The complete set of authors may be found at 6http://polymer.github.io/AUTHORS.txt The complete set of contributors may be 7found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as 8part of the polymer project is also subject to an additional IP rights grant 9found at http://polymer.github.io/PATENTS.txt 10*/ 11import '/node_modules/@polymer/polymer/polymer-legacy.js'; 12 13import {IronMeta} from '/node_modules/@polymer/iron-meta/iron-meta.js'; 14import {Polymer} from '/node_modules/@polymer/polymer/lib/legacy/polymer-fn.js'; 15import {dom} from '/node_modules/@polymer/polymer/lib/legacy/polymer.dom.js'; 16/** 17 * The `iron-iconset-svg` element allows users to define their own icon sets 18 * that contain svg icons. The svg icon elements should be children of the 19 * `iron-iconset-svg` element. Multiple icons should be given distinct id's. 20 * 21 * Using svg elements to create icons has a few advantages over traditional 22 * bitmap graphics like jpg or png. Icons that use svg are vector based so 23 * they are resolution independent and should look good on any device. They 24 * are stylable via css. Icons can be themed, colorized, and even animated. 25 * 26 * Example: 27 * 28 * <iron-iconset-svg name="my-svg-icons" size="24"> 29 * <svg> 30 * <defs> 31 * <g id="shape"> 32 * <rect x="12" y="0" width="12" height="24" /> 33 * <circle cx="12" cy="12" r="12" /> 34 * </g> 35 * </defs> 36 * </svg> 37 * </iron-iconset-svg> 38 * 39 * This will automatically register the icon set "my-svg-icons" to the iconset 40 * database. To use these icons from within another element, make a 41 * `iron-iconset` element and call the `byId` method 42 * to retrieve a given iconset. To apply a particular icon inside an 43 * element use the `applyIcon` method. For example: 44 * 45 * iconset.applyIcon(iconNode, 'car'); 46 * 47 * @element iron-iconset-svg 48 * @demo demo/index.html 49 * @implements {Polymer.Iconset} 50 */ 51Polymer({ 52 is: 'iron-iconset-svg', 53 54 properties: { 55 56 /** 57 * The name of the iconset. 58 */ 59 name: {type: String, observer: '_nameChanged'}, 60 61 /** 62 * The size of an individual icon. Note that icons must be square. 63 */ 64 size: {type: Number, value: 24}, 65 66 /** 67 * Set to true to enable mirroring of icons where specified when they are 68 * stamped. Icons that should be mirrored should be decorated with a 69 * `mirror-in-rtl` attribute. 70 * 71 * NOTE: For performance reasons, direction will be resolved once per 72 * document per iconset, so moving icons in and out of RTL subtrees will 73 * not cause their mirrored state to change. 74 */ 75 rtlMirroring: {type: Boolean, value: false}, 76 77 /** 78 * Set to true to measure RTL based on the dir attribute on the body or 79 * html elements (measured on document.body or document.documentElement as 80 * available). 81 */ 82 useGlobalRtlAttribute: {type: Boolean, value: false} 83 }, 84 85 created: function() { 86 this._meta = new IronMeta({type: 'iconset', key: null, value: null}); 87 }, 88 89 attached: function() { 90 this.style.display = 'none'; 91 }, 92 93 /** 94 * Construct an array of all icon names in this iconset. 95 * 96 * @return {!Array} Array of icon names. 97 */ 98 getIconNames: function() { 99 this._icons = this._createIconMap(); 100 return Object.keys(this._icons).map(function(n) { 101 return this.name + ':' + n; 102 }, this); 103 }, 104 105 /** 106 * Applies an icon to the given element. 107 * 108 * An svg icon is prepended to the element's shadowRoot if it exists, 109 * otherwise to the element itself. 110 * 111 * If RTL mirroring is enabled, and the icon is marked to be mirrored in 112 * RTL, the element will be tested (once and only once ever for each 113 * iconset) to determine the direction of the subtree the element is in. 114 * This direction will apply to all future icon applications, although only 115 * icons marked to be mirrored will be affected. 116 * 117 * @method applyIcon 118 * @param {Element} element Element to which the icon is applied. 119 * @param {string} iconName Name of the icon to apply. 120 * @return {?Element} The svg element which renders the icon. 121 */ 122 applyIcon: function(element, iconName) { 123 // Remove old svg element 124 this.removeIcon(element); 125 // install new svg element 126 var svg = this._cloneIcon( 127 iconName, this.rtlMirroring && this._targetIsRTL(element)); 128 if (svg) { 129 // insert svg element into shadow root, if it exists 130 var pde = dom(element.root || element); 131 pde.insertBefore(svg, pde.childNodes[0]); 132 return element._svgIcon = svg; 133 } 134 return null; 135 }, 136 137 /** 138 * Remove an icon from the given element by undoing the changes effected 139 * by `applyIcon`. 140 * 141 * @param {Element} element The element from which the icon is removed. 142 */ 143 removeIcon: function(element) { 144 // Remove old svg element 145 if (element._svgIcon) { 146 dom(element.root || element).removeChild(element._svgIcon); 147 element._svgIcon = null; 148 } 149 }, 150 151 /** 152 * Measures and memoizes the direction of the element. Note that this 153 * measurement is only done once and the result is memoized for future 154 * invocations. 155 */ 156 _targetIsRTL: function(target) { 157 if (this.__targetIsRTL == null) { 158 if (this.useGlobalRtlAttribute) { 159 var globalElement = 160 (document.body && document.body.hasAttribute('dir')) ? 161 document.body : 162 document.documentElement; 163 164 this.__targetIsRTL = globalElement.getAttribute('dir') === 'rtl'; 165 } else { 166 if (target && target.nodeType !== Node.ELEMENT_NODE) { 167 target = target.host; 168 } 169 170 this.__targetIsRTL = 171 target && window.getComputedStyle(target)['direction'] === 'rtl'; 172 } 173 } 174 175 return this.__targetIsRTL; 176 }, 177 178 /** 179 * 180 * When name is changed, register iconset metadata 181 * 182 */ 183 _nameChanged: function() { 184 this._meta.value = null; 185 this._meta.key = this.name; 186 this._meta.value = this; 187 188 this.async(function() { 189 this.fire('iron-iconset-added', this, {node: window}
189); 190 }); 191 }, 192 193 /** 194 * Create a map of child SVG elements by id. 195 * 196 * @return {!Object} Map of id's to SVG elements. 197 */ 198 _createIconMap: function() { 199 // Objects chained to Object.prototype (`{}`) have members. Specifically, 200 // on FF there is a `watch` method that confuses the icon map, so we 201 // need to use a null-based object here. 202 var icons = Object.create(null); 203 dom(this).querySelectorAll('[id]').forEach(function(icon) { 204 icons[icon.id] = icon; 205 }); 206 return icons; 207 }, 208 209 /** 210 * Produce installable clone of the SVG element matching `id` in this 211 * iconset, or `undefined` if there is no matching element. 212 * 213 * @return {Element} Returns an installable clone of the SVG element 214 * matching `id`. 215 */ 216 _cloneIcon: function(id, mirrorAllowed) { 217 // create the icon map on-demand, since the iconset itself has no discrete 218 // signal to know when it's children are fully parsed 219 this._icons = this._icons || this._createIconMap(); 220 return this._prepareSvgClone(this._icons[id], this.size, mirrorAllowed); 221 }, 222 223 /** 224 * @param {Element} sourceSvg 225 * @param {number} size 226 * @param {Boolean} mirrorAllowed 227 * @return {Element} 228 */ 229 _prepareSvgClone: function(sourceSvg, size, mirrorAllowed) { 230 if (sourceSvg) { 231 var content = sourceSvg.cloneNode(true), 232 svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
233 viewBox = 234 content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size, 235 cssText = 236 'pointer-events: none; display: block; width: 100%; height: 100%;'; 237 238 if (mirrorAllowed && content.hasAttribute('mirror-in-rtl')) { 239 cssText += 240 '-webkit-transform:scale(-1,1);transform:scale(-1,1);transform-origin:center;'; 241 } 242 243 svg.setAttribute('viewBox', viewBox); 244 svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); 245 svg.setAttribute('focusable', 'false'); 246 // TODO(dfreedm): `pointer-events: none` works around 247 // https://crbug.com/370136 248 // TODO(sjmiles): inline style may not be ideal, but avoids requiring a 249 // shadow-root 250 svg.style.cssText = cssText; 251 svg.appendChild(content).removeAttribute('id'); 252 return svg; 253 } 254 return null; 255 } 256 257});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.