tweb/src/components/popups/index.ts

185 lines
5.2 KiB
TypeScript
Raw Normal View History

2021-04-08 15:52:31 +02:00
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import rootScope from "../../lib/rootScope";
2021-04-04 17:39:17 +02:00
import { blurActiveElement } from "../../helpers/dom";
import { ripple } from "../ripple";
import animationIntersector from "../animationIntersector";
2021-02-18 13:11:16 +01:00
import appNavigationController, { NavigationItem } from "../appNavigationController";
2021-03-23 17:13:35 +01:00
import { i18n, LangPackKey } from "../../lib/langPack";
2021-04-04 17:39:17 +02:00
import findUpClassName from "../../helpers/dom/findUpClassName";
2021-02-19 16:27:56 +01:00
export type PopupButton = {
2021-03-23 17:13:35 +01:00
text?: string,
2021-02-19 16:27:56 +01:00
callback?: () => void,
2021-03-23 17:13:35 +01:00
langKey?: LangPackKey,
langArgs?: any[],
2021-02-19 16:27:56 +01:00
isDanger?: true,
isCancel?: true
};
export type PopupOptions = Partial<{
closable: true,
overlayClosable: true,
2021-04-04 17:39:17 +02:00
withConfirm: LangPackKey | true,
2021-02-19 16:27:56 +01:00
body: true
}>;
export default class PopupElement {
protected element = document.createElement('div');
protected container = document.createElement('div');
protected header = document.createElement('div');
protected title = document.createElement('div');
protected btnClose: HTMLElement;
protected btnConfirm: HTMLElement;
2020-06-16 22:48:08 +02:00
protected body: HTMLElement;
2020-06-16 22:48:08 +02:00
protected onClose: () => void;
protected onCloseAfterTimeout: () => void;
protected onEscape: () => boolean = () => true;
2020-06-16 22:48:08 +02:00
2021-02-18 13:11:16 +01:00
protected navigationItem: NavigationItem;
constructor(className: string, buttons?: Array<PopupButton>, options: PopupOptions = {}) {
this.element.classList.add('popup');
this.element.className = 'popup' + (className ? ' ' + className : '');
this.container.classList.add('popup-container', 'z-depth-1');
this.header.classList.add('popup-header');
this.title.classList.add('popup-title');
this.header.append(this.title);
2020-06-16 22:48:08 +02:00
if(options.closable) {
this.btnClose = document.createElement('span');
this.btnClose.classList.add('btn-icon', 'popup-close', 'tgico-close');
//ripple(this.closeBtn);
this.header.prepend(this.btnClose);
2020-06-16 22:48:08 +02:00
2021-02-18 13:11:16 +01:00
this.btnClose.addEventListener('click', this.hide, {once: true});
2021-03-01 20:49:36 +01:00
}
2021-03-01 20:49:36 +01:00
if(options.overlayClosable) {
const onOverlayClick = (e: MouseEvent) => {
if(!findUpClassName(e.target, 'popup-container')) {
this.hide();
this.element.removeEventListener('click', onOverlayClick);
}
};
this.element.addEventListener('click', onOverlayClick);
2020-06-16 22:48:08 +02:00
}
if(options.withConfirm) {
this.btnConfirm = document.createElement('button');
2021-02-20 18:10:26 +01:00
this.btnConfirm.classList.add('btn-primary', 'btn-color-primary');
2021-04-04 17:39:17 +02:00
if(options.withConfirm !== true) {
this.btnConfirm.append(i18n(options.withConfirm));
}
this.header.append(this.btnConfirm);
ripple(this.btnConfirm);
2020-06-16 22:48:08 +02:00
}
this.container.append(this.header);
2020-06-16 22:48:08 +02:00
if(options.body) {
this.body = document.createElement('div');
this.body.classList.add('popup-body');
this.container.append(this.body);
}
if(buttons && buttons.length) {
const buttonsDiv = document.createElement('div');
buttonsDiv.classList.add('popup-buttons');
if(buttons.length === 2) {
buttonsDiv.classList.add('popup-buttons-row');
}
const buttonsElements = buttons.map(b => {
const button = document.createElement('button');
button.className = 'btn' + (b.isDanger ? ' danger' : ' primary');
2021-03-23 17:13:35 +01:00
ripple(button);
2021-03-23 17:13:35 +01:00
if(b.text) {
button.innerHTML = b.text;
} else {
button.append(i18n(b.langKey, b.langArgs));
}
if(b.callback) {
button.addEventListener('click', () => {
b.callback();
this.destroy();
}, {once: true});
} else if(b.isCancel) {
button.addEventListener('click', () => {
this.destroy();
}, {once: true});
}
return button;
});
buttonsDiv.append(...buttonsElements);
this.container.append(buttonsDiv);
}
this.element.append(this.container);
}
public show() {
2021-02-18 13:11:16 +01:00
this.navigationItem = {
type: 'popup',
onPop: this.destroy,
onEscape: this.onEscape
};
appNavigationController.pushItem(this.navigationItem);
blurActiveElement(); // * hide mobile keyboard
document.body.append(this.element);
void this.element.offsetWidth; // reflow
this.element.classList.add('active');
2020-11-15 04:33:47 +01:00
rootScope.overlayIsActive = true;
animationIntersector.checkAnimations(true);
}
2021-02-18 13:11:16 +01:00
public hide = () => {
appNavigationController.back('popup');
2021-02-18 13:11:16 +01:00
};
private destroy = () => {
2020-06-16 22:48:08 +02:00
this.onClose && this.onClose();
this.element.classList.add('hiding');
this.element.classList.remove('active');
2021-02-18 13:11:16 +01:00
if(this.btnClose) this.btnClose.removeEventListener('click', this.hide);
2020-11-15 04:33:47 +01:00
rootScope.overlayIsActive = false;
2021-02-18 13:11:16 +01:00
appNavigationController.removeItem(this.navigationItem);
this.navigationItem = undefined;
setTimeout(() => {
this.element.remove();
2020-06-16 22:48:08 +02:00
this.onCloseAfterTimeout && this.onCloseAfterTimeout();
animationIntersector.checkAnimations(false);
}, 150);
};
}
2021-02-19 16:27:56 +01:00
export const addCancelButton = (buttons: PopupButton[]) => {
const button = buttons.find(b => b.isCancel);
if(!button) {
buttons.push({
2021-03-23 17:13:35 +01:00
langKey: 'Cancel',
2021-02-19 16:27:56 +01:00
isCancel: true
});
}
return buttons;
};