infojune/resources/sass/materialize/js/buttons.js

355 lines
8.9 KiB
JavaScript

(function($, anim) {
'use strict';
let _defaults = {
direction: 'top',
hoverEnabled: true,
toolbarEnabled: false
};
$.fn.reverse = [].reverse;
/**
* @class
*
*/
class FloatingActionButton extends Component {
/**
* Construct FloatingActionButton instance
* @constructor
* @param {Element} el
* @param {Object} options
*/
constructor(el, options) {
super(FloatingActionButton, el, options);
this.el.M_FloatingActionButton = this;
/**
* Options for the fab
* @member FloatingActionButton#options
* @prop {Boolean} [direction] - Direction fab menu opens
* @prop {Boolean} [hoverEnabled=true] - Enable hover vs click
* @prop {Boolean} [toolbarEnabled=false] - Enable toolbar transition
*/
this.options = $.extend({}, FloatingActionButton.defaults, options);
this.isOpen = false;
this.$anchor = this.$el.children('a').first();
this.$menu = this.$el.children('ul').first();
this.$floatingBtns = this.$el.find('ul .btn-floating');
this.$floatingBtnsReverse = this.$el.find('ul .btn-floating').reverse();
this.offsetY = 0;
this.offsetX = 0;
this.$el.addClass(`direction-${this.options.direction}`);
if (this.options.direction === 'top') {
this.offsetY = 40;
} else if (this.options.direction === 'right') {
this.offsetX = -40;
} else if (this.options.direction === 'bottom') {
this.offsetY = -40;
} else {
this.offsetX = 40;
}
this._setupEventHandlers();
}
static get defaults() {
return _defaults;
}
static init(els, options) {
return super.init(this, els, options);
}
/**
* Get Instance
*/
static getInstance(el) {
let domElem = !!el.jquery ? el[0] : el;
return domElem.M_FloatingActionButton;
}
/**
* Teardown component
*/
destroy() {
this._removeEventHandlers();
this.el.M_FloatingActionButton = undefined;
}
/**
* Setup Event Handlers
*/
_setupEventHandlers() {
this._handleFABClickBound = this._handleFABClick.bind(this);
this._handleOpenBound = this.open.bind(this);
this._handleCloseBound = this.close.bind(this);
if (this.options.hoverEnabled && !this.options.toolbarEnabled) {
this.el.addEventListener('mouseenter', this._handleOpenBound);
this.el.addEventListener('mouseleave', this._handleCloseBound);
} else {
this.el.addEventListener('click', this._handleFABClickBound);
}
}
/**
* Remove Event Handlers
*/
_removeEventHandlers() {
if (this.options.hoverEnabled && !this.options.toolbarEnabled) {
this.el.removeEventListener('mouseenter', this._handleOpenBound);
this.el.removeEventListener('mouseleave', this._handleCloseBound);
} else {
this.el.removeEventListener('click', this._handleFABClickBound);
}
}
/**
* Handle FAB Click
*/
_handleFABClick() {
if (this.isOpen) {
this.close();
} else {
this.open();
}
}
/**
* Handle Document Click
* @param {Event} e
*/
_handleDocumentClick(e) {
if (!$(e.target).closest(this.$menu).length) {
this.close();
}
}
/**
* Open FAB
*/
open() {
if (this.isOpen) {
return;
}
if (this.options.toolbarEnabled) {
this._animateInToolbar();
} else {
this._animateInFAB();
}
this.isOpen = true;
}
/**
* Close FAB
*/
close() {
if (!this.isOpen) {
return;
}
if (this.options.toolbarEnabled) {
window.removeEventListener('scroll', this._handleCloseBound, true);
document.body.removeEventListener('click', this._handleDocumentClickBound, true);
this._animateOutToolbar();
} else {
this._animateOutFAB();
}
this.isOpen = false;
}
/**
* Classic FAB Menu open
*/
_animateInFAB() {
this.$el.addClass('active');
let time = 0;
this.$floatingBtnsReverse.each((el) => {
anim({
targets: el,
opacity: 1,
scale: [0.4, 1],
translateY: [this.offsetY, 0],
translateX: [this.offsetX, 0],
duration: 275,
delay: time,
easing: 'easeInOutQuad'
});
time += 40;
});
}
/**
* Classic FAB Menu close
*/
_animateOutFAB() {
this.$floatingBtnsReverse.each((el) => {
anim.remove(el);
anim({
targets: el,
opacity: 0,
scale: 0.4,
translateY: this.offsetY,
translateX: this.offsetX,
duration: 175,
easing: 'easeOutQuad',
complete: () => {
this.$el.removeClass('active');
}
});
});
}
/**
* Toolbar transition Menu open
*/
_animateInToolbar() {
let scaleFactor;
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
let btnRect = this.el.getBoundingClientRect();
let backdrop = $('<div class="fab-backdrop"></div>');
let fabColor = this.$anchor.css('background-color');
this.$anchor.append(backdrop);
this.offsetX = btnRect.left - windowWidth / 2 + btnRect.width / 2;
this.offsetY = windowHeight - btnRect.bottom;
scaleFactor = windowWidth / backdrop[0].clientWidth;
this.btnBottom = btnRect.bottom;
this.btnLeft = btnRect.left;
this.btnWidth = btnRect.width;
// Set initial state
this.$el.addClass('active');
this.$el.css({
'text-align': 'center',
width: '100%',
bottom: 0,
left: 0,
transform: 'translateX(' + this.offsetX + 'px)',
transition: 'none'
});
this.$anchor.css({
transform: 'translateY(' + -this.offsetY + 'px)',
transition: 'none'
});
backdrop.css({
'background-color': fabColor
});
setTimeout(() => {
this.$el.css({
transform: '',
transition:
'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s'
});
this.$anchor.css({
overflow: 'visible',
transform: '',
transition: 'transform .2s'
});
setTimeout(() => {
this.$el.css({
overflow: 'hidden',
'background-color': fabColor
});
backdrop.css({
transform: 'scale(' + scaleFactor + ')',
transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
});
this.$menu
.children('li')
.children('a')
.css({
opacity: 1
});
// Scroll to close.
this._handleDocumentClickBound = this._handleDocumentClick.bind(this);
window.addEventListener('scroll', this._handleCloseBound, true);
document.body.addEventListener('click', this._handleDocumentClickBound, true);
}, 100);
}, 0);
}
/**
* Toolbar transition Menu close
*/
_animateOutToolbar() {
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
let backdrop = this.$el.find('.fab-backdrop');
let fabColor = this.$anchor.css('background-color');
this.offsetX = this.btnLeft - windowWidth / 2 + this.btnWidth / 2;
this.offsetY = windowHeight - this.btnBottom;
// Hide backdrop
this.$el.removeClass('active');
this.$el.css({
'background-color': 'transparent',
transition: 'none'
});
this.$anchor.css({
transition: 'none'
});
backdrop.css({
transform: 'scale(0)',
'background-color': fabColor
});
this.$menu
.children('li')
.children('a')
.css({
opacity: ''
});
setTimeout(() => {
backdrop.remove();
// Set initial state.
this.$el.css({
'text-align': '',
width: '',
bottom: '',
left: '',
overflow: '',
'background-color': '',
transform: 'translate3d(' + -this.offsetX + 'px,0,0)'
});
this.$anchor.css({
overflow: '',
transform: 'translate3d(0,' + this.offsetY + 'px,0)'
});
setTimeout(() => {
this.$el.css({
transform: 'translate3d(0,0,0)',
transition: 'transform .2s'
});
this.$anchor.css({
transform: 'translate3d(0,0,0)',
transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
});
}, 20);
}, 200);
}
}
M.FloatingActionButton = FloatingActionButton;
if (M.jQueryLoaded) {
M.initializeJqueryWrapper(
FloatingActionButton,
'floatingActionButton',
'M_FloatingActionButton'
);
}
})(cash, M.anime);