tweb/src/helpers/dropdownHover.ts
Eduard Kuzmenko d51d50e5c9 Favorite stickers
Stickers context menu
2022-08-18 13:21:19 +02:00

175 lines
4.9 KiB
TypeScript

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import {attachClickEvent} from './dom/clickEvent';
import findUpAsChild from './dom/findUpAsChild';
import EventListenerBase from './eventListenerBase';
import ListenerSetter from './listenerSetter';
import IS_TOUCH_SUPPORTED from '../environment/touchSupport';
import safeAssign from './object/safeAssign';
const KEEP_OPEN = false;
const TOGGLE_TIMEOUT = 200;
const ANIMATION_DURATION = 200;
export default class DropdownHover extends EventListenerBase<{
open: () => Promise<any> | void,
opened: () => any,
close: () => any,
closed: () => any
}> {
protected element: HTMLElement;
protected displayTimeout: number;
protected forceClose = false;
protected inited = false;
protected ignoreMouseOut = false;
constructor(options: {
element: DropdownHover['element']
}) {
super(false);
safeAssign(this, options);
}
public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) {
let firstTime = true;
if(IS_TOUCH_SUPPORTED) {
attachClickEvent(button, () => {
if(firstTime) {
firstTime = false;
this.toggle(true);
} else {
this.toggle();
}
}, {listenerSetter});
} else {
listenerSetter.add(button)('mouseover', (e) => {
// console.log('onmouseover button');
if(firstTime) {
listenerSetter.add(button)('mouseout', (e) => {
clearTimeout(this.displayTimeout);
this.onMouseOut(e);
});
firstTime = false;
}
clearTimeout(this.displayTimeout);
this.displayTimeout = window.setTimeout(() => {
this.toggle(true);
}, TOGGLE_TIMEOUT);
});
}
}
protected onMouseOut = (e: MouseEvent) => {
if(KEEP_OPEN || !this.isActive()) return;
clearTimeout(this.displayTimeout);
if(this.ignoreMouseOut) {
return;
}
const toElement = (e as any).toElement as HTMLElement;
if(toElement && findUpAsChild(toElement, this.element)) {
return;
}
this.displayTimeout = window.setTimeout(() => {
this.toggle(false);
}, TOGGLE_TIMEOUT);
};
protected init() {
if(!IS_TOUCH_SUPPORTED) {
this.element.onmouseout = this.onMouseOut;
this.element.onmouseover = (e) => {
if(this.forceClose) {
return;
}
// console.log('onmouseover element');
clearTimeout(this.displayTimeout);
};
}
}
public toggle = async(enable?: boolean) => {
// if(!this.element) return;
const willBeActive = (!!this.element.style.display && enable === undefined) || enable;
if(this.init) {
if(willBeActive) {
this.init();
this.init = null;
} else {
return;
}
}
if(willBeActive === this.isActive()) {
return;
}
if((this.element.style.display && enable === undefined) || enable) {
const res = this.dispatchResultableEvent('open');
await Promise.all(res);
this.element.style.display = '';
void this.element.offsetLeft; // reflow
this.element.classList.add('active');
clearTimeout(this.displayTimeout);
this.displayTimeout = window.setTimeout(() => {
this.forceClose = false;
this.dispatchEvent('opened');
}, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);
// ! can't use together with resizeObserver
/* if(isTouchSupported) {
const height = this.element.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;
console.log('[ESG]: toggle: enable height', height);
appImManager.chat.bubbles.scrollable.scrollTop += height;
} */
/* if(touchSupport) {
this.restoreScroll();
} */
} else {
this.dispatchEvent('close');
this.element.classList.remove('active');
clearTimeout(this.displayTimeout);
this.displayTimeout = window.setTimeout(() => {
this.element.style.display = 'none';
this.forceClose = false;
this.dispatchEvent('closed');
}, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);
/* if(isTouchSupported) {
const scrollHeight = this.container.scrollHeight;
if(scrollHeight) {
const height = this.container.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;
appImManager.chat.bubbles.scrollable.scrollTop -= height;
}
} */
/* if(touchSupport) {
this.restoreScroll();
} */
}
// animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
};
public isActive() {
return this.element.classList.contains('active');
}
public setIgnoreMouseOut(ignore: boolean) {
this.ignoreMouseOut = ignore;
}
}