framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
224 lines (218 loc) • 7.22 kB
JavaScript
import { getDocument } from 'ssr-window';
import $ from '../../shared/dom7.js';
import { extend, deleteProps } from '../../shared/utils.js';
import Framework7Class from '../../shared/class.js';
const openedModals = [];
const dialogsQueue = [];
function clearDialogsQueue() {
if (dialogsQueue.length === 0) return;
const dialog = dialogsQueue.shift();
dialog.open();
}
class Modal extends Framework7Class {
constructor(app, params) {
super(params, [app]);
const modal = this;
const defaults = {};
// Extend defaults with modules params
modal.useModulesParams(defaults);
modal.params = extend(defaults, params);
modal.opened = false;
let $containerEl = modal.params.containerEl ? $(modal.params.containerEl).eq(0) : app.$el;
if (!$containerEl.length) $containerEl = app.$el;
modal.$containerEl = $containerEl;
modal.containerEl = $containerEl[0];
// Install Modules
modal.useModules();
return this;
}
onOpen() {
const modal = this;
modal.opened = true;
openedModals.push(modal);
$('html').addClass(`with-modal-${modal.type.toLowerCase()}`);
modal.$el.trigger(`modal:open ${modal.type.toLowerCase()}:open`);
modal.emit(`local::open modalOpen ${modal.type}Open`, modal);
}
onOpened() {
const modal = this;
modal.$el.trigger(`modal:opened ${modal.type.toLowerCase()}:opened`);
modal.emit(`local::opened modalOpened ${modal.type}Opened`, modal);
}
onClose() {
const modal = this;
modal.opened = false;
if (!modal.type || !modal.$el) return;
openedModals.splice(openedModals.indexOf(modal), 1);
$('html').removeClass(`with-modal-${modal.type.toLowerCase()}`);
modal.$el.trigger(`modal:close ${modal.type.toLowerCase()}:close`);
modal.emit(`local::close modalClose ${modal.type}Close`, modal);
}
onClosed() {
const modal = this;
if (!modal.type || !modal.$el) return;
modal.$el.removeClass('modal-out');
modal.$el.hide();
if (modal.params.backdrop && (modal.params.backdropUnique || modal.forceBackdropUnique) && modal.$backdropEl) {
modal.$backdropEl.remove();
}
modal.$el.trigger(`modal:closed ${modal.type.toLowerCase()}:closed`);
modal.emit(`local::closed modalClosed ${modal.type}Closed`, modal);
}
open(animateModal, force) {
const modal = this;
const document = getDocument();
const app = modal.app;
const $el = modal.$el;
const $backdropEl = modal.$backdropEl;
const type = modal.type;
let animate = true;
if (typeof animateModal !== 'undefined') animate = animateModal;else if (typeof modal.params.animate !== 'undefined') {
animate = modal.params.animate;
}
if (!$el || $el.hasClass('modal-in')) {
if (animateModal === false && $el[0] && type !== 'dialog') {
$el[0].style.display = 'block';
}
if (!force) return modal;
}
if (type === 'dialog' && app.params.modal.queueDialogs) {
let pushToQueue;
if ($('.dialog.modal-in').length > 0) {
pushToQueue = true;
} else if (openedModals.length > 0) {
openedModals.forEach(openedModal => {
if (openedModal.type === 'dialog') pushToQueue = true;
});
}
if (pushToQueue) {
dialogsQueue.push(modal);
return modal;
}
}
const $modalParentEl = $el.parent();
const wasInDom = $el.parents(document).length > 0;
if (!$modalParentEl.is(modal.$containerEl)) {
modal.$containerEl.append($el);
modal.once(`${type}Closed`, () => {
if (wasInDom) {
$modalParentEl.append($el);
} else {
$el.remove();
}
});
}
// Show Modal
$el.show();
if (modal.params.backdrop && (modal.params.backdropUnique || modal.forceBackdropUnique) && modal.$backdropEl) {
modal.$backdropEl.insertBefore($el);
}
/* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
modal._clientLeft = $el[0].clientLeft;
// Modal
function transitionEnd() {
if ($el.hasClass('modal-out')) {
modal.onClosed();
} else if ($el.hasClass('modal-in')) {
modal.onOpened();
}
}
if (animate) {
if ($backdropEl) {
$backdropEl.removeClass('not-animated');
$backdropEl.addClass('backdrop-in');
}
$el.animationEnd(() => {
transitionEnd();
});
$el.transitionEnd(() => {
transitionEnd();
});
$el.removeClass('modal-out not-animated').addClass('modal-in');
modal.onOpen();
} else {
if ($backdropEl) {
$backdropEl.addClass('backdrop-in not-animated');
}
$el.removeClass('modal-out').addClass('modal-in not-animated');
modal.onOpen();
modal.onOpened();
}
return modal;
}
close(animateModal) {
const modal = this;
const $el = modal.$el;
const $backdropEl = modal.$backdropEl;
let animate = true;
if (typeof animateModal !== 'undefined') animate = animateModal;else if (typeof modal.params.animate !== 'undefined') {
animate = modal.params.animate;
}
if (!$el || !$el.hasClass('modal-in')) {
if (dialogsQueue.indexOf(modal) >= 0) {
dialogsQueue.splice(dialogsQueue.indexOf(modal), 1);
}
return modal;
}
// backdrop
if ($backdropEl) {
let needToHideBackdrop = true;
if (modal.type === 'popup') {
modal.$el.prevAll('.popup.modal-in').add(modal.$el.nextAll('.popup.modal-in')).each(popupEl => {
const popupInstance = popupEl.f7Modal;
if (!popupInstance) return;
if (popupInstance.params.closeByBackdropClick && popupInstance.params.backdrop && popupInstance.backdropEl === modal.backdropEl) {
needToHideBackdrop = false;
}
});
}
if (needToHideBackdrop) {
$backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
$backdropEl.removeClass('backdrop-in');
}
}
// Modal
$el[animate ? 'removeClass' : 'addClass']('not-animated');
function transitionEnd() {
if ($el.hasClass('modal-out')) {
modal.onClosed();
} else if ($el.hasClass('modal-in')) {
modal.onOpened();
}
}
if (animate) {
$el.animationEnd(() => {
transitionEnd();
});
$el.transitionEnd(() => {
transitionEnd();
});
$el.removeClass('modal-in').addClass('modal-out');
// Emit close
modal.onClose();
} else {
$el.addClass('not-animated').removeClass('modal-in').addClass('modal-out');
// Emit close
modal.onClose();
modal.onClosed();
}
if (modal.type === 'dialog') {
clearDialogsQueue();
}
return modal;
}
destroy() {
const modal = this;
if (modal.destroyed) return;
modal.emit(`local::beforeDestroy modalBeforeDestroy ${modal.type}BeforeDestroy`, modal);
if (modal.$el) {
modal.$el.trigger(`modal:beforedestroy ${modal.type.toLowerCase()}:beforedestroy`);
if (modal.$el.length && modal.$el[0].f7Modal) {
delete modal.$el[0].f7Modal;
}
}
deleteProps(modal);
modal.destroyed = true;
}
}
export default Modal;