Fix 'keyboard is closing on each message send'
Fix stickers categories order Refactored stickers & emoji heights to stickyIntersector
This commit is contained in:
parent
837fcbf13c
commit
aadcb9732e
@ -3,7 +3,7 @@ import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
import apiManager from "../lib/mtproto/mtprotoworker";
|
||||
import appWebPagesManager from "../lib/appManagers/appWebPagesManager";
|
||||
import appImManager from "../lib/appManagers/appImManager";
|
||||
import { getRichValue, calcImageInBox } from "../lib/utils";
|
||||
import { getRichValue, calcImageInBox, cancelEvent } from "../lib/utils";
|
||||
import { wrapDocument, wrapReply } from "./wrappers";
|
||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import { Layouter, RectPart } from "./groupedLayout";
|
||||
@ -495,7 +495,9 @@ export class ChatInput {
|
||||
this.onMessageSent();
|
||||
});
|
||||
|
||||
this.btnSend.addEventListener('click', () => {
|
||||
const onBtnSendClick = (e: Event) => {
|
||||
cancelEvent(e);
|
||||
|
||||
if(this.btnSend.classList.contains('tgico-send') || !this.recorder) {
|
||||
if(this.recording) {
|
||||
this.recorder.stop();
|
||||
@ -553,7 +555,10 @@ export class ChatInput {
|
||||
console.error('Recorder start error:', e);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.btnSend.addEventListener('touchend', onBtnSendClick);
|
||||
this.btnSend.addEventListener('click', onBtnSendClick);
|
||||
|
||||
if(this.recorder) {
|
||||
this.btnCancelRecord.addEventListener('click', () => {
|
||||
|
@ -9,6 +9,7 @@ import appImManager from "../../lib/appManagers/appImManager";
|
||||
import Scrollable from "../scrollable_new";
|
||||
import EmojiTab from "./tabs/emoji";
|
||||
import StickersTab from "./tabs/stickers";
|
||||
import StickyIntersector from "../stickyIntersector";
|
||||
|
||||
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
||||
|
||||
@ -17,6 +18,8 @@ export interface EmoticonsTab {
|
||||
onCloseAfterTimeout?: () => void
|
||||
}
|
||||
|
||||
const test = false;
|
||||
|
||||
export class EmoticonsDropdown {
|
||||
public static lazyLoadQueue = new LazyLoadQueue();
|
||||
private element: HTMLElement;
|
||||
@ -57,6 +60,7 @@ export class EmoticonsDropdown {
|
||||
//this.displayTimeout = setTimeout(() => {
|
||||
if(firstTime) {
|
||||
this.toggleEl.onmouseout = this.element.onmouseout = (e) => {
|
||||
if(test) return;
|
||||
const toElement = (e as any).toElement as Element;
|
||||
if(toElement && findUpClassName(toElement, 'emoji-dropdown')) {
|
||||
return;
|
||||
@ -213,8 +217,48 @@ export class EmoticonsDropdown {
|
||||
//animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||
};
|
||||
|
||||
public static menuOnClick = (menu: HTMLUListElement, heights: number[], scroll: Scrollable, menuScroll?: Scrollable) => {
|
||||
menu.addEventListener('click', function(e) {
|
||||
public static menuOnClick = (menu: HTMLUListElement, scroll: Scrollable, menuScroll?: Scrollable) => {
|
||||
let prevId = 0;
|
||||
let jumpedTo = -1;
|
||||
|
||||
const setActive = (id: number) => {
|
||||
if(id == prevId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
menu.children[prevId].classList.remove('active');
|
||||
menu.children[id].classList.add('active');
|
||||
prevId = id;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const stickyIntersector = new StickyIntersector(scroll.container, (stuck, target) => {
|
||||
//console.log('sticky scrollTOp', stuck, target, scroll.container.scrollTop);
|
||||
|
||||
if(jumpedTo == scroll.container.scrollTop) {
|
||||
return;
|
||||
} else {
|
||||
jumpedTo = -1;
|
||||
}
|
||||
|
||||
const which = whichChild(target);
|
||||
if(!stuck && which) { // * due to stickyIntersector
|
||||
return;
|
||||
}
|
||||
|
||||
setActive(which);
|
||||
|
||||
if(menuScroll) {
|
||||
if(which < menu.childElementCount - 4) {
|
||||
menuScroll.container.scrollLeft = (which - 3) * 47;
|
||||
} else {
|
||||
menuScroll.container.scrollLeft = which * 47;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
menu.addEventListener('click', (e) => {
|
||||
let target = e.target as HTMLElement;
|
||||
target = findUpTag(target, 'LI');
|
||||
|
||||
@ -222,59 +266,21 @@ export class EmoticonsDropdown {
|
||||
return;
|
||||
}
|
||||
|
||||
let index = whichChild(target);
|
||||
let y = heights[index - 1/* 2 */] || 0; // 10 == padding .scrollable
|
||||
const which = whichChild(target);
|
||||
|
||||
//console.log('emoticonsMenuOnClick', index, heights, target);
|
||||
|
||||
/* if(menuScroll) {
|
||||
menuScroll.container.scrollLeft = target.scrollWidth * index;
|
||||
if(!setActive(which)) {
|
||||
return;
|
||||
}
|
||||
console.log('emoticonsMenuOnClick', menu.getBoundingClientRect(), target.getBoundingClientRect());
|
||||
*/
|
||||
/* scroll.onAddedBottom = () => { // привет, костыль, давно не виделись!
|
||||
scroll.container.scrollTop = y;
|
||||
scroll.onAddedBottom = () => {};
|
||||
}; */
|
||||
scroll.container.scrollTop = y;
|
||||
|
||||
/* setTimeout(() => {
|
||||
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||
}, 100); */
|
||||
const element = (scroll.splitUp || scroll.container).children[which] as HTMLElement;
|
||||
const offsetTop = element.offsetTop + 1; // * due to stickyIntersector
|
||||
|
||||
/* window.requestAnimationFrame(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||
});
|
||||
}); */
|
||||
scroll.container.scrollTop = jumpedTo = offsetTop;
|
||||
|
||||
//console.log('set scrollTop:', offsetTop);
|
||||
});
|
||||
};
|
||||
|
||||
public static contentOnScroll = (menu: HTMLUListElement, heights: number[], prevCategoryIndex: number, scroll: HTMLElement, menuScroll?: Scrollable) => {
|
||||
let y = Math.round(scroll.scrollTop);
|
||||
|
||||
//console.log(heights, y);
|
||||
|
||||
for(let i = 0; i < heights.length; ++i) {
|
||||
let height = heights[i];
|
||||
if(y < height) {
|
||||
menu.children[prevCategoryIndex].classList.remove('active');
|
||||
prevCategoryIndex = i/* + 1 */;
|
||||
menu.children[prevCategoryIndex].classList.add('active');
|
||||
|
||||
if(menuScroll) {
|
||||
if(i < heights.length - 4) {
|
||||
menuScroll.container.scrollLeft = (i - 3) * 47;
|
||||
} else {
|
||||
menuScroll.container.scrollLeft = i * 47;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return prevCategoryIndex;
|
||||
return stickyIntersector;
|
||||
};
|
||||
|
||||
public static onMediaClick = (e: MouseEvent) => {
|
||||
|
@ -5,6 +5,7 @@ import { putPreloader } from "../../misc";
|
||||
import appStateManager from "../../../lib/appManagers/appStateManager";
|
||||
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||
import appImManager from "../../../lib/appManagers/appImManager";
|
||||
import StickyIntersector from "../../stickyIntersector";
|
||||
|
||||
export default class EmojiTab implements EmoticonsTab {
|
||||
public content: HTMLElement;
|
||||
@ -12,8 +13,8 @@ export default class EmojiTab implements EmoticonsTab {
|
||||
private recent: string[] = [];
|
||||
private recentItemsDiv: HTMLElement;
|
||||
|
||||
private heights: number[] = [];
|
||||
private scroll: Scrollable;
|
||||
private stickyIntersector: StickyIntersector;
|
||||
|
||||
init() {
|
||||
this.content = document.getElementById('content-emoji') as HTMLDivElement;
|
||||
@ -77,12 +78,9 @@ export default class EmojiTab implements EmoticonsTab {
|
||||
}
|
||||
//console.timeEnd('emojiParse');
|
||||
|
||||
let prevCategoryIndex = 0;
|
||||
const menu = this.content.previousElementSibling.firstElementChild as HTMLUListElement;
|
||||
const emojiScroll = this.scroll = new Scrollable(this.content, 'y', 'EMOJI', null);
|
||||
emojiScroll.container.addEventListener('scroll', (e) => {
|
||||
prevCategoryIndex = EmoticonsDropdown.contentOnScroll(menu, this.heights, prevCategoryIndex, emojiScroll.container);
|
||||
});
|
||||
|
||||
//emojiScroll.setVirtualContainer(emojiScroll.container);
|
||||
|
||||
const preloader = putPreloader(this.content, true);
|
||||
@ -112,15 +110,13 @@ export default class EmojiTab implements EmoticonsTab {
|
||||
}
|
||||
|
||||
emojiScroll.append(div);
|
||||
this.stickyIntersector.observeStickyHeaderChanges(div);
|
||||
return div;
|
||||
}).forEach(div => {
|
||||
//console.log('emoji heights push: ', (heights[heights.length - 1] || 0) + div.scrollHeight, div, div.scrollHeight);
|
||||
this.heights.push((this.heights[this.heights.length - 1] || 0) + div.scrollHeight);
|
||||
});
|
||||
});
|
||||
|
||||
this.content.addEventListener('click', this.onContentClick);
|
||||
EmoticonsDropdown.menuOnClick(menu, this.heights, emojiScroll);
|
||||
this.stickyIntersector = EmoticonsDropdown.menuOnClick(menu, emojiScroll);
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
@ -182,14 +178,6 @@ export default class EmojiTab implements EmoticonsTab {
|
||||
const scrollHeight = this.recentItemsDiv.scrollHeight;
|
||||
this.appendEmoji(emoji, this.recentItemsDiv, true);
|
||||
|
||||
// нужно поставить новые размеры для скролла
|
||||
if(this.recentItemsDiv.scrollHeight != scrollHeight) {
|
||||
this.heights.length = 0;
|
||||
(Array.from(this.scroll.container.children) as HTMLElement[]).forEach(div => {
|
||||
this.heights.push((this.heights[this.heights.length - 1] || 0) + div.scrollHeight);
|
||||
});
|
||||
}
|
||||
|
||||
this.recent.findAndSplice(e => e == emoji);
|
||||
this.recent.unshift(emoji);
|
||||
if(this.recent.length > 36) {
|
||||
|
@ -2,7 +2,7 @@ import { EmoticonsTab, EMOTICONSSTICKERGROUP, EmoticonsDropdown } from "..";
|
||||
import { MTDocument } from "../../../types";
|
||||
import Scrollable from "../../scrollable_new";
|
||||
import { wrapSticker } from "../../wrappers";
|
||||
import appStickersManager, { MTStickerSet } from "../../../lib/appManagers/appStickersManager";
|
||||
import appStickersManager, { MTStickerSet, MTStickerSetFull } from "../../../lib/appManagers/appStickersManager";
|
||||
import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
|
||||
import { readBlobAsText } from "../../../helpers/blob";
|
||||
import lottieLoader from "../../../lib/lottieLoader";
|
||||
@ -10,6 +10,7 @@ import { renderImageFromUrl, putPreloader } from "../../misc";
|
||||
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||
import { $rootScope } from "../../../lib/utils";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import StickyIntersector from "../../stickyIntersector";
|
||||
|
||||
export default class StickersTab implements EmoticonsTab {
|
||||
public content: HTMLElement;
|
||||
@ -22,15 +23,17 @@ export default class StickersTab implements EmoticonsTab {
|
||||
private recentDiv: HTMLElement;
|
||||
private recentStickers: MTDocument[] = [];
|
||||
|
||||
private heights: number[] = [];
|
||||
private heightRAF = 0;
|
||||
private scroll: Scrollable;
|
||||
|
||||
private menu: HTMLUListElement;
|
||||
|
||||
private mounted = false;
|
||||
|
||||
categoryPush(categoryDiv: HTMLElement, categoryTitle: string, docs: MTDocument[], prepend?: boolean) {
|
||||
private queueCategoryPush: {element: HTMLElement, prepend: boolean}[] = [];
|
||||
|
||||
private stickyIntersector: StickyIntersector;
|
||||
|
||||
categoryPush(categoryDiv: HTMLElement, categoryTitle: string, promise: Promise<MTDocument[]>, prepend?: boolean) {
|
||||
//if((docs.length % 5) != 0) categoryDiv.classList.add('not-full');
|
||||
|
||||
const itemsDiv = document.createElement('div');
|
||||
@ -42,62 +45,29 @@ export default class StickersTab implements EmoticonsTab {
|
||||
|
||||
categoryDiv.append(titleDiv, itemsDiv);
|
||||
|
||||
docs.forEach(doc => {
|
||||
itemsDiv.append(this.renderSticker(doc));
|
||||
});
|
||||
this.stickyIntersector.observeStickyHeaderChanges(categoryDiv);
|
||||
|
||||
if(prepend) {
|
||||
if(this.recentDiv.parentElement) {
|
||||
this.scroll.prepend(categoryDiv);
|
||||
this.scroll.prepend(this.recentDiv);
|
||||
} else {
|
||||
this.scroll.prepend(categoryDiv);
|
||||
}
|
||||
} else this.scroll.append(categoryDiv);
|
||||
this.queueCategoryPush.push({element: categoryDiv, prepend});
|
||||
|
||||
/* let scrollHeight = categoryDiv.scrollHeight;
|
||||
let prevHeight = heights[heights.length - 1] || 0;
|
||||
//console.log('scrollHeight', scrollHeight, categoryDiv, stickersDiv.childElementCount);
|
||||
if(prepend && heights.length) {// all stickers loaded faster than recent
|
||||
heights.forEach((h, i) => heights[i] += scrollHeight);
|
||||
|
||||
return heights.unshift(scrollHeight) - 1;
|
||||
} */
|
||||
|
||||
this.setNewHeights();
|
||||
|
||||
/* Array.from(stickersDiv.children).forEach((div, i) => {
|
||||
heights[i] = (heights[i - 1] || 0) + div.scrollHeight;
|
||||
}); */
|
||||
|
||||
//this.scroll.onScroll();
|
||||
|
||||
//return heights.push(prevHeight + scrollHeight) - 1;
|
||||
}
|
||||
|
||||
setNewHeights() {
|
||||
if(this.heightRAF) return;
|
||||
//if(this.heightRAF) window.cancelAnimationFrame(this.heightRAF);
|
||||
this.heightRAF = window.requestAnimationFrame(() => {
|
||||
this.heightRAF = 0;
|
||||
|
||||
const heights = this.heights;
|
||||
|
||||
let paddingTop = parseInt(window.getComputedStyle(this.scroll.container).getPropertyValue('padding-top')) || 0;
|
||||
|
||||
heights.length = 0;
|
||||
/* let concated = this.scroll.hiddenElements.up.concat(this.scroll.visibleElements, this.scroll.hiddenElements.down);
|
||||
concated.forEach((el, i) => {
|
||||
heights[i] = (heights[i - 1] || 0) + el.height + (i == 0 ? paddingTop : 0);
|
||||
}); */
|
||||
let concated = Array.from(this.scroll.splitUp.children) as HTMLElement[];
|
||||
concated.forEach((el, i) => {
|
||||
heights[i] = (heights[i - 1] || 0) + el.scrollHeight + (i == 0 ? paddingTop : 0);
|
||||
promise.then(documents => {
|
||||
documents.forEach(doc => {
|
||||
itemsDiv.append(this.renderSticker(doc));
|
||||
});
|
||||
|
||||
this.scroll.reorder();
|
||||
if(this.queueCategoryPush.length) {
|
||||
this.queueCategoryPush.forEach(({element, prepend}) => {
|
||||
if(prepend) {
|
||||
if(this.recentDiv.parentElement) {
|
||||
this.scroll.prepend(element);
|
||||
this.scroll.prepend(this.recentDiv);
|
||||
} else {
|
||||
this.scroll.prepend(element);
|
||||
}
|
||||
} else this.scroll.append(element);
|
||||
});
|
||||
|
||||
//console.log('stickers concated', concated, heights);
|
||||
this.queueCategoryPush.length = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -138,7 +108,9 @@ export default class StickersTab implements EmoticonsTab {
|
||||
|
||||
//stickersScroll.append(categoryDiv);
|
||||
|
||||
const stickerSet = await appStickersManager.getStickerSet(set);
|
||||
const promise = appStickersManager.getStickerSet(set);
|
||||
this.categoryPush(categoryDiv, RichTextProcessor.wrapEmojiText(set.title), promise.then(stickerSet => stickerSet.documents), prepend);
|
||||
const stickerSet = await promise;
|
||||
|
||||
//console.log('got stickerSet', stickerSet, li);
|
||||
|
||||
@ -175,8 +147,6 @@ export default class StickersTab implements EmoticonsTab {
|
||||
group: EMOTICONSSTICKERGROUP
|
||||
}); // kostil
|
||||
}
|
||||
|
||||
this.categoryPush(categoryDiv, RichTextProcessor.wrapEmojiText(stickerSet.set.title), stickerSet.documents, prepend);
|
||||
}
|
||||
|
||||
init() {
|
||||
@ -227,33 +197,16 @@ export default class StickersTab implements EmoticonsTab {
|
||||
const elements = this.stickerSets[set.id];
|
||||
elements.stickers.remove();
|
||||
elements.tab.remove();
|
||||
this.setNewHeights();
|
||||
delete this.stickerSets[set.id];
|
||||
}
|
||||
});
|
||||
|
||||
stickersDiv.addEventListener('click', EmoticonsDropdown.onMediaClick);
|
||||
|
||||
let prevCategoryIndex = 0;
|
||||
this.scroll = new Scrollable(this.content, 'y', 'STICKERS', undefined, undefined, 2);
|
||||
this.scroll.container.addEventListener('scroll', (e) => {
|
||||
//animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||
|
||||
if(this.heights[1] == 0) {
|
||||
this.setNewHeights();
|
||||
}
|
||||
|
||||
prevCategoryIndex = EmoticonsDropdown.contentOnScroll(this.menu, this.heights, prevCategoryIndex, this.scroll.container, menuScroll);
|
||||
});
|
||||
this.scroll.setVirtualContainer(stickersDiv);
|
||||
|
||||
this.menu.addEventListener('click', () => {
|
||||
if(this.heights[1] == 0) {
|
||||
this.setNewHeights();
|
||||
}
|
||||
});
|
||||
|
||||
EmoticonsDropdown.menuOnClick(this.menu, this.heights, this.scroll, menuScroll);
|
||||
this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll);
|
||||
|
||||
const preloader = putPreloader(this.content, true);
|
||||
|
||||
@ -269,7 +222,7 @@ export default class StickersTab implements EmoticonsTab {
|
||||
};
|
||||
|
||||
preloader.remove();
|
||||
this.categoryPush(this.recentDiv, 'Recent', this.recentStickers, true);
|
||||
this.categoryPush(this.recentDiv, 'Recent', Promise.resolve(this.recentStickers), true);
|
||||
}),
|
||||
|
||||
apiManager.invokeApi('messages.getAllStickers', {hash: 0}).then(async(res) => {
|
||||
@ -308,8 +261,6 @@ export default class StickersTab implements EmoticonsTab {
|
||||
if(items.childElementCount > 20) {
|
||||
(Array.from(items.children) as HTMLElement[]).slice(20).forEach(el => el.remove());
|
||||
}
|
||||
|
||||
this.setNewHeights();
|
||||
}
|
||||
|
||||
onClose() {
|
||||
|
@ -79,6 +79,13 @@
|
||||
padding: 12px 6px 6px 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sticky_sentinel {
|
||||
&--top {
|
||||
top: 0;
|
||||
height: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.emoji-category {
|
||||
//padding-top: 1px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user