Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
3.5 KiB
129 lines
3.5 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
import contextMenuController from '../helpers/contextMenuController'; |
|
import cancelEvent from '../helpers/dom/cancelEvent'; |
|
import {AttachClickOptions, CLICK_EVENT_NAME, hasMouseMovedSinceDown} from '../helpers/dom/clickEvent'; |
|
import ListenerSetter from '../helpers/listenerSetter'; |
|
import ButtonIcon from './buttonIcon'; |
|
import ButtonMenu, {ButtonMenuItemOptionsVerifiable} from './buttonMenu'; |
|
import filterAsync from '../helpers/array/filterAsync'; |
|
import {doubleRaf} from '../helpers/schedulers'; |
|
|
|
// TODO: refactor for attachClickEvent, because if move finger after touchstart, it will start anyway |
|
export function ButtonMenuToggleHandler({ |
|
el, |
|
onOpen, |
|
options, |
|
onClose |
|
}: { |
|
el: HTMLElement, |
|
onOpen?: (e: Event) => any, |
|
options?: AttachClickOptions, |
|
onClose?: () => void |
|
}) { |
|
const add = options?.listenerSetter ? options.listenerSetter.add(el) : el.addEventListener.bind(el); |
|
|
|
add(CLICK_EVENT_NAME, (e: Event) => { |
|
if(!el.classList.contains('btn-menu-toggle') || hasMouseMovedSinceDown(e)) return false; |
|
|
|
cancelEvent(e); |
|
|
|
if(el.classList.contains('menu-open')) { |
|
contextMenuController.close(); |
|
} else { |
|
const result = onOpen?.(e); |
|
const open = () => { |
|
const openedMenu = el.querySelector('.btn-menu') as HTMLDivElement; |
|
contextMenuController.openBtnMenu(openedMenu, onClose); |
|
}; |
|
|
|
if(result instanceof Promise) { |
|
result.then(open); |
|
} else { |
|
open(); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
export default function ButtonMenuToggle({ |
|
buttonOptions, |
|
listenerSetter: attachListenerSetter, |
|
container, |
|
direction, |
|
buttons, |
|
onOpenBefore, |
|
onOpen, |
|
onClose, |
|
onCloseAfter |
|
}: { |
|
buttonOptions?: Parameters<typeof ButtonIcon>[1], |
|
listenerSetter?: ListenerSetter, |
|
container?: HTMLElement |
|
direction: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right', |
|
buttons: ButtonMenuItemOptionsVerifiable[], |
|
onOpenBefore?: (e: Event) => any, |
|
onOpen?: (e: Event, element: HTMLElement) => any, |
|
onClose?: () => void, |
|
onCloseAfter?: () => void |
|
}) { |
|
if(buttonOptions) { |
|
buttonOptions.asDiv = true; |
|
} |
|
|
|
const button = container ?? ButtonIcon('more', buttonOptions); |
|
button.classList.add('btn-menu-toggle'); |
|
|
|
const listenerSetter = new ListenerSetter(); |
|
|
|
let element: HTMLElement, closeTimeout: number; |
|
ButtonMenuToggleHandler({ |
|
el: button, |
|
onOpen: async(e) => { |
|
await onOpenBefore?.(e); |
|
if(closeTimeout) { |
|
clearTimeout(closeTimeout); |
|
closeTimeout = undefined; |
|
return; |
|
} |
|
|
|
const f = (b: (typeof buttons[0])[]) => filterAsync(b, (button) => button?.verify ? button.verify() ?? false : true); |
|
|
|
const filteredButtons = await f(buttons); |
|
if(!filteredButtons.length) { |
|
return; |
|
} |
|
|
|
const _element = element = await ButtonMenu({ |
|
buttons: filteredButtons, |
|
listenerSetter |
|
}); |
|
_element.classList.add(direction); |
|
|
|
await onOpen?.(e, _element); |
|
|
|
button.append(_element); |
|
await doubleRaf(); |
|
}, |
|
options: { |
|
listenerSetter: attachListenerSetter |
|
}, |
|
onClose: () => { |
|
onClose?.(); |
|
|
|
closeTimeout = window.setTimeout(() => { |
|
onCloseAfter?.(); |
|
closeTimeout = undefined; |
|
listenerSetter.removeAll(); |
|
buttons.forEach((button) => button.element = undefined); |
|
element.remove(); |
|
}, 300); |
|
} |
|
}); |
|
|
|
return button; |
|
}
|
|
|