OLD | NEW |
| (Empty) |
1 | |
2 | |
3 Polymer({ | |
4 | |
5 is: 'iron-iconset', | |
6 | |
7 properties: { | |
8 | |
9 /** | |
10 * The URL of the iconset image. | |
11 * | |
12 * @attribute src | |
13 * @type string | |
14 * @default '' | |
15 */ | |
16 src: { | |
17 type: String, | |
18 observer: '_srcChanged' | |
19 }, | |
20 | |
21 /** | |
22 * The name of the iconset. | |
23 * | |
24 * @attribute name | |
25 * @type string | |
26 * @default 'no-name' | |
27 */ | |
28 name: { | |
29 type: String, | |
30 observer: '_nameChanged' | |
31 }, | |
32 | |
33 /** | |
34 * The width of the iconset image. This must only be specified if the | |
35 * icons are arranged into separate rows inside the image. | |
36 * | |
37 * @attribute width | |
38 * @type number | |
39 * @default 0 | |
40 */ | |
41 width: { | |
42 type: Number, | |
43 value: 0 | |
44 }, | |
45 | |
46 /** | |
47 * A space separated list of names corresponding to icons in the iconset | |
48 * image file. This list must be ordered the same as the icon images | |
49 * in the image file. | |
50 * | |
51 * @attribute icons | |
52 * @type string | |
53 * @default '' | |
54 */ | |
55 icons: { | |
56 type: String | |
57 }, | |
58 | |
59 /** | |
60 * The size of an individual icon. Note that icons must be square. | |
61 * | |
62 * @attribute size | |
63 * @type number | |
64 * @default 24 | |
65 */ | |
66 size: { | |
67 type: Number, | |
68 value: 24 | |
69 }, | |
70 | |
71 /** | |
72 * The horizontal offset of the icon images in the inconset src image. | |
73 * This is typically used if the image resource contains additional images | |
74 * beside those intended for the iconset. | |
75 * | |
76 * @attribute offset-x | |
77 * @type number | |
78 * @default 0 | |
79 */ | |
80 _offsetX: { | |
81 type: Number, | |
82 value: 0 | |
83 }, | |
84 | |
85 /** | |
86 * The vertical offset of the icon images in the inconset src image. | |
87 * This is typically used if the image resource contains additional images | |
88 * beside those intended for the iconset. | |
89 * | |
90 * @attribute offset-y | |
91 * @type number | |
92 * @default 0 | |
93 */ | |
94 _offsetY: { | |
95 type: Number, | |
96 value: 0 | |
97 }, | |
98 | |
99 /** | |
100 * Array of fully-qualified names of icons in this set. | |
101 */ | |
102 iconNames: { | |
103 type: Array, | |
104 notify: true | |
105 } | |
106 | |
107 }, | |
108 | |
109 hostAttributes: { | |
110 // non-visual | |
111 style: 'display: none;' | |
112 }, | |
113 | |
114 ready: function() { | |
115 // theme data must exist at ready-time | |
116 this._themes = this._mapThemes(); | |
117 }, | |
118 | |
119 /** | |
120 * Applies an icon to the given element as a css background image. This | |
121 * method does not size the element, and it's usually necessary to set | |
122 * the element's height and width so that the background image is visible. | |
123 * | |
124 * @method applyIcon | |
125 * @param {Element} element The element to which the icon is applied. | |
126 * @param {String|Number} icon The name or index of the icon to apply. | |
127 * @param {String} theme (optional) The name or index of the icon to apply. | |
128 * @param {Number} scale (optional, defaults to 1) Icon scaling factor. | |
129 */ | |
130 applyIcon: function(element, icon, theme, scale) { | |
131 this._validateIconMap(); | |
132 var offset = this._getThemedOffset(icon, theme); | |
133 if (element && offset) { | |
134 this._addIconStyles(element, this._srcUrl, offset, scale || 1, | |
135 this.size, this.width); | |
136 } | |
137 }, | |
138 | |
139 /** | |
140 * Remove an icon from the given element by undoing the changes effected | |
141 * by `applyIcon`. | |
142 * | |
143 * @param {Element} element The element from which the icon is removed. | |
144 */ | |
145 removeIcon: function(element) { | |
146 this._removeIconStyles(element.style); | |
147 }, | |
148 | |
149 _mapThemes: function() { | |
150 var themes = Object.create(null); | |
151 Polymer.dom(this).querySelectorAll('property[theme]') | |
152 .forEach(function(property) { | |
153 var offsetX = window.parseInt( | |
154 property.getAttribute('offset-x'), 10 | |
155 ) || 0; | |
156 var offsetY = window.parseInt( | |
157 property.getAttribute('offset-y'), 10 | |
158 ) || 0; | |
159 themes[property.getAttribute('theme')] = { | |
160 offsetX: offsetX, | |
161 offsetY: offsetY | |
162 }; | |
163 }); | |
164 return themes; | |
165 }, | |
166 | |
167 _srcChanged: function(src) { | |
168 // ensure `srcUrl` is always relative to the main document | |
169 this._srcUrl = this.ownerDocument !== document | |
170 ? this.resolveUrl(src) : src; | |
171 this._prepareIconset(); | |
172 }, | |
173 | |
174 _nameChanged: function(name) { | |
175 this._prepareIconset(); | |
176 }, | |
177 | |
178 _prepareIconset: function() { | |
179 new Polymer.IronMeta({type: 'iconset', key: this.name, value: this}); | |
180 }, | |
181 | |
182 _invalidateIconMap: function() { | |
183 this._iconMapValid = false; | |
184 }, | |
185 | |
186 _validateIconMap: function() { | |
187 if (!this._iconMapValid) { | |
188 this._recomputeIconMap(); | |
189 this._iconMapValid = true; | |
190 } | |
191 }, | |
192 | |
193 _recomputeIconMap: function() { | |
194 this.iconNames = this._computeIconNames(this.icons); | |
195 this.iconMap = this._computeIconMap(this._offsetX, this._offsetY, | |
196 this.size, this.width, this.iconNames); | |
197 }, | |
198 | |
199 _computeIconNames: function(icons) { | |
200 return icons.split(/\s+/g); | |
201 }, | |
202 | |
203 _computeIconMap: function(offsetX, offsetY, size, width, iconNames) { | |
204 var iconMap = {}; | |
205 if (offsetX !== undefined && offsetY !== undefined) { | |
206 var x0 = offsetX; | |
207 iconNames.forEach(function(iconName) { | |
208 iconMap[iconName] = { | |
209 offsetX: offsetX, | |
210 offsetY: offsetY | |
211 }; | |
212 if ((offsetX + size) < width) { | |
213 offsetX += size; | |
214 } else { | |
215 offsetX = x0; | |
216 offsetY += size; | |
217 } | |
218 }, this); | |
219 } | |
220 return iconMap; | |
221 }, | |
222 | |
223 /** | |
224 * Returns an object containing `offsetX` and `offsetY` properties which | |
225 * specify the pixel location in the iconset's src file for the given | |
226 * `icon` and `theme`. It's uncommon to call this method. It is useful, | |
227 * for example, to manually position a css backgroundImage to the proper | |
228 * offset. It's more common to use the `applyIcon` method. | |
229 * | |
230 * @method getThemedOffset | |
231 * @param {String|Number} identifier The name of the icon or the index of | |
232 * the icon within in the icon image. | |
233 * @param {String} theme The name of the theme. | |
234 * @returns {Object} An object specifying the offset of the given icon | |
235 * within the icon resource file; `offsetX` is the horizontal offset and | |
236 * `offsetY` is the vertical offset. Both values are in pixel units. | |
237 */ | |
238 _getThemedOffset: function(identifier, theme) { | |
239 var iconOffset = this._getIconOffset(identifier); | |
240 var themeOffset = this._themes[theme]; | |
241 if (iconOffset && themeOffset) { | |
242 return { | |
243 offsetX: iconOffset.offsetX + themeOffset.offsetX, | |
244 offsetY: iconOffset.offsetY + themeOffset.offsetY | |
245 }; | |
246 } | |
247 return iconOffset; | |
248 }, | |
249 | |
250 _getIconOffset: function(identifier) { | |
251 // TODO(sjmiles): consider creating offsetArray (indexed by Number) | |
252 // and having iconMap map names to indices, then and index is just | |
253 // iconMap[identifier] || identifier (be careful of zero, store indices | |
254 // as 1-based) | |
255 return this.iconMap[identifier] || | |
256 this.iconMap[this.iconNames[Number(identifier)]]; | |
257 }, | |
258 | |
259 _addIconStyles: function(element, url, offset, scale, size, width) { | |
260 var style = element.style; | |
261 style.backgroundImage = 'url(' + url + ')'; | |
262 style.backgroundPosition = | |
263 (-offset.offsetX * scale + 'px') + ' ' + | |
264 (-offset.offsetY * scale + 'px'); | |
265 style.backgroundSize = (scale === 1) ? 'auto' : width * scale + 'px'; | |
266 style.width = size + 'px'; | |
267 style.height = size + 'px'; | |
268 element.setAttribute('role', 'img'); | |
269 }, | |
270 | |
271 _removeIconStyles: function(style) { | |
272 style.background = ''; | |
273 } | |
274 | |
275 }); | |
276 | |
OLD | NEW |