551 lines
15 KiB
JavaScript
551 lines
15 KiB
JavaScript
import _setImmediate from 'babel-runtime/core-js/set-immediate';
|
|
import _Promise from 'babel-runtime/core-js/promise';
|
|
import _Object$getPrototypeOf from 'babel-runtime/core-js/object/get-prototype-of';
|
|
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
|
|
import _createClass from 'babel-runtime/helpers/createClass';
|
|
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
|
|
import _inherits from 'babel-runtime/helpers/inherits';
|
|
/*
|
|
Copyright 2013-2015 ASIAL CORPORATION
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
import onsElements from '../ons/elements';
|
|
import util from '../ons/util';
|
|
import autoStyle from '../ons/autostyle';
|
|
import ModifierUtil from '../ons/internal/modifier-util';
|
|
import BaseElement from './base/base-element';
|
|
import contentReady from '../ons/content-ready';
|
|
import styler from '../ons/styler';
|
|
|
|
var defaultClassName = 'speed-dial';
|
|
var scheme = {
|
|
'': 'speed-dial--*'
|
|
};
|
|
|
|
/**
|
|
* @element ons-speed-dial
|
|
* @category control
|
|
* @description
|
|
* [en]
|
|
* Element that displays a Material Design Speed Dialog component. It is useful when there are more than one primary action that can be performed in a page.
|
|
*
|
|
* The Speed dial looks like a `<ons-fab>` element but will expand a menu when tapped.
|
|
* [/en]
|
|
* [ja][/ja]
|
|
* @codepen dYQYLg
|
|
* @tutorial vanilla/Reference/speed-dial
|
|
* @seealso ons-speed-dial-item
|
|
* [en]The `<ons-speed-dial-item>` represents a menu item.[/en]
|
|
* [ja]ons-speed-dial-itemコンポーネント[/ja]
|
|
* @seealso ons-fab
|
|
* [en]ons-fab component[/en]
|
|
* [ja]ons-fabコンポーネント[/ja]
|
|
* @example
|
|
* <ons-speed-dial position="left bottom">
|
|
* <ons-fab>
|
|
* <ons-icon icon="fa-twitter"></ons-icon>
|
|
* </ons-fab>
|
|
* <ons-speed-dial-item>A</ons-speed-dial-item>
|
|
* <ons-speed-dial-item>B</ons-speed-dial-item>
|
|
* <ons-speed-dial-item>C</ons-speed-dial-item>
|
|
* </ons-speed-dial>
|
|
*/
|
|
|
|
var SpeedDialElement = function (_BaseElement) {
|
|
_inherits(SpeedDialElement, _BaseElement);
|
|
|
|
/**
|
|
* @event open
|
|
* @description
|
|
* [en]Fired when the menu items are shown.[/en]
|
|
* [ja][/ja]
|
|
*/
|
|
|
|
/**
|
|
* @event close
|
|
* @description
|
|
* [en]Fired when the menu items are hidden.[/en]
|
|
* [ja][/ja]
|
|
*/
|
|
|
|
/**
|
|
* @attribute modifier
|
|
* @type {String}
|
|
* @description
|
|
* [en]The appearance of the component.[/en]
|
|
* [ja]このコンポーネントの表現を指定します。[/ja]
|
|
*/
|
|
|
|
/**
|
|
* @attribute ripple
|
|
* @description
|
|
* [en]If this attribute is defined, the button will have a ripple effect when tapped.[/en]
|
|
* [ja][/ja]
|
|
*/
|
|
|
|
/**
|
|
* @attribute position
|
|
* @type {String}
|
|
* @description
|
|
* [en]
|
|
* Specify the vertical and horizontal position of the component.
|
|
* I.e. to display it in the top right corner specify "right top".
|
|
* Choose from "right", "left", "top" and "bottom".
|
|
* [/en]
|
|
* [ja]
|
|
* この要素を表示する左右と上下の位置を指定します。
|
|
* 例えば、右上に表示する場合には"right top"を指定します。
|
|
* 左右と上下の位置の指定には、rightとleft、topとbottomがそれぞれ指定できます。
|
|
* [/ja]
|
|
*/
|
|
|
|
/**
|
|
* @attribute direction
|
|
* @type {String}
|
|
* @description
|
|
* [en]Specify the direction the items are displayed. Possible values are "up", "down", "left" and "right".[/en]
|
|
* [ja]
|
|
* 要素が表示する方向を指定します。up, down, left, rightが指定できます。
|
|
* [/ja]
|
|
*/
|
|
|
|
/**
|
|
* @attribute disabled
|
|
* @description
|
|
* [en]Specify if button should be disabled.[/en]
|
|
* [ja]無効化する場合に指定します。[/ja]
|
|
*/
|
|
|
|
function SpeedDialElement() {
|
|
_classCallCheck(this, SpeedDialElement);
|
|
|
|
var _this = _possibleConstructorReturn(this, (SpeedDialElement.__proto__ || _Object$getPrototypeOf(SpeedDialElement)).call(this));
|
|
|
|
contentReady(_this, function () {
|
|
_this._compile();
|
|
});
|
|
|
|
_this._itemShown = false;
|
|
_this._boundOnClick = _this._onClick.bind(_this);
|
|
return _this;
|
|
}
|
|
|
|
_createClass(SpeedDialElement, [{
|
|
key: '_compile',
|
|
value: function _compile() {
|
|
this.classList.add(defaultClassName);
|
|
autoStyle.prepare(this);
|
|
this._updateRipple();
|
|
ModifierUtil.initModifier(this, scheme);
|
|
|
|
if (this.hasAttribute('direction')) {
|
|
this._updateDirection(this.getAttribute('direction'));
|
|
} else {
|
|
this._updateDirection('up');
|
|
}
|
|
|
|
this._updatePosition();
|
|
}
|
|
}, {
|
|
key: 'attributeChangedCallback',
|
|
value: function attributeChangedCallback(name, last, current) {
|
|
var _this2 = this;
|
|
|
|
switch (name) {
|
|
case 'class':
|
|
util.restoreClass(this, defaultClassName, scheme);
|
|
break;
|
|
case 'modifier':
|
|
ModifierUtil.onModifierChanged(last, current, this, scheme);
|
|
break;
|
|
case 'ripple':
|
|
contentReady(this, function () {
|
|
return _this2._updateRipple();
|
|
});
|
|
break;
|
|
case 'direction':
|
|
contentReady(this, function () {
|
|
return _this2._updateDirection(current);
|
|
});
|
|
break;
|
|
case 'position':
|
|
contentReady(this, function () {
|
|
return _this2._updatePosition();
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'connectedCallback',
|
|
value: function connectedCallback() {
|
|
this.addEventListener('click', this._boundOnClick, false);
|
|
}
|
|
}, {
|
|
key: 'disconnectedCallback',
|
|
value: function disconnectedCallback() {
|
|
this.removeEventListener('click', this._boundOnClick, false);
|
|
}
|
|
}, {
|
|
key: '_onClick',
|
|
value: function _onClick(e) {
|
|
if (this.onClick) {
|
|
this.onClick.apply(this);
|
|
return _Promise.resolve();
|
|
} else if (!this.disabled && this.visible) {
|
|
return this.toggleItems();
|
|
}
|
|
}
|
|
}, {
|
|
key: '_show',
|
|
value: function _show() {
|
|
if (!this.inline) {
|
|
return this.show();
|
|
}
|
|
return _Promise.resolve();
|
|
}
|
|
}, {
|
|
key: '_hide',
|
|
value: function _hide() {
|
|
var _this3 = this;
|
|
|
|
return new _Promise(function (resolve) {
|
|
if (!_this3.inline) {
|
|
_setImmediate(function () {
|
|
return _this3.hide().then(resolve);
|
|
});
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
}
|
|
}, {
|
|
key: '_updateRipple',
|
|
value: function _updateRipple() {
|
|
if (this._fab) {
|
|
this.hasAttribute('ripple') ? this._fab.setAttribute('ripple', '') : this._fab.removeAttribute('ripple');
|
|
}
|
|
}
|
|
}, {
|
|
key: '_updateDirection',
|
|
value: function _updateDirection(direction) {
|
|
var children = this.items;
|
|
for (var i = 0; i < children.length; i++) {
|
|
styler(children[i], {
|
|
transitionDelay: 25 * i + 'ms',
|
|
bottom: 'auto',
|
|
right: 'auto',
|
|
top: 'auto',
|
|
left: 'auto'
|
|
});
|
|
}
|
|
switch (direction) {
|
|
case 'up':
|
|
for (var _i = 0; _i < children.length; _i++) {
|
|
children[_i].style.bottom = 72 + 56 * _i + 'px';
|
|
children[_i].style.right = '8px';
|
|
}
|
|
break;
|
|
case 'down':
|
|
for (var _i2 = 0; _i2 < children.length; _i2++) {
|
|
children[_i2].style.top = 72 + 56 * _i2 + 'px';
|
|
children[_i2].style.left = '8px';
|
|
}
|
|
break;
|
|
case 'left':
|
|
for (var _i3 = 0; _i3 < children.length; _i3++) {
|
|
children[_i3].style.top = '8px';
|
|
children[_i3].style.right = 72 + 56 * _i3 + 'px';
|
|
}
|
|
break;
|
|
case 'right':
|
|
for (var _i4 = 0; _i4 < children.length; _i4++) {
|
|
children[_i4].style.top = '8px';
|
|
children[_i4].style.left = 72 + 56 * _i4 + 'px';
|
|
}
|
|
break;
|
|
default:
|
|
util.throw('Argument must be one of up, down, left or right.');
|
|
}
|
|
}
|
|
}, {
|
|
key: '_updatePosition',
|
|
value: function _updatePosition() {
|
|
var position = this.getAttribute('position');
|
|
this.classList.remove('fab--top__left', 'fab--bottom__right', 'fab--bottom__left', 'fab--top__right', 'fab--top__center', 'fab--bottom__center');
|
|
switch (position) {
|
|
case 'top right':
|
|
case 'right top':
|
|
this.classList.add('fab--top__right');
|
|
break;
|
|
case 'top left':
|
|
case 'left top':
|
|
this.classList.add('fab--top__left');
|
|
break;
|
|
case 'bottom right':
|
|
case 'right bottom':
|
|
this.classList.add('fab--bottom__right');
|
|
break;
|
|
case 'bottom left':
|
|
case 'left bottom':
|
|
this.classList.add('fab--bottom__left');
|
|
break;
|
|
case 'center top':
|
|
case 'top center':
|
|
this.classList.add('fab--top__center');
|
|
break;
|
|
case 'center bottom':
|
|
case 'bottom center':
|
|
this.classList.add('fab--bottom__center');
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}, {
|
|
key: '_getTranslate',
|
|
value: function _getTranslate() {
|
|
var isBottom = (this.getAttribute('position') || '').indexOf('bottom') >= 0;
|
|
var translate = isBottom ? 'translate3d(0px, -' + (util.globals.fabOffset || 0) + 'px, 0px) ' : '';
|
|
return translate;
|
|
}
|
|
|
|
/**
|
|
* @method show
|
|
* @signature show()
|
|
* @description
|
|
* [en]Show the speed dial.[/en]
|
|
* [ja]Speed dialを表示します。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'show',
|
|
value: function show() {
|
|
this._fab.show();
|
|
styler(this, { transform: this._getTranslate });
|
|
return _Promise.resolve();
|
|
}
|
|
|
|
/**
|
|
* @method hide
|
|
* @signature hide()
|
|
* @description
|
|
* [en]Hide the speed dial.[/en]
|
|
* [ja]Speed dialを非表示にします。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'hide',
|
|
value: function hide() {
|
|
var _this4 = this;
|
|
|
|
return this.hideItems().then(function () {
|
|
return _this4._fab.hide();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @method showItems
|
|
* @signature showItems()
|
|
* @description
|
|
* [en]Show the speed dial items.[/en]
|
|
* [ja]Speed dialの子要素を表示します。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'showItems',
|
|
value: function showItems() {
|
|
if (this.hasAttribute('direction')) {
|
|
this._updateDirection(this.getAttribute('direction'));
|
|
} else {
|
|
this._updateDirection('up');
|
|
}
|
|
|
|
var totalDelay = 0;
|
|
if (!this._itemShown) {
|
|
var children = this.items;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var delay = 25 * i;
|
|
totalDelay += delay;
|
|
styler(children[i], {
|
|
transform: 'scale(1)',
|
|
transitionDelay: delay + 'ms'
|
|
});
|
|
}
|
|
totalDelay += 50;
|
|
|
|
this._itemShown = true;
|
|
util.triggerElementEvent(this, 'open');
|
|
}
|
|
|
|
var deferred = util.defer();
|
|
setTimeout(deferred.resolve, totalDelay);
|
|
return deferred.promise;
|
|
}
|
|
|
|
/**
|
|
* @method hideItems
|
|
* @signature hideItems()
|
|
* @description
|
|
* [en]Hide the speed dial items.[/en]
|
|
* [ja]Speed dialの子要素を非表示にします。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'hideItems',
|
|
value: function hideItems() {
|
|
var totalDelay = 0;
|
|
if (this._itemShown) {
|
|
var children = this.items;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var delay = 25 * (children.length - i);
|
|
totalDelay += delay;
|
|
styler(children[i], {
|
|
transform: 'scale(0)',
|
|
transitionDelay: delay + 'ms'
|
|
});
|
|
}
|
|
totalDelay += 50;
|
|
|
|
this._itemShown = false;
|
|
util.triggerElementEvent(this, 'close');
|
|
}
|
|
|
|
var deferred = util.defer();
|
|
setTimeout(deferred.resolve, totalDelay);
|
|
return deferred.promise;
|
|
}
|
|
|
|
/**
|
|
* @property disabled
|
|
* @type {Boolean}
|
|
* @description
|
|
* [en]Whether the element is disabled or not.[/en]
|
|
* [ja]無効化されている場合に`true`。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'isOpen',
|
|
|
|
|
|
/**
|
|
* @method isOpen
|
|
* @signature isOpen()
|
|
* @description
|
|
* [en]Returns whether the menu is open or not.[/en]
|
|
* [ja][/ja]
|
|
*/
|
|
value: function isOpen() {
|
|
return this._itemShown;
|
|
}
|
|
|
|
/**
|
|
* @method toggle
|
|
* @signature toggle()
|
|
* @description
|
|
* [en]Toggle visibility.[/en]
|
|
* [ja]Speed dialの表示非表示を切り替えます。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'toggle',
|
|
value: function toggle() {
|
|
return this.visible ? this.hide() : this.show();
|
|
}
|
|
|
|
/**
|
|
* @method toggleItems
|
|
* @signature toggleItems()
|
|
* @description
|
|
* [en]Toggle item visibility.[/en]
|
|
* [ja]Speed dialの子要素の表示非表示を切り替えます。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'toggleItems',
|
|
value: function toggleItems() {
|
|
return this.isOpen() ? this.hideItems() : this.showItems();
|
|
}
|
|
}, {
|
|
key: 'items',
|
|
get: function get() {
|
|
return util.arrayFrom(this.querySelectorAll('ons-speed-dial-item'));
|
|
}
|
|
}, {
|
|
key: '_fab',
|
|
get: function get() {
|
|
return util.findChild(this, 'ons-fab');
|
|
}
|
|
}, {
|
|
key: 'disabled',
|
|
set: function set(value) {
|
|
if (value) {
|
|
this.hideItems();
|
|
}
|
|
util.arrayFrom(this.children).forEach(function (e) {
|
|
util.match(e, '.fab') && util.toggleAttribute(e, 'disabled', value);
|
|
});
|
|
|
|
return util.toggleAttribute(this, 'disabled', value);
|
|
},
|
|
get: function get() {
|
|
return this.hasAttribute('disabled');
|
|
}
|
|
|
|
/**
|
|
* @property inline
|
|
* @readonly
|
|
* @type {Boolean}
|
|
* @description
|
|
* [en]Whether the element is inline or not.[/en]
|
|
* [ja]インライン要素の場合に`true`。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'inline',
|
|
get: function get() {
|
|
return this.hasAttribute('inline');
|
|
}
|
|
|
|
/**
|
|
* @property visible
|
|
* @readonly
|
|
* @type {Boolean}
|
|
* @description
|
|
* [en]Whether the element is visible or not.[/en]
|
|
* [ja]要素が見える場合に`true`。[/ja]
|
|
*/
|
|
|
|
}, {
|
|
key: 'visible',
|
|
get: function get() {
|
|
return this._fab.visible && this.style.display !== 'none';
|
|
}
|
|
}], [{
|
|
key: 'observedAttributes',
|
|
get: function get() {
|
|
return ['class', 'modifier', 'ripple', 'direction', 'position'];
|
|
}
|
|
}, {
|
|
key: 'events',
|
|
get: function get() {
|
|
return ['open', 'close'];
|
|
}
|
|
}]);
|
|
|
|
return SpeedDialElement;
|
|
}(BaseElement);
|
|
|
|
export default SpeedDialElement;
|
|
|
|
|
|
onsElements.SpeedDial = SpeedDialElement;
|
|
customElements.define('ons-speed-dial', SpeedDialElement); |