diff --git a/src/components/chat/replyKeyboard.ts b/src/components/chat/replyKeyboard.ts index b82a4a97..d5923f67 100644 --- a/src/components/chat/replyKeyboard.ts +++ b/src/components/chat/replyKeyboard.ts @@ -10,8 +10,11 @@ import { ReplyMarkup } from "../../layer"; import RichTextProcessor from "../../lib/richtextprocessor"; import rootScope from "../../lib/rootScope"; import { safeAssign } from "../../helpers/object"; -import ListenerSetter from "../../helpers/listenerSetter"; +import ListenerSetter, { Listener } from "../../helpers/listenerSetter"; import findUpClassName from "../../helpers/dom/findUpClassName"; +import { isTouchSupported } from "../../helpers/touchSupport"; +import findUpAsChild from "../../helpers/dom/findUpAsChild"; +import { cancelEvent } from "../../helpers/dom/cancelEvent"; export default class ReplyKeyboard extends DropdownHover { private static BASE_CLASS = 'reply-keyboard'; @@ -20,6 +23,7 @@ export default class ReplyKeyboard extends DropdownHover { private appMessagesManager: AppMessagesManager; private btnHover: HTMLElement; private peerId: number; + private touchListener: Listener; constructor(options: { listenerSetter: ListenerSetter, @@ -49,8 +53,15 @@ export default class ReplyKeyboard extends DropdownHover { this.listenerSetter.add(this, 'open', () => { this.render(); - }); + if(isTouchSupported) { + this.touchListener = this.listenerSetter.add(document.body, 'touchstart', this.onBodyTouchStart, {passive: false, capture: true}); + this.listenerSetter.add(this, 'close', () => { + this.listenerSetter.remove(this.touchListener); + }, {once: true}); + } + }); + this.listenerSetter.add(this.element, 'click', (e) => { const target = findUpClassName(e.target, 'btn'); if(!target) { @@ -64,6 +75,14 @@ export default class ReplyKeyboard extends DropdownHover { return super.init(); } + private onBodyTouchStart = (e: TouchEvent) => { + const target = e.touches[0].target as HTMLElement; + if(!findUpAsChild(target, this.element) && target !== this.btnHover) { + cancelEvent(e); + this.toggle(false); + } + }; + private getReplyMarkup(): ReplyMarkup { return this.appMessagesManager.getHistoryStorage(this.peerId).reply_markup ?? { _: 'replyKeyboardHide' diff --git a/src/helpers/listenerSetter.ts b/src/helpers/listenerSetter.ts index ad3aa85c..0fc62305 100644 --- a/src/helpers/listenerSetter.ts +++ b/src/helpers/listenerSetter.ts @@ -22,7 +22,10 @@ export type Listener = { element: ListenerElement, event: ListenerEvent, callback: ListenerCallback, - options?: ListenerOptions + options?: ListenerOptions, + + onceFired?: true, // will be set only when options.once is set + onceCallback?: () => void, }; export type ListenerElement = Window | Document | HTMLElement | Element | RootScope | any; @@ -43,12 +46,31 @@ export default class ListenerSetter { public addManual(listener: Listener) { // @ts-ignore listener.element.addEventListener(listener.event, listener.callback, listener.options); + + if(listener.options?.once) { // remove listener when its called + listener.onceCallback = () => { + this.remove(listener); + listener.onceFired = true; + }; + + // @ts-ignore + listener.element.addEventListener(listener.event, listener.onceCallback, listener.options); + } + this.listeners.add(listener); } public remove(listener: Listener) { - // @ts-ignore - listener.element.removeEventListener(listener.event, listener.callback, listener.options); + if(!listener.onceFired) { + // @ts-ignore + listener.element.removeEventListener(listener.event, listener.callback, listener.options); + + if(listener.onceCallback) { + // @ts-ignore + listener.element.removeEventListener(listener.event, listener.onceCallback, listener.options); + } + } + this.listeners.delete(listener); } diff --git a/src/scss/partials/_replyKeyboard.scss b/src/scss/partials/_replyKeyboard.scss index ba2f6834..6873ad17 100644 --- a/src/scss/partials/_replyKeyboard.scss +++ b/src/scss/partials/_replyKeyboard.scss @@ -4,6 +4,7 @@ right: 0; bottom: calc(100% + .625rem); width: 26.25rem !important; + max-width: 100%; //height: 26.25rem; max-height: 26.25rem; box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, .14);