diff --git a/src/components/audio.ts b/src/components/audio.ts index e7f03795..f133fa23 100644 --- a/src/components/audio.ts +++ b/src/components/audio.ts @@ -11,7 +11,7 @@ import { isSafari } from "../helpers/userAgent"; import appMessagesManager from "../lib/appManagers/appMessagesManager"; import rootScope from "../lib/rootScope"; import './middleEllipsis'; -import { cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom"; +import { attachClickEvent, cancelEvent, detachClickEvent } from "../helpers/dom"; rootScope.on('messages_media_read', e => { const mids = e.detail; @@ -214,13 +214,20 @@ function wrapVoiceMessage(doc: MyDocument, audioEl: AudioElement, mid: number) { mousedown = false; } }); - progress.addEventListener(CLICK_EVENT_NAME, (e) => { + attachClickEvent(progress, (e) => { cancelEvent(e); if(!audio.paused) scrub(e); }); function scrub(e: MouseEvent | TouchEvent) { - const offsetX = e instanceof MouseEvent ? e.offsetX : e.changedTouches[0].clientX; + let offsetX: number; + if(e instanceof MouseEvent) { + offsetX = e.offsetX; + } else { // touch + const rect = (e.target as HTMLElement).getBoundingClientRect(); + offsetX = e.targetTouches[0].pageX - rect.left; + } + const scrubTime = offsetX / availW /* width */ * audio.duration; lastIndex = Math.round(scrubTime / audio.duration * barCount); @@ -369,12 +376,12 @@ export default class AudioElement extends HTMLElement { audioTimeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true) + ' / ' + durationStr; } - toggle.addEventListener(CLICK_EVENT_NAME, (e) => { + attachClickEvent(toggle, (e) => { cancelEvent(e); if(audio.paused) audio.play().catch(() => {}); else audio.pause(); }); - + this.addAudioListener('ended', () => { //toggle.classList.add('tgico-largeplay'); toggle.classList.remove('tgico-largepause'); @@ -400,7 +407,10 @@ export default class AudioElement extends HTMLElement { let download: Download; const onClick = (e: Event) => { - cancelEvent(e); + if(e) { + cancelEvent(e); + } + if(!download) { if(!preloader) { preloader = new ProgressivePreloader(null, true); @@ -411,7 +421,7 @@ export default class AudioElement extends HTMLElement { download.then(() => { downloadDiv.remove(); - this.removeEventListener(CLICK_EVENT_NAME, onClick); + detachClickEvent(this, onClick); onLoad(); }).catch(err => { if(err.name === 'AbortError') { @@ -427,8 +437,8 @@ export default class AudioElement extends HTMLElement { } }; - this.addEventListener(CLICK_EVENT_NAME, onClick); - this.click(); + attachClickEvent(this, onClick); + onClick(null); } else { onLoad(false); @@ -437,7 +447,7 @@ export default class AudioElement extends HTMLElement { //} else { const r = (e: Event) => { //onLoad(); - cancelEvent(e); + //cancelEvent(e); appMediaPlaybackController.resolveWaitingForLoadMedia(mid); appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio @@ -469,8 +479,8 @@ export default class AudioElement extends HTMLElement { //}, 10e3); }); }; - - this.addEventListener(CLICK_EVENT_NAME, r, {once: true}); + + attachClickEvent(this, r, {once: true, capture: true, passive: false}); //} } } else { diff --git a/src/components/buttonMenu.ts b/src/components/buttonMenu.ts index f0fffb4b..690a7a1a 100644 --- a/src/components/buttonMenu.ts +++ b/src/components/buttonMenu.ts @@ -1,4 +1,4 @@ -import { cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom"; +import { attachClickEvent, cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom"; import { closeBtnMenu } from "./misc"; import { ripple } from "./ripple"; @@ -13,24 +13,13 @@ const ButtonMenuItem = (options: ButtonMenuItemOptions) => { el.innerText = text; ripple(el); - /* if(options.cancelEvent) { - el.addEventListener(CLICK_EVENT_NAME, (e) => { - cancelEvent(e); - closeBtnMenu(); - options.onClick(e); - }); - } else { - el.addEventListener(CLICK_EVENT_NAME, onClick); - } */ - if(CLICK_EVENT_NAME == 'touchend') { // * cancel keyboard close - el.addEventListener(CLICK_EVENT_NAME, (e) => { - cancelEvent(e); - options.onClick(e); - closeBtnMenu(); - }); - } else { - el.addEventListener(CLICK_EVENT_NAME, onClick); - } + + // * cancel keyboard close + attachClickEvent(el, CLICK_EVENT_NAME == 'touchend' ? (e) => { + cancelEvent(e); + onClick(e); + closeBtnMenu(); + } : onClick); return options.element = el; }; diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts index e2ba0a43..872668cd 100644 --- a/src/components/chat/contextMenu.ts +++ b/src/components/chat/contextMenu.ts @@ -5,7 +5,7 @@ import appMessagesManager from "../../lib/appManagers/appMessagesManager"; import appPeersManager from "../../lib/appManagers/appPeersManager"; import appPollsManager, { Poll } from "../../lib/appManagers/appPollsManager"; import rootScope from "../../lib/rootScope"; -import { cancelEvent, cancelSelection, findUpClassName } from "../../helpers/dom"; +import { attachClickEvent, cancelEvent, cancelSelection, findUpClassName } from "../../helpers/dom"; import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu"; import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc"; import PopupDeleteMessages from "../popupDeleteMessages"; @@ -97,22 +97,6 @@ export default class ChatContextMenu { }; if(isTouchSupported) { - const attachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent) => void) => { - elem.addEventListener('touchstart', (e) => { - const onTouchMove = (e: TouchEvent) => { - elem.removeEventListener('touchend', onTouchEnd); - }; - - const onTouchEnd = (e: TouchEvent) => { - elem.removeEventListener('touchmove', onTouchMove); - callback(e); - }; - - elem.addEventListener('touchend', onTouchEnd, {once: true}); - elem.addEventListener('touchmove', onTouchMove, {once: true}); - }); - }; - attachClickEvent(attachTo, (e) => { if(appImManager.chatSelection.isSelecting) { return; @@ -126,7 +110,7 @@ export default class ChatContextMenu { const good = ['bubble', 'bubble__container', 'message', 'time', 'inner'].find(c => className.match(new RegExp(c + '($|\\s)'))); if(good) { cancelEvent(e); - onContextMenu(e.changedTouches[0]); + onContextMenu((e as TouchEvent).changedTouches[0]); } }); diff --git a/src/helpers/dom.ts b/src/helpers/dom.ts index c4d4c29a..7f876b3e 100644 --- a/src/helpers/dom.ts +++ b/src/helpers/dom.ts @@ -442,3 +442,37 @@ export function blurActiveElement() { } export const CLICK_EVENT_NAME = isTouchSupported ? 'touchend' : 'click'; +export const attachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) => { + if(CLICK_EVENT_NAME == 'touchend') { + const o = {...options, once: true}; + + const onTouchStart = (e: TouchEvent) => { + const onTouchMove = (e: TouchEvent) => { + elem.removeEventListener('touchend', onTouchEnd, o); + }; + + const onTouchEnd = (e: TouchEvent) => { + elem.removeEventListener('touchmove', onTouchMove, o); + callback(e); + if(options.once) { + elem.removeEventListener('touchstart', onTouchStart); + } + }; + + elem.addEventListener('touchend', onTouchEnd, o); + elem.addEventListener('touchmove', onTouchMove, o); + }; + + elem.addEventListener('touchstart', onTouchStart); + } else { + elem.addEventListener(CLICK_EVENT_NAME, callback, options); + } +}; + +export const detachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) => { + if(CLICK_EVENT_NAME == 'touchend') { + elem.removeEventListener('touchstart', callback, options); + } else { + elem.removeEventListener(CLICK_EVENT_NAME, callback, options); + } +}; diff --git a/src/lib/richtextprocessor.ts b/src/lib/richtextprocessor.ts index 61a8ef07..cf4ee681 100644 --- a/src/lib/richtextprocessor.ts +++ b/src/lib/richtextprocessor.ts @@ -723,7 +723,11 @@ namespace RichTextProcessor { export function wrapDraftText(text: string, options: Partial<{ entities: MessageEntity[] }> = {}) { - let entities = options.entities.slice(); + if(!text) { + return ''; + } + + let entities = (options.entities || []).slice(); if(emojiSupported) { // * fix safari emoji entities = entities.filter(e => e._ != 'messageEntityEmoji'); } diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index e663e6c1..2ddb0f9a 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -353,6 +353,7 @@ $chat-helper-size: 39px; > .tgico { position: absolute; animation: hide-icon .4s forwards ease-in-out; + height: 24px; } &.send {