framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
381 lines (318 loc) • 10.4 kB
JavaScript
import $ from 'dom7';
import Utils from '../../utils/utils';
import Framework7Class from '../../utils/class';
import SwipePanel from './swipe-panel';
import ResizablePanel from './resizable-panel';
class Panel extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const panel = this;
let el = params.el;
if (!el && params.content) {
el = params.content;
}
const $el = $(el);
if ($el.length === 0) return panel;
if ($el[0].f7Panel) return $el[0].f7Panel;
$el[0].f7Panel = panel;
let { opened, side, effect } = params;
if (typeof opened === 'undefined') opened = $el.hasClass('panel-active');
if (typeof side === 'undefined') side = $el.hasClass('panel-left') ? 'left' : 'right';
if (typeof effect === 'undefined') effect = $el.hasClass('panel-cover') ? 'cover' : 'reveal';
if (!app.panel[side]) {
app.panel[side] = panel;
} else {
throw new Error(`Framework7: Can't create panel; app already has a ${side} panel!`);
}
let $backdropEl = $('.panel-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="panel-backdrop"></div>');
$backdropEl.insertBefore($el);
}
Utils.extend(panel, {
app,
side,
effect,
$el,
el: $el[0],
opened,
$backdropEl,
backdropEl: $backdropEl[0],
params,
});
// Install Modules
panel.useModules();
// Init
panel.init();
return panel;
}
getViewEl() {
const panel = this;
const app = panel.app;
let viewEl;
if (app.root.children('.views').length > 0) {
viewEl = app.root.children('.views')[0];
} else {
viewEl = app.root.children('.view')[0];
}
return viewEl;
}
setBreakpoint(emitEvents = true) {
const panel = this;
const app = panel.app;
const { side, $el } = panel;
const $viewEl = $(panel.getViewEl());
const breakpoint = app.params.panel[`${side}Breakpoint`];
const wasVisible = $el.hasClass('panel-visible-by-breakpoint');
if (app.width >= breakpoint) {
if (!wasVisible) {
$('html').removeClass(`with-panel-${side}-reveal with-panel-${side}-cover with-panel`);
$el.css('display', '').addClass('panel-visible-by-breakpoint').removeClass('panel-active');
panel.onOpen();
panel.onOpened();
$viewEl.css({
[`margin-${side}`]: `${$el.width()}px`,
});
app.allowPanelOpen = true;
if (emitEvents) {
app.emit('local::breakpoint panelBreakpoint');
panel.$el.trigger('panel:breakpoint', panel);
}
} else {
$viewEl.css({
[`margin-${side}`]: `${$el.width()}px`,
});
}
} else if (wasVisible) {
$el.css('display', '').removeClass('panel-visible-by-breakpoint panel-active');
panel.onClose();
panel.onClosed();
$viewEl.css({
[`margin-${side}`]: '',
});
if (emitEvents) {
app.emit('local::breakpoint panelBreakpoint');
panel.$el.trigger('panel:breakpoint', panel);
}
}
}
initBreakpoints() {
const panel = this;
const app = panel.app;
panel.resizeHandler = function resizeHandler() {
panel.setBreakpoint();
};
if (app.params.panel[`${panel.side}Breakpoint`]) {
app.on('resize', panel.resizeHandler);
}
panel.setBreakpoint();
return panel;
}
initSwipePanel() {
if ("universal" !== 'desktop') {
SwipePanel(this);
}
}
initResizablePanel() {
ResizablePanel(this);
}
toggle(animate = true) {
const panel = this;
if (panel.opened) panel.close(animate);
else panel.open(animate);
}
onOpen() {
const panel = this;
panel.opened = true;
panel.$el.trigger('panel:beforeopen', panel);
panel.emit('local::beforeOpen panelBeforeOpen', panel);
panel.$el.trigger('panel:open', panel);
panel.emit('local::open panelOpen', panel);
}
onOpened() {
const panel = this;
const app = panel.app;
app.panel.allowOpen = true;
panel.$el.trigger('panel:opened', panel);
panel.emit('local::opened panelOpened', panel);
}
onClose() {
const panel = this;
panel.opened = false;
panel.$el.addClass('panel-closing');
panel.$el.trigger('panel:beforeclose', panel);
panel.emit('local::beforeClose panelBeforeClose', panel);
panel.$el.trigger('panel:close', panel);
panel.emit('local::close panelClose', panel);
}
onClosed() {
const panel = this;
const app = panel.app;
app.panel.allowOpen = true;
panel.$el.removeClass('panel-closing');
panel.$el.trigger('panel:closed', panel);
panel.emit('local::closed panelClosed', panel);
}
open(animate = true) {
const panel = this;
const app = panel.app;
if (!app.panel.allowOpen) return false;
const { side, effect, $el, $backdropEl, opened } = panel;
const $panelParentEl = $el.parent();
const wasInDom = $el.parents(document).length > 0;
if (!$panelParentEl.is(app.root) || $el.prevAll('.views, .view').length) {
const $insertBeforeEl = app.root.children('.panel, .views, .view').eq(0);
const $insertAfterEl = app.root.children('.statusbar').eq(0);
if ($insertBeforeEl.length) {
$el.insertBefore($insertBeforeEl);
} else if ($insertAfterEl.length) {
$el.insertAfter($insertBeforeEl);
} else {
app.root.prepend($el);
}
if ($backdropEl
&& $backdropEl.length
&& (
(
!$backdropEl.parent().is(app.root)
&& $backdropEl.nextAll('.panel').length === 0
)
|| (
$backdropEl.parent().is(app.root)
&& $backdropEl.nextAll('.panel').length === 0
)
)
) {
$backdropEl.insertBefore($el);
}
panel.once('panelClosed', () => {
if (wasInDom) {
$panelParentEl.append($el);
} else {
$el.remove();
}
});
}
// Ignore if opened
if (opened || $el.hasClass('panel-visible-by-breakpoint') || $el.hasClass('panel-active')) return false;
// Close if some panel is opened
app.panel.close(side === 'left' ? 'right' : 'left', animate);
app.panel.allowOpen = false;
$el[animate ? 'removeClass' : 'addClass']('not-animated');
$el
.css({ display: 'block' })
.addClass('panel-active');
$backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
$backdropEl.css({ display: 'block' });
/* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
// panel._clientLeft = $el[0].clientLeft;
// Transition End;
const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;
function panelTransitionEnd() {
transitionEndTarget.transitionEnd((e) => {
if ($(e.target).is(transitionEndTarget)) {
if ($el.hasClass('panel-active')) {
panel.onOpened();
$backdropEl.css({ display: '' });
} else {
panel.onClosed();
$backdropEl.css({ display: '' });
}
} else panelTransitionEnd();
});
}
if (animate) {
Utils.nextFrame(() => {
$('html').addClass(`with-panel with-panel-${side}-${effect}`);
panel.onOpen();
panelTransitionEnd();
});
} else {
$('html').addClass(`with-panel with-panel-${side}-${effect}`);
panel.onOpen();
panel.onOpened();
$backdropEl.css({ display: '' });
}
return true;
}
close(animate = true) {
const panel = this;
const app = panel.app;
const { side, effect, $el, $backdropEl, opened } = panel;
if (!opened || $el.hasClass('panel-visible-by-breakpoint') || !$el.hasClass('panel-active')) return false;
$el[animate ? 'removeClass' : 'addClass']('not-animated');
$el.removeClass('panel-active');
$backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;
panel.onClose();
app.panel.allowOpen = false;
if (animate) {
transitionEndTarget.transitionEnd(() => {
if ($el.hasClass('panel-active')) return;
$el.css({ display: '' });
$('html').removeClass('with-panel-transitioning');
panel.onClosed();
});
$('html')
.removeClass(`with-panel with-panel-${side}-${effect}`)
.addClass('with-panel-transitioning');
} else {
$el.css({ display: '' });
$el.removeClass('not-animated');
$('html').removeClass(`with-panel with-panel-transitioning with-panel-${side}-${effect}`);
panel.onClosed();
}
return true;
}
init() {
const panel = this;
const app = panel.app;
if (app.params.panel[`${panel.side}Breakpoint`]) {
panel.initBreakpoints();
}
if (process.env.TARGET !== 'desktop') {
if (
(app.params.panel.swipe === panel.side)
|| (app.params.panel.swipe === 'both')
|| (app.params.panel.swipe && app.params.panel.swipe !== panel.side && app.params.panel.swipeCloseOpposite)
) {
panel.initSwipePanel();
}
}
if (panel.params.resizable || panel.$el.hasClass('panel-resizable')) {
panel.initResizablePanel();
}
}
destroy() {
let panel = this;
const app = panel.app;
if (!panel.$el) {
// Panel already destroyed
return;
}
panel.emit('local::beforeDestroy panelBeforeDestroy', panel);
panel.$el.trigger('panel:beforedestroy', panel);
if (panel.resizeHandler) {
app.off('resize', panel.resizeHandler);
}
if (panel.$el.hasClass('panel-visible-by-breakpoint')) {
const $viewEl = $(panel.getViewEl());
panel.$el.css('display', '').removeClass('panel-visible-by-breakpoint panel-active');
$viewEl.css({
[`margin-${panel.side}`]: '',
});
app.emit('local::breakpoint panelBreakpoint');
panel.$el.trigger('panel:breakpoint', panel);
}
panel.$el.trigger('panel:destroy', panel);
panel.emit('local::destroy panelDestroy');
delete app.panel[panel.side];
if (panel.el) {
panel.el.f7Panel = null;
delete panel.el.f7Panel;
}
Utils.deleteProps(panel);
panel = null;
}
}
export default Panel;