framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
317 lines (294 loc) • 10.8 kB
JavaScript
/* eslint indent: ["off"] */
import $ from 'dom7';
import { window, document } from 'ssr-window';
import Utils from '../../utils/utils';
import Modal from '../modal/modal-class';
class Actions extends Modal {
constructor(app, params) {
const extendedParams = Utils.extend(
{ on: {} },
app.params.actions,
params
);
// Extends with open/close Modal methods;
super(app, extendedParams);
const actions = this;
actions.params = extendedParams;
// Buttons
let groups;
if (actions.params.buttons) {
groups = actions.params.buttons;
if (!Array.isArray(groups[0])) groups = [groups];
}
actions.groups = groups;
// Find Element
let $el;
if (actions.params.el) {
$el = $(actions.params.el).eq(0);
} else if (actions.params.content) {
$el = $(actions.params.content).filter((elIndex, node) => node.nodeType === 1).eq(0);
} else if (actions.params.buttons) {
if (actions.params.convertToPopover) {
actions.popoverHtml = actions.renderPopover();
}
actions.actionsHtml = actions.render();
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el && $el.length === 0 && !(actions.actionsHtml || actions.popoverHtml)) {
return actions.destroy();
}
// Backdrop
let $backdropEl;
if (actions.params.backdrop && actions.params.backdropEl) {
$backdropEl = $(actions.params.backdropEl);
} else if (actions.params.backdrop) {
$backdropEl = app.root.children('.actions-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="actions-backdrop"></div>');
app.root.append($backdropEl);
}
}
const originalOpen = actions.open;
const originalClose = actions.close;
let popover;
function buttonOnClick(e) {
const $buttonEl = $(this);
let buttonIndex;
let groupIndex;
if ($buttonEl.hasClass('list-button') || $buttonEl.hasClass('item-link')) {
buttonIndex = $buttonEl.parents('li').index();
groupIndex = $buttonEl.parents('.list').index();
} else {
buttonIndex = $buttonEl.index();
groupIndex = $buttonEl.parents('.actions-group').index();
}
if (typeof groups !== 'undefined') {
const button = groups[groupIndex][buttonIndex];
if (button.onClick) button.onClick(actions, e);
if (actions.params.onClick) actions.params.onClick(actions, e);
if (button.close !== false) actions.close();
}
}
actions.open = function open(animate) {
let convertToPopover = false;
const { targetEl, targetX, targetY, targetWidth, targetHeight } = actions.params;
if (actions.params.convertToPopover && (targetEl || (targetX !== undefined && targetY !== undefined))) {
// Popover
if (
actions.params.forceToPopover
|| (app.device.ios && app.device.ipad)
|| app.width >= 768
|| (app.device.desktop && app.theme === 'aurora')
) {
convertToPopover = true;
}
}
if (convertToPopover && actions.popoverHtml) {
popover = app.popover.create({
content: actions.popoverHtml,
backdrop: actions.params.backdrop,
targetEl,
targetX,
targetY,
targetWidth,
targetHeight,
on: {
open() {
actions.$el.trigger(`modal:open ${actions.type.toLowerCase()}:open`);
actions.emit(`local::open modalOpen ${actions.type}Open`, actions);
},
opened() {
actions.$el.trigger(`modal:opened ${actions.type.toLowerCase()}:opened`);
actions.emit(`local::opened modalOpened ${actions.type}Opened`, actions);
},
close() {
actions.$el.trigger(`modal:close ${actions.type.toLowerCase()}:close`);
actions.emit(`local::close modalClose ${actions.type}Close`, actions);
},
closed() {
actions.$el.trigger(`modal:closed ${actions.type.toLowerCase()}:closed`);
actions.emit(`local::closed modalClosed ${actions.type}Closed`, actions);
},
},
});
popover.open(animate);
popover.once('popoverOpened', () => {
popover.$el.find('.list-button, .item-link').each((groupIndex, buttonEl) => {
$(buttonEl).on('click', buttonOnClick);
});
});
popover.once('popoverClosed', () => {
popover.$el.find('.list-button, .item-link').each((groupIndex, buttonEl) => {
$(buttonEl).off('click', buttonOnClick);
});
Utils.nextTick(() => {
popover.destroy();
popover = undefined;
});
});
} else {
actions.$el = actions.actionsHtml ? $(actions.actionsHtml) : actions.$el;
actions.$el[0].f7Modal = actions;
if (actions.groups) {
actions.$el.find('.actions-button').each((groupIndex, buttonEl) => {
$(buttonEl).on('click', buttonOnClick);
});
actions.once('actionsClosed', () => {
actions.$el.find('.actions-button').each((groupIndex, buttonEl) => {
$(buttonEl).off('click', buttonOnClick);
});
});
}
actions.el = actions.$el[0];
originalOpen.call(actions, animate);
}
return actions;
};
actions.close = function close(animate) {
if (popover) {
popover.close(animate);
} else {
originalClose.call(actions, animate);
}
return actions;
};
Utils.extend(actions, {
app,
$el,
el: $el ? $el[0] : undefined,
$backdropEl,
backdropEl: $backdropEl && $backdropEl[0],
type: 'actions',
});
function handleClick(e) {
const target = e.target;
const $target = $(target);
const keyboardOpened = !app.device.desktop && app.device.cordova && ((window.Keyboard && window.Keyboard.isVisible) || (window.cordova.plugins && window.cordova.plugins.Keyboard && window.cordova.plugins.Keyboard.isVisible));
if (keyboardOpened) return;
if ($target.closest(actions.el).length === 0) {
if (
actions.params.closeByBackdropClick
&& actions.params.backdrop
&& actions.backdropEl
&& actions.backdropEl === target
) {
actions.close();
} else if (actions.params.closeByOutsideClick) {
actions.close();
}
}
}
function onKeyDown(e) {
const keyCode = e.keyCode;
if (keyCode === 27 && actions.params.closeOnEscape) {
actions.close();
}
}
if (actions.params.closeOnEscape) {
actions.on('open', () => {
$(document).on('keydown', onKeyDown);
});
actions.on('close', () => {
$(document).off('keydown', onKeyDown);
});
}
actions.on('opened', () => {
if (actions.params.closeByBackdropClick || actions.params.closeByOutsideClick) {
app.on('click', handleClick);
}
});
actions.on('close', () => {
if (actions.params.closeByBackdropClick || actions.params.closeByOutsideClick) {
app.off('click', handleClick);
}
});
if ($el) {
$el[0].f7Modal = actions;
}
return actions;
}
render() {
const actions = this;
if (actions.params.render) return actions.params.render.call(actions, actions);
const { groups } = actions;
const cssClass = actions.params.cssClass;
return `
<div class="actions-modal${actions.params.grid ? ' actions-grid' : ''} ${cssClass || ''}">
${groups.map(group => `<div class="actions-group">
${group.map((button) => {
const buttonClasses = [`actions-${button.label ? 'label' : 'button'}`];
const { color, bg, bold, disabled, label, text, icon } = button;
if (color) buttonClasses.push(`color-${color}`);
if (bg) buttonClasses.push(`bg-color-${bg}`);
if (bold) buttonClasses.push('actions-button-bold');
if (disabled) buttonClasses.push('disabled');
if (label) {
return `<div class="${buttonClasses.join(' ')}">${text}</div>`;
}
return `
<div class="${buttonClasses.join(' ')}">
${icon ? `<div class="actions-button-media">${icon}</div>` : ''}
<div class="actions-button-text">${text}</div>
</div>`.trim();
}).join('')}
</div>`).join('')}
</div>
`.trim();
}
renderPopover() {
const actions = this;
if (actions.params.renderPopover) return actions.params.renderPopover.call(actions, actions);
const { groups } = actions;
const cssClass = actions.params.cssClass;
return `
<div class="popover popover-from-actions ${cssClass || ''}">
<div class="popover-inner">
${groups.map(group => `
<div class="list">
<ul>
${group.map((button) => {
const itemClasses = [];
const { color, bg, bold, disabled, label, text, icon } = button;
if (color) itemClasses.push(`color-${color}`);
if (bg) itemClasses.push(`bg-color-${bg}`);
if (bold) itemClasses.push('popover-from-actions-bold');
if (disabled) itemClasses.push('disabled');
if (label) {
itemClasses.push('popover-from-actions-label');
return `<li class="${itemClasses.join(' ')}">${text}</li>`;
}
if (icon) {
itemClasses.push('item-link item-content');
return `
<li>
<a class="${itemClasses.join(' ')}">
<div class="item-media">
${icon}
</div>
<div class="item-inner">
<div class="item-title">
${text}
</div>
</div>
</a>
</li>
`;
}
itemClasses.push('list-button');
return `
<li>
<a class="${itemClasses.join(' ')}">${text}</a>
</li>
`;
}).join('')}
</ul>
</div>
`).join('')}
</div>
</div>
`.trim();
}
}
export default Actions;