1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | import onsElements from '../ons/elements.js';
|
15 | import util from '../ons/util.js';
|
16 | import autoStyle from '../ons/autostyle.js';
|
17 | import ModifierUtil from '../ons/internal/modifier-util.js';
|
18 | import BaseElement from './base/base-element.js';
|
19 | import contentReady from '../ons/content-ready.js';
|
20 | import styler from '../ons/styler.js';
|
21 |
|
22 | const defaultClassName = 'speed-dial';
|
23 | const scheme = {
|
24 | '': 'speed-dial--*',
|
25 | };
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | export default class SpeedDialElement extends BaseElement {
|
56 |
|
57 | |
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 | |
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | |
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 | |
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | |
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | |
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 | |
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | |
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | constructor() {
|
128 | super();
|
129 |
|
130 | contentReady(this, () => {
|
131 | this._compile();
|
132 | });
|
133 |
|
134 | this._boundOnClick = this._onClick.bind(this);
|
135 |
|
136 | const {onConnected, onDisconnected} = util.defineListenerProperty(this, 'click');
|
137 | this._connectOnClick = onConnected;
|
138 | this._disconnectOnClick = onDisconnected;
|
139 | }
|
140 |
|
141 | _compile() {
|
142 | this.classList.add(defaultClassName);
|
143 | autoStyle.prepare(this);
|
144 | this._updateRipple();
|
145 | ModifierUtil.initModifier(this, scheme);
|
146 |
|
147 | if (this.hasAttribute('direction')) {
|
148 | this._updateDirection(this.getAttribute('direction'));
|
149 | } else {
|
150 | this._updateDirection('up');
|
151 | }
|
152 |
|
153 | this._updatePosition();
|
154 | }
|
155 |
|
156 | static get observedAttributes() {
|
157 | return ['class', 'modifier', 'ripple', 'direction', 'position', 'open'];
|
158 | }
|
159 |
|
160 | attributeChangedCallback(name, last, current) {
|
161 | switch (name) {
|
162 | case 'class':
|
163 | util.restoreClass(this, defaultClassName, scheme);
|
164 | break;
|
165 | case 'modifier':
|
166 | ModifierUtil.onModifierChanged(last, current, this, scheme);
|
167 | break;
|
168 | case 'ripple':
|
169 | contentReady(this, () => this._updateRipple());
|
170 | break;
|
171 | case 'direction':
|
172 | contentReady(this, () => this._updateDirection(current));
|
173 | break;
|
174 | case 'position':
|
175 | contentReady(this, () => this._updatePosition());
|
176 | break;
|
177 | case 'open':
|
178 | if (!this._ignoreOpenSideEffect) {
|
179 | contentReady(this, () => this._updateOpen(last));
|
180 | }
|
181 | break;
|
182 | }
|
183 | }
|
184 |
|
185 | connectedCallback() {
|
186 | this.addEventListener('click', this._boundOnClick, false);
|
187 | this._connectOnClick();
|
188 | }
|
189 |
|
190 | disconnectedCallback() {
|
191 | this.removeEventListener('click', this._boundOnClick, false);
|
192 | this._disconnectOnClick();
|
193 | }
|
194 |
|
195 | get items() {
|
196 | return util.arrayFrom(this.querySelectorAll('ons-speed-dial-item'));
|
197 | }
|
198 |
|
199 | get _fab() {
|
200 | return util.findChild(this, 'ons-fab');
|
201 | }
|
202 |
|
203 | _onClick(event) {
|
204 | setTimeout(() => {
|
205 | if (!event.defaultPrevented && !this.disabled && this.visible) {
|
206 | return this.toggleItems();
|
207 | }
|
208 | });
|
209 | }
|
210 |
|
211 | _show() {
|
212 | if (!this.inline) {
|
213 | return this.show();
|
214 | }
|
215 | return Promise.resolve();
|
216 | }
|
217 |
|
218 | _hide() {
|
219 | return new Promise(resolve => {
|
220 | if (!this.inline) {
|
221 | setImmediate(() => this.hide().then(resolve));
|
222 | } else {
|
223 | resolve();
|
224 | }
|
225 | });
|
226 | }
|
227 |
|
228 | _updateRipple() {
|
229 | if (this._fab) {
|
230 | this.hasAttribute('ripple') ? this._fab.setAttribute('ripple', '') : this._fab.removeAttribute('ripple');
|
231 | }
|
232 | }
|
233 |
|
234 | _updateDirection(direction) {
|
235 | const children = this.items;
|
236 | for (let i = 0; i < children.length; i++) {
|
237 | styler(children[i], {
|
238 | transitionDelay: 25 * i + 'ms',
|
239 | bottom: 'auto',
|
240 | right: 'auto',
|
241 | top: 'auto',
|
242 | left: 'auto'
|
243 | });
|
244 | }
|
245 | switch (direction) {
|
246 | case 'up':
|
247 | for (let i = 0; i < children.length; i++) {
|
248 | children[i].style.bottom = 72 + 56 * i + 'px';
|
249 | children[i].style.right = '8px';
|
250 | }
|
251 | break;
|
252 | case 'down':
|
253 | for (let i = 0; i < children.length; i++) {
|
254 | children[i].style.top = 72 + 56 * i + 'px';
|
255 | children[i].style.left = '8px';
|
256 | }
|
257 | break;
|
258 | case 'left':
|
259 | for (let i = 0; i < children.length; i++) {
|
260 | children[i].style.top = '8px';
|
261 | children[i].style.right = 72 + 56 * i + 'px';
|
262 | }
|
263 | break;
|
264 | case 'right':
|
265 | for (let i = 0; i < children.length; i++) {
|
266 | children[i].style.top = '8px';
|
267 | children[i].style.left = 72 + 56 * i + 'px';
|
268 | }
|
269 | break;
|
270 | default:
|
271 | util.throw('Argument must be one of up, down, left or right.');
|
272 | }
|
273 | }
|
274 |
|
275 | _updatePosition() {
|
276 | const position = this.getAttribute('position');
|
277 | this.classList.remove(
|
278 | 'fab--top__left',
|
279 | 'fab--bottom__right',
|
280 | 'fab--bottom__left',
|
281 | 'fab--top__right',
|
282 | 'fab--top__center',
|
283 | 'fab--bottom__center');
|
284 | switch (position) {
|
285 | case 'top right':
|
286 | case 'right top':
|
287 | this.classList.add('fab--top__right');
|
288 | break;
|
289 | case 'top left':
|
290 | case 'left top':
|
291 | this.classList.add('fab--top__left');
|
292 | break;
|
293 | case 'bottom right':
|
294 | case 'right bottom':
|
295 | this.classList.add('fab--bottom__right');
|
296 | break;
|
297 | case 'bottom left':
|
298 | case 'left bottom':
|
299 | this.classList.add('fab--bottom__left');
|
300 | break;
|
301 | case 'center top':
|
302 | case 'top center':
|
303 | this.classList.add('fab--top__center');
|
304 | break;
|
305 | case 'center bottom':
|
306 | case 'bottom center':
|
307 | this.classList.add('fab--bottom__center');
|
308 | break;
|
309 | default:
|
310 | break;
|
311 | }
|
312 | }
|
313 |
|
314 | _getTranslate() {
|
315 | const isBottom = (this.getAttribute('position') || '').indexOf('bottom') >= 0;
|
316 | const translate = isBottom ? `translate3d(0px, -${util.globals.fabOffset || 0}px, 0px) ` : '';
|
317 | return translate;
|
318 | }
|
319 |
|
320 | |
321 |
|
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 | show() {
|
328 | this._fab.show();
|
329 | styler(this, { transform: this._getTranslate });
|
330 | return Promise.resolve();
|
331 | }
|
332 |
|
333 | |
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 | hide() {
|
341 | return this.hideItems().then(()=> this._fab.hide());
|
342 | }
|
343 |
|
344 | |
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 | showItems() {
|
352 | const last = this.open;
|
353 | this._ignoreOpenSideEffect = true;
|
354 | this.open = true;
|
355 | this._ignoreOpenSideEffect = false;
|
356 |
|
357 | return this._updateOpen(last);
|
358 | }
|
359 |
|
360 | |
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 | hideItems() {
|
368 | const last = this.open;
|
369 | this._ignoreOpenSideEffect = true;
|
370 | this.open = false;
|
371 | this._ignoreOpenSideEffect = false;
|
372 |
|
373 | return this._updateOpen(last);
|
374 | }
|
375 |
|
376 | _updateOpen(last) {
|
377 |
|
378 | if (this.open) {
|
379 | if (this.hasAttribute('direction')) {
|
380 | this._updateDirection(this.getAttribute('direction'));
|
381 | } else {
|
382 | this._updateDirection('up');
|
383 | }
|
384 | }
|
385 |
|
386 | let totalDelay = 0;
|
387 | if (last !== this.open) {
|
388 | const children = this.items;
|
389 | for (let i = 0; i < children.length; i++) {
|
390 | const delay = 25 * (this.open ? i : children.length - i);
|
391 | totalDelay += delay;
|
392 | styler(children[i], {
|
393 | transform: `scale(${this.open ? 1 : 0})`,
|
394 | transitionDelay: delay + 'ms'
|
395 | });
|
396 | }
|
397 | totalDelay += 50;
|
398 |
|
399 | util.triggerElementEvent(this, this.open ? 'open' : 'close');
|
400 | }
|
401 |
|
402 | const deferred = util.defer();
|
403 | setTimeout(deferred.resolve, totalDelay);
|
404 | return deferred.promise;
|
405 | }
|
406 |
|
407 | |
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 | set disabled(value) {
|
415 | if (value) {
|
416 | this.hideItems();
|
417 | }
|
418 | util.arrayFrom(this.children).forEach(e => {
|
419 | util.match(e, '.fab') && util.toggleAttribute(e, 'disabled', value);
|
420 | });
|
421 |
|
422 | util.toggleAttribute(this, 'disabled', value);
|
423 | }
|
424 |
|
425 | get disabled() {
|
426 | return this.hasAttribute('disabled');
|
427 | }
|
428 |
|
429 | |
430 |
|
431 |
|
432 |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 | get inline() {
|
438 | return this.hasAttribute('inline');
|
439 | }
|
440 |
|
441 | |
442 |
|
443 |
|
444 |
|
445 |
|
446 |
|
447 |
|
448 |
|
449 | get visible() {
|
450 | return this._fab && this._fab.visible && this.style.display !== 'none';
|
451 | }
|
452 |
|
453 | |
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 | isOpen() {
|
461 | return this.open;
|
462 | }
|
463 |
|
464 | |
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 | |
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 | |
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 | toggle() {
|
488 | return this.visible ? this.hide() : this.show();
|
489 | }
|
490 |
|
491 | |
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 |
|
498 | toggleItems() {
|
499 | return this.open ? this.hideItems() : this.showItems();
|
500 | }
|
501 |
|
502 | static get events() {
|
503 | return ['open', 'close'];
|
504 | }
|
505 | }
|
506 |
|
507 | util.defineBooleanProperties(SpeedDialElement, ['open', 'ripple']);
|
508 |
|
509 | onsElements.SpeedDial = SpeedDialElement;
|
510 | customElements.define('ons-speed-dial', SpeedDialElement);
|