Files
david/src/widgets/popup/Popup.js
T
2025-12-02 02:06:05 +02:00

246 lines
4.5 KiB
JavaScript

import './popup.css';
import { Ut } from '../../utils/Ut';
import { El } from '../../utils/dom';
import { Overlay } from '../overlay';
import { Stack } from '../../core/Stack';
import { Render } from '../../core/Render';
////////////////////
// Popup Widget
////////////////////
export class Popup {
/**
* Popup, Constructor
*/
constructor(target, opts) {
let that = this;
this.target = target;
if (this.target.dxData('popup')) {
return;
}
this.target.dxData('popup', this);
this.opts = { ... {
scrollBar : true,
marginTop : 50,
marginBottom : 50,
multiple : false,
width : 800,
height : 'auto',
modal : true,
cls : null
}, ... opts };
this.opened = false;
if (!this.opts.multiple) {
Stack.widgets.Popup?.forEach((popup, key) => {
if (key == this.ekey - 1) {
that.opened = true;
popup.destroy(_ => that.init());
}
else {
popup.destroy();
}
});
}
if (!this.opened) {
this.opened = true;
this.init();
}
}
/**
* Popup, Init
*/
init() {
Stack.add(this);
this._plugins = [];
this.create();
this.setEvents();
}
/**
* Popup, Create
*/
create() {
this.card = {
ui: Render.makeCardElement({
title: this.opts.title || this.target.dataset.title,
descr: this.opts.descr || this.target.dataset.descr,
scrollbar : this.opts.scrollBar || this.target.scrollbar
}, null)
};
this.card.toolbar = this.card.ui.dxFind('.top-bar-inner');
this.card.container = this.card.ui.dxFind('.container');
this.target.classList.add('popup-container');
this.card.container.append(this.target);
if (this.opts.toolbar) {
if (!this.card.toolbar) {
this.card.toolbar = El('div', { className: 'top-bar-inner' });
this.card.ui.prepend(El('div', { className: 'top-bar' }, this.card.toolbar));
}
this.card.toolbar.append(this.opts.toolbar);
}
if (this.card.toolbar) {
this.card.toolbar.append( El('a', { className: 'ic-close' }) );
}
this.card.ui.classList.add('sp-popup');
if (this.opts.cls) {
this.card.ui.classList.add(this.opts.cls);
}
this.card.ui.style.width = this.opts.width + 'px';
this.card.container.style.height = this.opts.height + 'px';
if (this.opts.scrollBar) {
this.card.container.classList.add('sp-scrollbar');
}
this.scrollTop = window.screenY;
if (Ut.device.isMobile) {
document.body.dxCss({ position: 'fixed', top: '-' + this.scrollTop + 'px' })
}
document.body.append(this.card.ui);
if (this.opts.modal) {
Overlay.showModal(this.card.ui);
}
this.resize();
this.card.ui.dxCss({ top: this.opts.marginTop + 'px', opacity: 1 });
Ut.trigger(this.opts.onInit, this);
}
/**
* Popup, Set Title
*/
setTitle(text) {
let title = this.card.toolbar.dxFind('h2.title');
title.textContent = text;
title.classList.remove('hide');
}
/**
* Popup, resize
*/
resize() {
if (this.opts.scrollBar) {
this.card.container.dxCss('max-height',
( window.innerHeight - this.card.toolbar.clientHeight - this.opts.marginTop - this.opts.marginBottom )
+ 'px'
);
}
Ut.trigger(this.opts.onResize,
this,
this.card.container.clientWidth,
this.card.container.clientHeight
);
}
/**
* Popup, Set Events
*/
setEvents() {
let that = this;
if (this.opts.scrollBar) {
let tm = null;
window.dxOn('resize.popup' + this.ekey + ' orientationchange.popup' + this.ekey, function() {
if (tm) {
clearTimeout(tm);
tm = null;
}
tm = setTimeout(function() {
that.resize();
}, 300);
});
}
this.card.toolbar.dxOn('click', '.ic-close', function() {
that.destroy();
});
document.dxOn('keyup.popup' + this.ekey, function(e) {
if (e.key == 'Escape') {
that.destroy();
}
});
}
/**
* Popup, Destroy
*/
destroy(callback) {
const that = this;
this.card.ui.addEventListener('transitionend', function(e) {
document.dxOff('keyup.popup' + that.ekey + ' resize.popup' + that.ekey + ' orientationchange.popup' + that.ekey);
if (that.opts.modal) {
Overlay.hideModal(that.card.ui);
}
that.card.ui.remove();
if (Ut.device.isMobile) {
document.body.dxCss({ position: '', top: '' });
document.body.scrollTop = that.scrollTop;
}
that._plugins.forEach(widget => widget.destroy());
Stack.delete(this);
that.target.dxRemoveData('popup');
Ut.trigger(callback);
Ut.trigger(that.opts.onDestroy);
}, {
once: true
});
this.card.ui.dxCss({ top: '-25%', opacity: 0 });
}
}