Eduard Kuzmenko
2 years ago
32 changed files with 690 additions and 174 deletions
@ -0,0 +1,113 @@ |
|||||||
|
/* |
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/ |
||||||
|
|
||||||
|
import ButtonMenu, {ButtonMenuItemOptions} from '../../components/buttonMenu'; |
||||||
|
import filterAsync from '../array/filterAsync'; |
||||||
|
import contextMenuController from '../contextMenuController'; |
||||||
|
import ListenerSetter from '../listenerSetter'; |
||||||
|
import {getMiddleware} from '../middleware'; |
||||||
|
import positionMenu from '../positionMenu'; |
||||||
|
import {attachContextMenuListener} from './attachContextMenuListener'; |
||||||
|
|
||||||
|
export default function createContextMenu<T extends ButtonMenuItemOptions & {verify?: () => boolean | Promise<boolean>}>({ |
||||||
|
buttons, |
||||||
|
findElement, |
||||||
|
listenTo, |
||||||
|
appendTo, |
||||||
|
filterButtons, |
||||||
|
onOpen, |
||||||
|
onClose |
||||||
|
}: { |
||||||
|
buttons: T[], |
||||||
|
findElement: (e: MouseEvent) => HTMLElement, |
||||||
|
listenTo: HTMLElement, |
||||||
|
appendTo?: HTMLElement, |
||||||
|
filterButtons?: (buttons: T[]) => Promise<T[]>, |
||||||
|
onOpen?: (target: HTMLElement) => any, |
||||||
|
onClose?: () => any |
||||||
|
}) { |
||||||
|
appendTo ??= document.body; |
||||||
|
|
||||||
|
const attachListenerSetter = new ListenerSetter(); |
||||||
|
const listenerSetter = new ListenerSetter(); |
||||||
|
const middleware = getMiddleware(); |
||||||
|
let element: HTMLElement; |
||||||
|
|
||||||
|
attachContextMenuListener(listenTo, (e) => { |
||||||
|
const target = findElement(e as any); |
||||||
|
if(!target) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
let _element = element; |
||||||
|
if(e instanceof MouseEvent || e.hasOwnProperty('preventDefault')) (e as any).preventDefault(); |
||||||
|
if(_element && _element.classList.contains('active')) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if(e instanceof MouseEvent || e.hasOwnProperty('cancelBubble')) (e as any).cancelBubble = true; |
||||||
|
|
||||||
|
const r = async() => { |
||||||
|
await onOpen?.(target); |
||||||
|
|
||||||
|
const initResult = await init(); |
||||||
|
if(!initResult) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
_element = initResult.element; |
||||||
|
const {cleanup, destroy} = initResult; |
||||||
|
|
||||||
|
positionMenu(e, _element); |
||||||
|
contextMenuController.openBtnMenu(_element, () => { |
||||||
|
onClose?.(); |
||||||
|
cleanup(); |
||||||
|
|
||||||
|
setTimeout(() => { |
||||||
|
destroy(); |
||||||
|
}, 300); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
r(); |
||||||
|
}, attachListenerSetter); |
||||||
|
|
||||||
|
const cleanup = () => { |
||||||
|
listenerSetter.removeAll(); |
||||||
|
middleware.clean(); |
||||||
|
}; |
||||||
|
|
||||||
|
const destroy = () => { |
||||||
|
cleanup(); |
||||||
|
attachListenerSetter.removeAll(); |
||||||
|
}; |
||||||
|
|
||||||
|
const init = async() => { |
||||||
|
cleanup(); |
||||||
|
|
||||||
|
buttons.forEach((button) => button.element = undefined); |
||||||
|
const f = filterButtons || ((buttons: T[]) => filterAsync(buttons, (button) => button?.verify?.() ?? true)); |
||||||
|
|
||||||
|
const filteredButtons = await f(buttons); |
||||||
|
if(!filteredButtons.length) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const _element = element = ButtonMenu(filteredButtons, listenerSetter); |
||||||
|
_element.classList.add('contextmenu'); |
||||||
|
|
||||||
|
appendTo.append(_element); |
||||||
|
|
||||||
|
return { |
||||||
|
element: _element, |
||||||
|
cleanup, |
||||||
|
destroy: () => { |
||||||
|
_element.remove(); |
||||||
|
} |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
return {element, destroy}; |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/* |
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/ |
||||||
|
|
||||||
|
import type {MyDocument} from '../../lib/appManagers/appDocsManager'; |
||||||
|
import PopupStickers from '../../components/popups/stickers'; |
||||||
|
import appImManager from '../../lib/appManagers/appImManager'; |
||||||
|
import rootScope from '../../lib/rootScope'; |
||||||
|
import createContextMenu from './createContextMenu'; |
||||||
|
import findUpClassName from './findUpClassName'; |
||||||
|
import emoticonsDropdown, {EmoticonsDropdown} from '../../components/emoticonsDropdown'; |
||||||
|
|
||||||
|
export default function createStickersContextMenu(options: { |
||||||
|
listenTo: HTMLElement, |
||||||
|
isStickerPack?: boolean, |
||||||
|
verifyRecent?: (target: HTMLElement) => boolean, |
||||||
|
appendTo?: HTMLElement, |
||||||
|
onOpen?: () => any, |
||||||
|
onClose?: () => any |
||||||
|
}) { |
||||||
|
const {listenTo, isStickerPack, verifyRecent, appendTo, onOpen, onClose} = options; |
||||||
|
let target: HTMLElement, doc: MyDocument; |
||||||
|
const verifyFavoriteSticker = async(toAdd: boolean) => { |
||||||
|
const favedStickers = await rootScope.managers.acknowledged.appStickersManager.getFavedStickersStickers(); |
||||||
|
if(!favedStickers.cached) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
const found = (await favedStickers.result).some((_doc) => _doc.id === doc.id); |
||||||
|
return toAdd ? !found : found; |
||||||
|
}; |
||||||
|
|
||||||
|
return createContextMenu({ |
||||||
|
listenTo: listenTo, |
||||||
|
appendTo, |
||||||
|
findElement: (e) => target = findUpClassName(e.target, 'media-sticker-wrapper'), |
||||||
|
onOpen: async() => { |
||||||
|
doc = await rootScope.managers.appDocsManager.getDoc(target.dataset.docId); |
||||||
|
return onOpen?.(); |
||||||
|
}, |
||||||
|
onClose, |
||||||
|
buttons: [{ |
||||||
|
icon: 'stickers', |
||||||
|
text: 'Context.ViewStickerSet', |
||||||
|
onClick: () => new PopupStickers(doc.stickerSetInput).show(), |
||||||
|
verify: () => !isStickerPack |
||||||
|
}, { |
||||||
|
icon: 'favourites', |
||||||
|
text: 'AddToFavorites', |
||||||
|
onClick: () => rootScope.managers.appStickersManager.faveSticker(doc.id, false), |
||||||
|
verify: () => verifyFavoriteSticker(true) |
||||||
|
}, { |
||||||
|
icon: 'favourites', |
||||||
|
text: 'DeleteFromFavorites', |
||||||
|
onClick: () => rootScope.managers.appStickersManager.faveSticker(doc.id, true), |
||||||
|
verify: () => verifyFavoriteSticker(false) |
||||||
|
}, { |
||||||
|
icon: 'delete', |
||||||
|
text: 'DeleteFromRecent', |
||||||
|
onClick: () => emoticonsDropdown.stickersTab.deleteRecentSticker(doc), |
||||||
|
verify: () => verifyRecent?.(target) ?? false |
||||||
|
}, { |
||||||
|
icon: 'mute', |
||||||
|
text: 'Chat.Send.WithoutSound', |
||||||
|
onClick: () => EmoticonsDropdown.sendDocId(doc.id, false, true), |
||||||
|
verify: () => !!(appImManager.chat.peerId && appImManager.chat.peerId !== rootScope.myId) |
||||||
|
}, { |
||||||
|
icon: 'schedule', |
||||||
|
text: 'Chat.Send.ScheduledMessage', |
||||||
|
onClick: () => appImManager.chat.input.scheduleSending(() => appImManager.chat.input.sendMessageWithDocument(doc)), |
||||||
|
verify: () => !!appImManager.chat.peerId |
||||||
|
}] |
||||||
|
}); |
||||||
|
} |
@ -1,17 +1,11 @@ |
|||||||
/* |
import {InputDocument} from '../../../../layer'; |
||||||
* https://github.com/morethanwords/tweb
|
import type {MyDocument} from '../../appDocsManager'; |
||||||
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
export default function getDocumentInput(doc: MyDocument): InputDocument { |
||||||
*/ |
return { |
||||||
|
_: 'inputDocument', |
||||||
import {Document, InputFileLocation} from '../../../../layer'; |
id: doc.id, |
||||||
|
access_hash: doc.access_hash, |
||||||
export default function getInput(doc: Document.document, thumbSize?: string): InputFileLocation.inputDocumentFileLocation { |
file_reference: doc.file_reference |
||||||
return { |
}; |
||||||
_: 'inputDocumentFileLocation', |
} |
||||||
id: doc.id, |
|
||||||
access_hash: doc.access_hash, |
|
||||||
file_reference: doc.file_reference, |
|
||||||
thumb_size: thumbSize |
|
||||||
}; |
|
||||||
} |
|
||||||
|
@ -0,0 +1,17 @@ |
|||||||
|
/* |
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/ |
||||||
|
|
||||||
|
import {Document, InputFileLocation} from '../../../../layer'; |
||||||
|
|
||||||
|
export default function getDocumentInputFileLocation(doc: Document.document, thumbSize?: string): InputFileLocation.inputDocumentFileLocation { |
||||||
|
return { |
||||||
|
_: 'inputDocumentFileLocation', |
||||||
|
id: doc.id, |
||||||
|
access_hash: doc.access_hash, |
||||||
|
file_reference: doc.file_reference, |
||||||
|
thumb_size: thumbSize |
||||||
|
}; |
||||||
|
} |
Loading…
Reference in new issue