OLD | NEW |
(Empty) | |
| 1 <!-- |
| 2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
| 3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
| 4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| 5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
| 6 Code distributed by Google as part of the polymer project is also |
| 7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
| 8 --> |
| 9 |
| 10 <!-- |
| 11 /** |
| 12 * @group Iron Elements |
| 13 * |
| 14 * The `iron-iconset` element allows users to define their own icon sets. |
| 15 * The `src` property specifies the url of the icon image. Multiple icons may |
| 16 * be included in this image and they may be organized into rows. |
| 17 * The `icons` property is a space separated list of names corresponding to the |
| 18 * icons. The names must be ordered as the icons are ordered in the icon image. |
| 19 * Icons are expected to be square and are the size specified by the `size` |
| 20 * property. The `width` property corresponds to the width of the icon image |
| 21 * and must be specified if icons are arranged into multiple rows in the image. |
| 22 * |
| 23 * All `iron-iconset` elements are available for use by other `iron-iconset` |
| 24 * elements via a database keyed by id. Typically, an element author that wants |
| 25 * to support a set of custom icons uses a `iron-iconset` to retrieve |
| 26 * and use another, user-defined iconset. |
| 27 * |
| 28 * Example: |
| 29 * |
| 30 * <iron-iconset id="my-icons" src="my-icons.png" width="96" size="24" |
| 31 * icons="location place starta stopb bus car train walk"> |
| 32 * </iron-iconset> |
| 33 * |
| 34 * This will automatically register the icon set "my-icons" to the iconset |
| 35 * database. To use these icons from within another element, make a |
| 36 * `iron-iconset` element and call the `byId` method to retrieve a |
| 37 * given iconset. To apply a particular icon to an element, use the |
| 38 * `applyIcon` method. For example: |
| 39 * |
| 40 * iconset.applyIcon(iconNode, 'car'); |
| 41 * |
| 42 * Themed icon sets are also supported. The `iron-iconset` can contain child |
| 43 * `property` elements that specify a theme with an offsetX and offsetY of the |
| 44 * theme within the icon resource. For example. |
| 45 * |
| 46 * <iron-iconset id="my-icons" src="my-icons.png" width="96" size="24" |
| 47 * icons="location place starta stopb bus car train walk"> |
| 48 * <property theme="special" offsetX="256" offsetY="24"></property> |
| 49 * </iron-iconset> |
| 50 * |
| 51 * Then a themed icon can be applied like this: |
| 52 * |
| 53 * iconset.applyIcon(iconNode, 'car', 'special'); |
| 54 * |
| 55 * @element iron-iconset |
| 56 */ |
| 57 --> |
| 58 <link rel="import" href="../polymer/polymer.html"> |
| 59 <link rel="import" href="../iron-meta/iron-meta.html"> |
| 60 |
| 61 <script> |
| 62 |
| 63 Polymer({ |
| 64 |
| 65 is: 'iron-iconset', |
| 66 |
| 67 properties: { |
| 68 |
| 69 /** |
| 70 * The URL of the iconset image. |
| 71 * |
| 72 * @attribute src |
| 73 * @type string |
| 74 * @default '' |
| 75 */ |
| 76 src: { |
| 77 type: String, |
| 78 observer: '_srcChanged' |
| 79 }, |
| 80 |
| 81 /** |
| 82 * The name of the iconset. |
| 83 * |
| 84 * @attribute name |
| 85 * @type string |
| 86 * @default 'no-name' |
| 87 */ |
| 88 name: { |
| 89 type: String, |
| 90 observer: '_nameChanged' |
| 91 }, |
| 92 |
| 93 /** |
| 94 * The width of the iconset image. This must only be specified if the |
| 95 * icons are arranged into separate rows inside the image. |
| 96 * |
| 97 * @attribute width |
| 98 * @type number |
| 99 * @default 0 |
| 100 */ |
| 101 width: { |
| 102 type: Number, |
| 103 value: 0 |
| 104 }, |
| 105 |
| 106 /** |
| 107 * A space separated list of names corresponding to icons in the iconset |
| 108 * image file. This list must be ordered the same as the icon images |
| 109 * in the image file. |
| 110 * |
| 111 * @attribute icons |
| 112 * @type string |
| 113 * @default '' |
| 114 */ |
| 115 icons: { |
| 116 type: String |
| 117 }, |
| 118 |
| 119 /** |
| 120 * The size of an individual icon. Note that icons must be square. |
| 121 * |
| 122 * @attribute size |
| 123 * @type number |
| 124 * @default 24 |
| 125 */ |
| 126 size: { |
| 127 type: Number, |
| 128 value: 24 |
| 129 }, |
| 130 |
| 131 /** |
| 132 * The horizontal offset of the icon images in the inconset src image. |
| 133 * This is typically used if the image resource contains additional images |
| 134 * beside those intended for the iconset. |
| 135 * |
| 136 * @attribute offset-x |
| 137 * @type number |
| 138 * @default 0 |
| 139 */ |
| 140 _offsetX: { |
| 141 type: Number, |
| 142 value: 0 |
| 143 }, |
| 144 |
| 145 /** |
| 146 * The vertical offset of the icon images in the inconset src image. |
| 147 * This is typically used if the image resource contains additional images |
| 148 * beside those intended for the iconset. |
| 149 * |
| 150 * @attribute offset-y |
| 151 * @type number |
| 152 * @default 0 |
| 153 */ |
| 154 _offsetY: { |
| 155 type: Number, |
| 156 value: 0 |
| 157 }, |
| 158 |
| 159 /** |
| 160 * Array of fully-qualified names of icons in this set. |
| 161 */ |
| 162 iconNames: { |
| 163 type: Array, |
| 164 notify: true |
| 165 } |
| 166 |
| 167 }, |
| 168 |
| 169 hostAttributes: { |
| 170 // non-visual |
| 171 style: 'display: none;' |
| 172 }, |
| 173 |
| 174 ready: function() { |
| 175 // theme data must exist at ready-time |
| 176 this._themes = this._mapThemes(); |
| 177 }, |
| 178 |
| 179 /** |
| 180 * Applies an icon to the given element as a css background image. This |
| 181 * method does not size the element, and it's usually necessary to set |
| 182 * the element's height and width so that the background image is visible. |
| 183 * |
| 184 * @method applyIcon |
| 185 * @param {Element} element The element to which the icon is applied. |
| 186 * @param {String|Number} icon The name or index of the icon to apply. |
| 187 * @param {String} theme (optional) The name or index of the icon to apply. |
| 188 * @param {Number} scale (optional, defaults to 1) Icon scaling factor. |
| 189 * @return {Element} The applied icon element. |
| 190 */ |
| 191 applyIcon: function(element, icon, theme, scale) { |
| 192 this._validateIconMap(); |
| 193 var offset = this._getThemedOffset(icon, theme); |
| 194 if (element && offset) { |
| 195 this._addIconStyles(element, this._srcUrl, offset, scale || 1, |
| 196 this.size, this.width); |
| 197 } |
| 198 }, |
| 199 |
| 200 /** |
| 201 * Remove an icon from the given element by undoing the changes effected |
| 202 * by `applyIcon`. |
| 203 * |
| 204 * @param {Element} element The element from which the icon is removed. |
| 205 */ |
| 206 removeIcon: function(element) { |
| 207 this._removeIconStyles(element.style); |
| 208 }, |
| 209 |
| 210 _mapThemes: function() { |
| 211 var themes = Object.create(null); |
| 212 Polymer.dom(this).querySelectorAll('property[theme]') |
| 213 .forEach(function(property) { |
| 214 var offsetX = window.parseInt( |
| 215 property.getAttribute('offset-x'), 10 |
| 216 ) || 0; |
| 217 var offsetY = window.parseInt( |
| 218 property.getAttribute('offset-y'), 10 |
| 219 ) || 0; |
| 220 themes[property.getAttribute('theme')] = { |
| 221 offsetX: offsetX, |
| 222 offsetY: offsetY |
| 223 }; |
| 224 }); |
| 225 return themes; |
| 226 }, |
| 227 |
| 228 _srcChanged: function(src) { |
| 229 // ensure `srcUrl` is always relative to the main document |
| 230 this._srcUrl = this.ownerDocument !== document |
| 231 ? this.resolveUrl(src) : src; |
| 232 this._prepareIconset(); |
| 233 }, |
| 234 |
| 235 _nameChanged: function(name) { |
| 236 this._prepareIconset(); |
| 237 }, |
| 238 |
| 239 _prepareIconset: function() { |
| 240 new Polymer.IronMeta({type: 'iconset', key: this.name, value: this}); |
| 241 }, |
| 242 |
| 243 _invalidateIconMap: function() { |
| 244 this._iconMapValid = false; |
| 245 }, |
| 246 |
| 247 _validateIconMap: function() { |
| 248 if (!this._iconMapValid) { |
| 249 this._recomputeIconMap(); |
| 250 this._iconMapValid = true; |
| 251 } |
| 252 }, |
| 253 |
| 254 _recomputeIconMap: function() { |
| 255 this.iconNames = this._computeIconNames(this.icons); |
| 256 this.iconMap = this._computeIconMap(this._offsetX, this._offsetY, |
| 257 this.size, this.width, this.iconNames); |
| 258 }, |
| 259 |
| 260 _computeIconNames: function(icons) { |
| 261 return icons.split(/\s+/g); |
| 262 }, |
| 263 |
| 264 _computeIconMap: function(offsetX, offsetY, size, width, iconNames) { |
| 265 var iconMap = {}; |
| 266 if (offsetX !== undefined && offsetY !== undefined) { |
| 267 var x0 = offsetX; |
| 268 iconNames.forEach(function(iconName) { |
| 269 iconMap[iconName] = { |
| 270 offsetX: offsetX, |
| 271 offsetY: offsetY |
| 272 }; |
| 273 if ((offsetX + size) < width) { |
| 274 offsetX += size; |
| 275 } else { |
| 276 offsetX = x0; |
| 277 offsetY += size; |
| 278 } |
| 279 }, this); |
| 280 } |
| 281 return iconMap; |
| 282 }, |
| 283 |
| 284 /** |
| 285 * Returns an object containing `offsetX` and `offsetY` properties which |
| 286 * specify the pixel location in the iconset's src file for the given |
| 287 * `icon` and `theme`. It's uncommon to call this method. It is useful, |
| 288 * for example, to manually position a css backgroundImage to the proper |
| 289 * offset. It's more common to use the `applyIcon` method. |
| 290 * |
| 291 * @method getThemedOffset |
| 292 * @param {String|Number} identifier The name of the icon or the index of |
| 293 * the icon within in the icon image. |
| 294 * @param {String} theme The name of the theme. |
| 295 * @returns {Object} An object specifying the offset of the given icon |
| 296 * within the icon resource file; `offsetX` is the horizontal offset and |
| 297 * `offsetY` is the vertical offset. Both values are in pixel units. |
| 298 */ |
| 299 _getThemedOffset: function(identifier, theme) { |
| 300 var iconOffset = this._getIconOffset(identifier); |
| 301 var themeOffset = this._themes[theme]; |
| 302 if (iconOffset && themeOffset) { |
| 303 return { |
| 304 offsetX: iconOffset.offsetX + themeOffset.offsetX, |
| 305 offsetY: iconOffset.offsetY + themeOffset.offsetY |
| 306 }; |
| 307 } |
| 308 return iconOffset; |
| 309 }, |
| 310 |
| 311 _getIconOffset: function(identifier) { |
| 312 // TODO(sjmiles): consider creating offsetArray (indexed by Number) |
| 313 // and having iconMap map names to indices, then and index is just |
| 314 // iconMap[identifier] || identifier (be careful of zero, store indices |
| 315 // as 1-based) |
| 316 return this.iconMap[identifier] || |
| 317 this.iconMap[this.iconNames[Number(identifier)]]; |
| 318 }, |
| 319 |
| 320 _addIconStyles: function(element, url, offset, scale, size, width) { |
| 321 var style = element.style; |
| 322 style.backgroundImage = 'url(' + url + ')'; |
| 323 style.backgroundPosition = |
| 324 (-offset.offsetX * scale + 'px') + ' ' + |
| 325 (-offset.offsetY * scale + 'px'); |
| 326 style.backgroundSize = (scale === 1) ? 'auto' : width * scale + 'px'; |
| 327 style.width = size + 'px'; |
| 328 style.height = size + 'px'; |
| 329 element.setAttribute('role', 'img'); |
| 330 }, |
| 331 |
| 332 _removeIconStyles: function(style) { |
| 333 style.background = ''; |
| 334 } |
| 335 |
| 336 }); |
| 337 |
| 338 </script> |
OLD | NEW |