import LazyLoadQueue from "../lazyLoadQueue"; import GifsTab from "./tabs/gifs"; import { touchSupport } from "../../lib/config"; import { findUpClassName, findUpTag, whichChild } from "../../lib/utils"; import { horizontalMenu } from "../horizontalMenu"; import animationIntersector from "../animationIntersector"; import appSidebarRight from "../../lib/appManagers/appSidebarRight"; import appImManager from "../../lib/appManagers/appImManager"; import Scrollable, { ScrollableX } from "../scrollable_new"; import EmojiTab from "./tabs/emoji"; import StickersTab from "./tabs/stickers"; import StickyIntersector from "../stickyIntersector"; export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown'; export interface EmoticonsTab { init: () => void, onCloseAfterTimeout?: () => void } const test = false; export class EmoticonsDropdown { public static lazyLoadQueue = new LazyLoadQueue(); private element: HTMLElement; public emojiTab: EmojiTab; public stickersTab: StickersTab; public gifsTab: GifsTab; private container: HTMLElement; private tabsEl: HTMLElement; private tabID = -1; private tabs: {[id: number]: EmoticonsTab}; public searchButton: HTMLElement; public deleteBtn: HTMLElement; public toggleEl: HTMLElement; private displayTimeout: number; public events: { onClose: Array<() => void>, onCloseAfter: Array<() => void>, onOpen: Array<() => void>, onOpenAfter: Array<() => void> } = { onClose: [], onCloseAfter: [], onOpen: [], onOpenAfter: [] }; constructor() { this.element = document.getElementById('emoji-dropdown') as HTMLDivElement; let firstTime = true; this.toggleEl = document.getElementById('toggle-emoticons'); if(touchSupport) { this.toggleEl.addEventListener('click', () => { if(firstTime) { firstTime = false; this.toggle(true); } else { this.toggle(); } }); } else { this.toggleEl.onmouseover = (e) => { clearTimeout(this.displayTimeout); //this.displayTimeout = setTimeout(() => { if(firstTime) { this.toggleEl.onmouseout = this.element.onmouseout = (e) => { if(test) return; if(!this.element.classList.contains('active')) return; const toElement = (e as any).toElement as Element; if(toElement && findUpClassName(toElement, 'emoji-dropdown')) { return; } clearTimeout(this.displayTimeout); this.displayTimeout = window.setTimeout(() => { this.toggle(false); }, 200); }; this.element.onmouseover = (e) => { clearTimeout(this.displayTimeout); }; firstTime = false; } this.toggle(true); //}, 0/* 200 */); }; } } private init() { this.emojiTab = new EmojiTab(); this.stickersTab = new StickersTab(); this.gifsTab = new GifsTab(); this.tabs = { 0: this.emojiTab, 1: this.stickersTab, 2: this.gifsTab }; this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement; this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement; horizontalMenu(this.tabsEl, this.container, (id) => { animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP); this.tabID = id; this.searchButton.classList.toggle('hide', this.tabID == 0); this.deleteBtn.classList.toggle('hide', this.tabID != 0); }, () => { const tab = this.tabs[this.tabID]; if(tab.init) { tab.init(); } tab.onCloseAfterTimeout && tab.onCloseAfterTimeout(); animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP); }); this.searchButton = this.element.querySelector('.emoji-tabs-search'); this.searchButton.addEventListener('click', () => { if(this.tabID == 1) { appSidebarRight.stickersTab.init(); } else { appSidebarRight.gifsTab.init(); } }); this.deleteBtn = this.element.querySelector('.emoji-tabs-delete'); this.deleteBtn.addEventListener('click', () => { const input = appImManager.chatInputC.messageInput; if((input.lastChild as any)?.tagName) { input.lastElementChild.remove(); } else if(input.lastChild) { if(!input.lastChild.textContent.length) { input.lastChild.remove(); } else { input.lastChild.textContent = input.lastChild.textContent.slice(0, -1); } } const event = new Event('input', {bubbles: true, cancelable: true}); appImManager.chatInputC.messageInput.dispatchEvent(event); //appSidebarRight.stickersTab.init(); }); (this.tabsEl.firstElementChild.children[1] as HTMLLIElement).click(); // set emoji tab this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка } 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(touchSupport) { this.toggleEl.classList.toggle('flip-icon', willBeActive); if(willBeActive) { appImManager.chatInputC.saveScroll(); // @ts-ignore document.activeElement.blur(); await new Promise((resolve) => { setTimeout(resolve, 100); }); } } else { this.toggleEl.classList.toggle('active', enable); } if((this.element.style.display && enable === undefined) || enable) { this.events.onOpen.forEach(cb => cb()); EmoticonsDropdown.lazyLoadQueue.lock(); //EmoticonsDropdown.lazyLoadQueue.unlock(); animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP); this.element.style.display = ''; void this.element.offsetLeft; // reflow this.element.classList.add('active'); clearTimeout(this.displayTimeout); this.displayTimeout = window.setTimeout(() => { animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP); EmoticonsDropdown.lazyLoadQueue.unlock(); EmoticonsDropdown.lazyLoadQueue.refresh(); this.events.onOpenAfter.forEach(cb => cb()); }, touchSupport ? 0 : 200); /* if(touchSupport) { this.restoreScroll(); } */ } else { this.events.onClose.forEach(cb => cb()); EmoticonsDropdown.lazyLoadQueue.lock(); //EmoticonsDropdown.lazyLoadQueue.lock(); // нужно залочить группу и выключить стикеры animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP); animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP); this.element.classList.remove('active'); clearTimeout(this.displayTimeout); this.displayTimeout = window.setTimeout(() => { this.element.style.display = 'none'; // теперь можно убрать visible, чтобы они не включились после фокуса animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP); EmoticonsDropdown.lazyLoadQueue.unlock(); EmoticonsDropdown.lazyLoadQueue.refresh(); this.events.onCloseAfter.forEach(cb => cb()); }, touchSupport ? 0 : 200); /* if(touchSupport) { this.restoreScroll(); } */ } //animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP); }; public static menuOnClick = (menu: HTMLUListElement, scroll: Scrollable, menuScroll?: ScrollableX) => { let prevId = 0; let jumpedTo = -1; const setActive = (id: number) => { if(id == prevId) { return false; } menu.children[prevId].classList.remove('active'); menu.children[id].classList.add('active'); prevId = id; return true; }; const stickyIntersector = new StickyIntersector(scroll.container, (stuck, target) => { //console.log('sticky scrollTOp', stuck, target, scroll.container.scrollTop); if(Math.abs(jumpedTo - scroll.container.scrollTop) <= 1) { return; } else { jumpedTo = -1; } const which = whichChild(target); if(!stuck && which) { // * due to stickyIntersector return; } setActive(which); if(menuScroll) { if(which < menu.childElementCount - 4) { menuScroll.container.scrollLeft = (which - 3) * 47; } else { menuScroll.container.scrollLeft = which * 47; } } }); menu.addEventListener('click', (e) => { let target = e.target as HTMLElement; target = findUpTag(target, 'LI'); if(!target) { return; } const which = whichChild(target); if(!setActive(which)) { return; } const element = (scroll.splitUp || scroll.container).children[which] as HTMLElement; const offsetTop = element.offsetTop + 1; // * due to stickyIntersector scroll.container.scrollTop = jumpedTo = offsetTop; //console.log('set scrollTop:', offsetTop); }); return stickyIntersector; }; public static onMediaClick = (e: MouseEvent) => { let target = e.target as HTMLElement; target = findUpTag(target, 'DIV'); if(!target) return; const fileID = target.dataset.docID; if(!fileID) return; if(appImManager.chatInputC.sendMessageWithDocument(fileID)) { /* dropdown.classList.remove('active'); toggleEl.classList.remove('active'); */ emoticonsDropdown.toggle(false); } else { console.warn('got no doc by id:', fileID); } }; } const emoticonsDropdown = new EmoticonsDropdown(); // @ts-ignore if(process.env.NODE_ENV != 'production') { (window as any).emoticonsDropdown = emoticonsDropdown; } export default emoticonsDropdown;