|
|
|
/*
|
|
|
|
* https://github.com/morethanwords/tweb
|
|
|
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
|
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
|
|
|
*/
|
|
|
|
|
|
|
|
import type Chat from "./chat";
|
|
|
|
import type ChatTopbar from "./topbar";
|
|
|
|
import mediaSizes from "../../helpers/mediaSizes";
|
|
|
|
import DivAndCaption from "../divAndCaption";
|
|
|
|
import { ripple } from "../ripple";
|
|
|
|
import ListenerSetter from "../../helpers/listenerSetter";
|
|
|
|
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
|
|
|
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
|
|
|
import { safeAssign } from "../../helpers/object";
|
|
|
|
import { Message } from "../../layer";
|
|
|
|
|
|
|
|
const classNames: string[] = ['is-pinned-message-shown', 'is-pinned-audio-shown'];
|
|
|
|
const CLASSNAME_BASE = 'pinned-container';
|
|
|
|
const HEIGHT = 52;
|
|
|
|
|
|
|
|
export default class PinnedContainer {
|
|
|
|
public wrapperUtils: HTMLElement;
|
|
|
|
public btnClose: HTMLElement;
|
|
|
|
protected wrapper: HTMLElement;
|
|
|
|
|
|
|
|
protected topbar: ChatTopbar;
|
|
|
|
protected chat: Chat;
|
|
|
|
protected listenerSetter: ListenerSetter;
|
|
|
|
public className: string;
|
|
|
|
public divAndCaption: DivAndCaption<(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message?: any) => void>;
|
|
|
|
|
|
|
|
protected floating = false;
|
|
|
|
|
|
|
|
protected onClose?: () => void | Promise<boolean>;
|
|
|
|
|
|
|
|
constructor(options: {
|
|
|
|
topbar: PinnedContainer['topbar'],
|
|
|
|
chat: PinnedContainer['chat'],
|
|
|
|
listenerSetter: PinnedContainer['listenerSetter'],
|
|
|
|
className: PinnedContainer['className'],
|
|
|
|
divAndCaption: PinnedContainer['divAndCaption'],
|
|
|
|
onClose?: PinnedContainer['onClose'],
|
|
|
|
floating?: PinnedContainer['floating']
|
|
|
|
}) {
|
|
|
|
safeAssign(this, options);
|
|
|
|
|
|
|
|
const {divAndCaption, className, onClose} = this;
|
|
|
|
divAndCaption.container.classList.add(CLASSNAME_BASE, 'hide');
|
|
|
|
divAndCaption.title.classList.add(CLASSNAME_BASE + '-title');
|
|
|
|
divAndCaption.subtitle.classList.add(CLASSNAME_BASE + '-subtitle');
|
|
|
|
divAndCaption.content.classList.add(CLASSNAME_BASE + '-content');
|
|
|
|
|
|
|
|
this.btnClose = document.createElement('button');
|
|
|
|
this.btnClose.classList.add(CLASSNAME_BASE + '-close', `pinned-${className}-close`, 'btn-icon', 'tgico-close');
|
|
|
|
|
|
|
|
this.wrapper = document.createElement('div');
|
|
|
|
this.wrapper.classList.add(CLASSNAME_BASE + '-wrapper');
|
|
|
|
ripple(this.wrapper);
|
|
|
|
|
|
|
|
this.wrapperUtils = document.createElement('div');
|
|
|
|
this.wrapperUtils.classList.add(CLASSNAME_BASE + '-wrapper-utils');
|
|
|
|
this.wrapperUtils.append(this.btnClose);
|
|
|
|
|
|
|
|
this.wrapper.append(...Array.from(divAndCaption.container.children), this.wrapperUtils);
|
|
|
|
|
|
|
|
divAndCaption.container.append(this.wrapper/* , this.close */);
|
|
|
|
|
|
|
|
attachClickEvent(this.btnClose, (e) => {
|
|
|
|
cancelEvent(e);
|
|
|
|
|
|
|
|
((onClose ? onClose() : null) || Promise.resolve(true)).then(needClose => {
|
|
|
|
if(needClose) {
|
|
|
|
this.toggle(true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}, {listenerSetter: this.listenerSetter});
|
|
|
|
}
|
|
|
|
|
|
|
|
public toggle(hide?: boolean) {
|
|
|
|
const isHidden = this.divAndCaption.container.classList.contains('hide');
|
|
|
|
if(hide === undefined) {
|
|
|
|
hide = !isHidden;
|
|
|
|
} else if(hide === isHidden) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const scrollable = this.chat.bubbles.scrollable;
|
|
|
|
|
|
|
|
const isFloating = (this.floating || mediaSizes.isMobile) && !hide;
|
|
|
|
const scrollTop = isFloating || this.divAndCaption.container.classList.contains('is-floating') ? scrollable.scrollTop : undefined;
|
|
|
|
|
|
|
|
this.divAndCaption.container.classList.toggle('is-floating', isFloating);
|
|
|
|
this.divAndCaption.container.classList.toggle('hide', hide);
|
|
|
|
|
|
|
|
this.topbar.container.classList.toggle('is-pinned-floating', isFloating);
|
|
|
|
this.topbar.container.classList.toggle(`is-pinned-${this.className}-shown`, !hide);
|
|
|
|
|
|
|
|
const active = classNames.filter(className => this.topbar.container.classList.contains(className));
|
|
|
|
const maxActive = hide ? 0 : 1;
|
|
|
|
|
|
|
|
if(scrollTop !== undefined && active.length <= maxActive/* && !scrollable.isScrolledDown */) {
|
|
|
|
scrollable.scrollTop = scrollTop + ((hide ? -1 : 1) * HEIGHT);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.topbar.setFloating();
|
|
|
|
this.topbar.setUtilsWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
public fill(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message: Message.message) {
|
|
|
|
this.divAndCaption.container.dataset.peerId = '' + message.peerId;
|
|
|
|
this.divAndCaption.container.dataset.mid = '' + message.mid;
|
|
|
|
this.divAndCaption.fill(title, subtitle, message);
|
|
|
|
this.topbar.setUtilsWidth();
|
|
|
|
}
|
|
|
|
}
|