|
|
|
/*
|
|
|
|
* https://github.com/morethanwords/tweb
|
|
|
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
|
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
|
|
|
*/
|
|
|
|
|
|
|
|
import type ChatInput from "./input";
|
|
|
|
import DropdownHover from "../../helpers/dropdownHover";
|
|
|
|
import { KeyboardButton, ReplyMarkup } from "../../layer";
|
|
|
|
import rootScope from "../../lib/rootScope";
|
|
|
|
import ListenerSetter, { Listener } from "../../helpers/listenerSetter";
|
|
|
|
import findUpClassName from "../../helpers/dom/findUpClassName";
|
|
|
|
import IS_TOUCH_SUPPORTED from "../../environment/touchSupport";
|
|
|
|
import findUpAsChild from "../../helpers/dom/findUpAsChild";
|
|
|
|
import cancelEvent from "../../helpers/dom/cancelEvent";
|
|
|
|
import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck";
|
|
|
|
import confirmationPopup from "../confirmationPopup";
|
|
|
|
import safeAssign from "../../helpers/object/safeAssign";
|
|
|
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
|
|
|
import wrapEmojiText from "../../lib/richTextProcessor/wrapEmojiText";
|
|
|
|
import { AppManagers } from "../../lib/appManagers/managers";
|
|
|
|
|
|
|
|
export default class ReplyKeyboard extends DropdownHover {
|
|
|
|
private static BASE_CLASS = 'reply-keyboard';
|
|
|
|
private appendTo: HTMLElement;
|
|
|
|
private listenerSetter: ListenerSetter;
|
|
|
|
private managers: AppManagers;
|
|
|
|
private btnHover: HTMLElement;
|
|
|
|
private peerId: PeerId;
|
|
|
|
private touchListener: Listener;
|
|
|
|
private chatInput: ChatInput;
|
|
|
|
|
|
|
|
constructor(options: {
|
|
|
|
listenerSetter: ListenerSetter,
|
|
|
|
managers: AppManagers,
|
|
|
|
appendTo: HTMLElement,
|
|
|
|
btnHover: HTMLElement,
|
|
|
|
chatInput: ChatInput
|
|
|
|
}) {
|
|
|
|
super({
|
|
|
|
element: document.createElement('div')
|
|
|
|
});
|
|
|
|
|
|
|
|
safeAssign(this, options);
|
|
|
|
|
|
|
|
this.element.classList.add(ReplyKeyboard.BASE_CLASS);
|
|
|
|
this.element.style.display = 'none';
|
|
|
|
|
|
|
|
this.attachButtonListener(this.btnHover, this.listenerSetter);
|
|
|
|
this.listenerSetter.add(rootScope)('history_reply_markup', async({peerId}) => {
|
|
|
|
if(this.peerId === peerId) {
|
|
|
|
if(this.checkAvailability() && this.isActive()) {
|
|
|
|
await this.render();
|
|
|
|
}
|
|
|
|
|
|
|
|
getHeavyAnimationPromise().then(() => {
|
|
|
|
this.checkForceReply();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
protected init() {
|
|
|
|
this.appendTo.append(this.element);
|
|
|
|
|
|
|
|
this.listenerSetter.add(this)('open', async() => {
|
|
|
|
await this.render();
|
|
|
|
|
|
|
|
if(IS_TOUCH_SUPPORTED) {
|
|
|
|
this.touchListener = this.listenerSetter.add(document.body)('touchstart', this.onBodyTouchStart, {passive: false, capture: true}) as any as Listener;
|
|
|
|
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) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const type = target.dataset.type as KeyboardButton['_'];
|
|
|
|
const {peerId} = this;
|
|
|
|
switch(type) {
|
|
|
|
case 'keyboardButtonRequestPhone': {
|
|
|
|
confirmationPopup({
|
|
|
|
titleLangKey: 'ShareYouPhoneNumberTitle',
|
|
|
|
button: {
|
|
|
|
langKey: 'OK'
|
|
|
|
},
|
|
|
|
descriptionLangKey: 'AreYouSureShareMyContactInfoBot'
|
|
|
|
}).then(() => {
|
|
|
|
this.managers.appMessagesManager.sendContact(peerId, rootScope.myId);
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: {
|
|
|
|
this.managers.appMessagesManager.sendText(peerId, target.dataset.text);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.toggle(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
public async checkForceReply() {
|
|
|
|
const replyMarkup = await this.getReplyMarkup();
|
|
|
|
if(replyMarkup._ === 'replyKeyboardForceReply' &&
|
|
|
|
!replyMarkup.pFlags.hidden &&
|
|
|
|
!replyMarkup.pFlags.used) {
|
|
|
|
replyMarkup.pFlags.used = true;
|
|
|
|
this.chatInput.initMessageReply(replyMarkup.mid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private async getReplyMarkup() {
|
|
|
|
return (await this.managers.appMessagesManager.getHistoryStorageTransferable(this.peerId)).replyMarkup ?? {
|
|
|
|
_: 'replyKeyboardHide'
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public async render(replyMarkup?: ReplyMarkup.replyKeyboardMarkup) {
|
|
|
|
if(replyMarkup === undefined) {
|
|
|
|
replyMarkup = await this.getReplyMarkup() as any;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.element.textContent = '';
|
|
|
|
|
|
|
|
for(const row of replyMarkup.rows) {
|
|
|
|
const div = document.createElement('div');
|
|
|
|
div.classList.add(ReplyKeyboard.BASE_CLASS + '-row');
|
|
|
|
|
|
|
|
for(const button of row.buttons) {
|
|
|
|
const btn = document.createElement('button');
|
|
|
|
btn.classList.add(ReplyKeyboard.BASE_CLASS + '-button', 'btn');
|
|
|
|
setInnerHTML(btn, wrapEmojiText(button.text));
|
|
|
|
btn.dataset.text = button.text;
|
|
|
|
btn.dataset.type = button._;
|
|
|
|
div.append(btn);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.element.append(div);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public async checkAvailability(replyMarkup?: ReplyMarkup) {
|
|
|
|
if(replyMarkup === undefined) {
|
|
|
|
replyMarkup = await this.getReplyMarkup();
|
|
|
|
}
|
|
|
|
|
|
|
|
const hide = replyMarkup._ === 'replyKeyboardHide' || !(replyMarkup as ReplyMarkup.replyInlineMarkup).rows?.length;
|
|
|
|
this.btnHover.classList.toggle('hide', hide);
|
|
|
|
|
|
|
|
if(hide) {
|
|
|
|
this.toggle(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return !hide;
|
|
|
|
}
|
|
|
|
|
|
|
|
public setPeer(peerId: PeerId) {
|
|
|
|
this.peerId = peerId;
|
|
|
|
|
|
|
|
this.checkAvailability();
|
|
|
|
this.checkForceReply();
|
|
|
|
}
|
|
|
|
}
|