1 | /*
|
2 | Copyright 2013-2015 ASIAL CORPORATION
|
3 |
|
4 | Licensed under the Apache License, Version 2.0 (the "License");
|
5 | you may not use this file except in compliance with the License.
|
6 | You may obtain a copy of the License at
|
7 |
|
8 | http://www.apache.org/licenses/LICENSE-2.0
|
9 |
|
10 | Unless required by applicable law or agreed to in writing, software
|
11 | distributed under the License is distributed on an "AS IS" BASIS,
|
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 | See the License for the specific language governing permissions and
|
14 | limitations under the License.
|
15 |
|
16 | */
|
17 |
|
18 | import onsElements from '../ons/elements.js';
|
19 | import util from '../ons/util.js';
|
20 | import autoStyle from '../ons/autostyle.js';
|
21 | import BaseElement from './base/base-element.js';
|
22 | import contentReady from '../ons/content-ready.js';
|
23 |
|
24 | let autoPrefix = 'fa'; // FIXME: To be removed in v3
|
25 |
|
26 | /**
|
27 | * @element ons-icon
|
28 | * @category visual
|
29 | * @description
|
30 | * [en]
|
31 | * Displays an icon. The following icon suites are available:
|
32 | *
|
33 | * * [Font Awesome](https://fortawesome.github.io/Font-Awesome/)
|
34 | * * [Ionicons](http://ionicons.com/)
|
35 | * * [Material Design Iconic Font](http://zavoloklom.github.io/material-design-iconic-font/)
|
36 | * [/en]
|
37 | * [ja][/ja]
|
38 | * @codepen xAhvg
|
39 | * @tutorial vanilla/Reference/icon
|
40 | * @guide theming.html#cross-platform-styling-autostyling [en]Information about cross platform styling[/en][ja][/ja]
|
41 | * @guide appsize.html#removing-icon-packs [en]Removing icon packs.[/en][ja][/ja]
|
42 | * @guide faq.html#how-can-i-use-custom-icon-packs [en]Adding custom icon packs.[/en][ja][/ja]
|
43 | * @example
|
44 | * <ons-icon
|
45 | * icon="md-car"
|
46 | * size="20px"
|
47 | * style="color: red">
|
48 | * </ons-icon>
|
49 | *
|
50 | * <ons-button>
|
51 | * <ons-icon icon="md-car"></ons-icon>
|
52 | * Car
|
53 | * </ons-button>
|
54 | */
|
55 | export default class IconElement extends BaseElement {
|
56 |
|
57 | /**
|
58 | * @attribute icon
|
59 | * @type {String}
|
60 | * @description
|
61 | * [en]
|
62 | * The icon name. `"md-"` prefix for Material Icons, `"fa-"` for Font Awesome and `"ion-"` prefix for Ionicons.
|
63 | *
|
64 | * See all available icons on the element description (at the top).
|
65 | *
|
66 | * Icons can also be styled based on modifier presence. Add comma-separated icons with `"modifierName:"` prefix.
|
67 | *
|
68 | * The code `<ons-icon icon="ion-edit, material:md-edit"></ons-icon>` will display `"md-edit"` for Material Design and `"ion-edit"` as the default icon.
|
69 | *
|
70 | * `fa-` prefix is added automatically if none is provided. Check [See also](#seealso) section for more information.
|
71 | * [/en]
|
72 | * [ja][/ja]
|
73 | */
|
74 |
|
75 | /**
|
76 | * @attribute size
|
77 | * @type {String}
|
78 | * @description
|
79 | * [en]
|
80 | * The sizes of the icon. Valid values are lg, 2x, 3x, 4x, 5x, or in the size in pixels.
|
81 | * Icons can also be styled based on modifier presence. Add comma-separated icons with `"modifierName:"` prefix.
|
82 | *
|
83 | * The code:
|
84 | *
|
85 | * ```
|
86 | * <ons-icon
|
87 | * icon="ion-edit"
|
88 | * size="32px, material:24px">
|
89 | * </ons-icon>
|
90 | * ```
|
91 | *
|
92 | * will render as a `24px` icon if the `"material"` modifier is present and `32px` otherwise.
|
93 | * [/en]
|
94 | * [ja][/ja]
|
95 | */
|
96 |
|
97 | /**
|
98 | * @attribute rotate
|
99 | * @type {Number}
|
100 | * @description
|
101 | * [en]Number of degrees to rotate the icon. Valid values are 90, 180 and 270.[/en]
|
102 | * [ja]アイコンを回転して表示します。90, 180, 270から指定できます。[/ja]
|
103 | */
|
104 |
|
105 | /**
|
106 | * @attribute fixed-width
|
107 | * @type {Boolean}
|
108 | * @default false
|
109 | * @description
|
110 | * [en]When used in a list, you want the icons to have the same width so that they align vertically by defining this attribute.[/en]
|
111 | * [ja][/ja]
|
112 | */
|
113 |
|
114 | /**
|
115 | * @property fixedWidth
|
116 | * @type {Boolean}
|
117 | * @default false
|
118 | * @description
|
119 | * [en]When used in a list, you want the icons to have the same width so that they align vertically by defining this attribute.[/en]
|
120 | * [ja][/ja]
|
121 | */
|
122 |
|
123 | /**
|
124 | * @attribute spin
|
125 | * @description
|
126 | * [en]Specify whether the icon should be spinning.[/en]
|
127 | * [ja]アイコンを回転するかどうかを指定します。[/ja]
|
128 | */
|
129 |
|
130 | /**
|
131 | * @property spin
|
132 | * @type {Boolean}
|
133 | * @description
|
134 | * [en]Specify whether the icon should be spinning.[/en]
|
135 | * [ja]アイコンを回転するかどうかを指定します。[/ja]
|
136 | */
|
137 |
|
138 | constructor() {
|
139 | super();
|
140 |
|
141 | contentReady(this, () => {
|
142 | this._compile();
|
143 | });
|
144 | }
|
145 |
|
146 | static get observedAttributes() {
|
147 | return ['icon', 'size', 'modifier', 'class'];
|
148 | }
|
149 |
|
150 | attributeChangedCallback(name, last, current) {
|
151 | this._cleanClassAttribute(name === 'icon' ? last : this.getAttribute('icon'), name === 'modifier' ? last : undefined);
|
152 | this._update();
|
153 | }
|
154 |
|
155 | _compile() {
|
156 | autoStyle.prepare(this);
|
157 | this._update();
|
158 | }
|
159 |
|
160 | _update() {
|
161 | const {classList, style} = this._buildClassAndStyle(this._parseAttr('icon'), this._parseAttr('size'));
|
162 | util.extend(this.style, style);
|
163 |
|
164 | classList.forEach(className => this.classList.add(className));
|
165 | }
|
166 |
|
167 | _parseAttr(attrName, modifier = this.getAttribute('modifier') || '') {
|
168 | const attr = this.getAttribute(attrName) || attrName || '';
|
169 | const parts = attr.split(/\s*,\s*/);
|
170 | const def = parts[0];
|
171 | let md = parts[1];
|
172 | md = (md || '').split(/\s*:\s*/);
|
173 |
|
174 | return (modifier && (RegExp(`(^|\\s+)${md[0]}($|\\s+)`, 'i').test(modifier)) ? md[1] : def) || '';
|
175 | }
|
176 |
|
177 | /**
|
178 | * Remove unneeded class value.
|
179 | */
|
180 | _cleanClassAttribute(lastIcon, lastModifier) {
|
181 | const { className, prefix } = this._prefixIcon(this._parseAttr(lastIcon, lastModifier));
|
182 | const customPrefixRE = className !== prefix ? `|${prefix}$|${prefix}-` : `|${className}$` || '';
|
183 | const re = new RegExp(`^(fa$|fa-|ion-|zmdi$|zmdi-|ons-icon--${customPrefixRE})`);
|
184 |
|
185 | util.arrayFrom(this.classList)
|
186 | .filter(className => re.test(className))
|
187 | .forEach(className => this.classList.remove(className));
|
188 | }
|
189 |
|
190 | _prefixIcon(iconName) {
|
191 | const className = autoPrefix + (autoPrefix ? '-' : '') + iconName;
|
192 | return { className, prefix: className.split('-')[0] };
|
193 | }
|
194 |
|
195 | _buildClassAndStyle(iconName, size) {
|
196 | const classList = ['ons-icon'];
|
197 | const style = {};
|
198 |
|
199 | // Icon
|
200 | if (iconName.indexOf('ion-') === 0) {
|
201 | classList.push(iconName);
|
202 | classList.push('ons-icon--ion');
|
203 | } else if (iconName.indexOf('fa-') === 0) {
|
204 | classList.push(iconName);
|
205 | // default icon style to Font Awesome Solid if icon style is not specified already
|
206 | if (!(this.classList.contains('far') || this.classList.contains('fab') || this.classList.contains('fal'))) {
|
207 | classList.push('fa');
|
208 | }
|
209 | } else if (iconName.indexOf('md-') === 0) {
|
210 | classList.push('zmdi');
|
211 | classList.push('zmdi-' + iconName.split(/-(.+)?/)[1]);
|
212 | } else {
|
213 | const { className, prefix } = this._prefixIcon(iconName);
|
214 | prefix && classList.push(prefix);
|
215 | className && classList.push(className);
|
216 | }
|
217 |
|
218 | // Size
|
219 | if (size.match(/^[1-5]x|lg$/)) {
|
220 | classList.push('ons-icon--' + size);
|
221 | this.style.removeProperty('font-size');
|
222 | } else {
|
223 | style.fontSize = size;
|
224 | }
|
225 |
|
226 | return {
|
227 | classList: classList,
|
228 | style: style
|
229 | };
|
230 | }
|
231 |
|
232 | static setAutoPrefix(prefix) {
|
233 | autoPrefix = prefix ? (typeof prefix === 'string' && prefix || 'fa') : '';
|
234 | }
|
235 | }
|
236 |
|
237 | util.defineBooleanProperties(IconElement, ['fixed-width', 'spin']);
|
238 |
|
239 | onsElements.Icon = IconElement;
|
240 | customElements.define('ons-icon', IconElement);
|