send webpage & minor chat fixes
This commit is contained in:
parent
ff118053f6
commit
196bcf485c
361
src/components/emoticonsDropdown.ts
Normal file
361
src/components/emoticonsDropdown.ts
Normal file
@ -0,0 +1,361 @@
|
||||
import { AppImManager } from "../lib/appManagers/appImManager";
|
||||
import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
|
||||
import { LazyLoadQueue, horizontalMenu, MTDocument, wrapSticker } from "./misc";
|
||||
import lottieLoader from "../lib/lottieLoader";
|
||||
import Scrollable from "./scrollable";
|
||||
import { findUpTag, whichChild } from "../lib/utils";
|
||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickersManager";
|
||||
import apiManager from '../lib/mtproto/apiManager';
|
||||
import CryptoWorker from '../lib/crypto/cryptoworker';
|
||||
|
||||
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
||||
|
||||
const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
appImManager: AppImManager, appMessagesManager: AppMessagesManager,
|
||||
messageInput: HTMLDivElement, toggleEl: HTMLButtonElement, btnSend: HTMLButtonElement) => {
|
||||
let dropdown = pageEl.querySelector('.emoji-dropdown') as HTMLDivElement;
|
||||
dropdown.classList.add('active'); // need
|
||||
|
||||
let lazyLoadQueue = new LazyLoadQueue();
|
||||
|
||||
let container = pageEl.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
|
||||
let tabs = pageEl.querySelector('.emoji-dropdown .emoji-tabs') as HTMLUListElement;
|
||||
horizontalMenu(tabs, container, (id) => {
|
||||
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||
|
||||
if(id == 1 && stickersInit) {
|
||||
stickersInit();
|
||||
}
|
||||
}, () => {
|
||||
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||
lazyLoadQueue.check(); // for stickers
|
||||
});
|
||||
(tabs.children[0] as HTMLLIElement).click(); // set media
|
||||
|
||||
let emoticonsMenuOnClick = (menu: HTMLUListElement, heights: number[], scroll: Scrollable) => {
|
||||
menu.addEventListener('click', function(e) {
|
||||
let target = e.target as HTMLLIElement;
|
||||
target = findUpTag(target, 'LI');
|
||||
|
||||
let index = whichChild(target);
|
||||
let y = heights[index - 1/* 2 */] || 0; // 10 == padding .scrollable
|
||||
|
||||
console.log('emoticonsMenuOnClick', index, y, scroll.container.scrollHeight, scroll);
|
||||
|
||||
scroll.onAddedBottom = () => { // привет, костыль, давно не виделись!
|
||||
scroll.container.scrollTop = y;
|
||||
scroll.onAddedBottom = () => {};
|
||||
};
|
||||
scroll.container.scrollTop = y;
|
||||
});
|
||||
};
|
||||
|
||||
let emoticonsContentOnScroll = (menu: HTMLUListElement, heights: number[], prevCategoryIndex: number, scroll: HTMLDivElement) => {
|
||||
let y = 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');
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return prevCategoryIndex;
|
||||
};
|
||||
|
||||
{
|
||||
let categories = ["Smileys & Emotion", "Animals & Nature", "Food & Drink", "Travel & Places", "Activities", "Objects", "Symbols", "Flags", "Skin Tones"];
|
||||
let divs: {
|
||||
[category: string]: HTMLDivElement
|
||||
} = {};
|
||||
|
||||
let keyCategory = Config.Emoji.keyCategory;
|
||||
let sorted: {
|
||||
[category: string]: any[]
|
||||
} = {};
|
||||
|
||||
for(let unified in Config.Emoji.emoji) {
|
||||
// @ts-ignore
|
||||
let details = Config.Emoji.emoji[unified];
|
||||
let category = details[keyCategory];
|
||||
|
||||
details.unified = unified;
|
||||
|
||||
if(!sorted[category]) sorted[category] = [];
|
||||
sorted[category][details.sort_order] = details;
|
||||
}
|
||||
|
||||
Object.keys(sorted).forEach(c => sorted[c].sort());
|
||||
|
||||
categories.pop();
|
||||
delete sorted["Skin Tones"];
|
||||
|
||||
console.time('emojiParse');
|
||||
for(let category in sorted) {
|
||||
let div = document.createElement('div');
|
||||
div.classList.add('emoji-category');
|
||||
|
||||
let emojis = sorted[category];
|
||||
emojis.forEach(details => {
|
||||
let emoji = details.unified;
|
||||
//let emoji = (details.unified as string).split('-')
|
||||
//.reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), '');
|
||||
|
||||
let spanEmoji = document.createElement('span');
|
||||
let kek = RichTextProcessor.wrapRichText(emoji);
|
||||
|
||||
if(!kek.includes('emoji')) {
|
||||
console.log(details, emoji, kek, spanEmoji, emoji.length, new TextEncoder().encode(emoji));
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log(kek);
|
||||
|
||||
spanEmoji.innerHTML = kek;
|
||||
|
||||
//spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement;
|
||||
//spanEmoji.setAttribute('emoji', emoji);
|
||||
div.appendChild(spanEmoji);
|
||||
});
|
||||
|
||||
divs[category] = div;
|
||||
}
|
||||
console.timeEnd('emojiParse');
|
||||
|
||||
let heights: number[] = [0];
|
||||
|
||||
let contentEmojiDiv = document.getElementById('content-emoji') as HTMLDivElement;
|
||||
categories.forEach(category => {
|
||||
let div = divs[category];
|
||||
|
||||
if(!div) {
|
||||
console.error('no div by category:', category);
|
||||
}
|
||||
|
||||
contentEmojiDiv.append(div);
|
||||
heights.push((heights[heights.length - 1] || 0) + div.scrollHeight);
|
||||
|
||||
//console.log(div, div.scrollHeight);
|
||||
});
|
||||
|
||||
contentEmojiDiv.addEventListener('click', function(e) {
|
||||
let target = e.target as any;
|
||||
//if(target.tagName != 'SPAN') return;
|
||||
|
||||
if(target.tagName == 'SPAN' && !target.classList.contains('emoji')) {
|
||||
target = target.firstElementChild;
|
||||
} else if(target.tagName == 'DIV') return;
|
||||
|
||||
//console.log('contentEmoji div', target);
|
||||
|
||||
/* if(!target.classList.contains('emoji')) {
|
||||
target = target.parentElement as HTMLSpanElement;
|
||||
|
||||
if(!target.classList.contains('emoji')) {
|
||||
return;
|
||||
}
|
||||
} */
|
||||
|
||||
//messageInput.innerHTML += target.innerHTML;
|
||||
messageInput.innerHTML += target.outerHTML;
|
||||
|
||||
btnSend.classList.add('tgico-send');
|
||||
btnSend.classList.remove('tgico-microphone2');
|
||||
});
|
||||
|
||||
let prevCategoryIndex = 1;
|
||||
let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement;
|
||||
let emojiScroll = new Scrollable(contentEmojiDiv);
|
||||
emojiScroll.container.addEventListener('scroll', (e) => {
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container);
|
||||
});
|
||||
//emojiScroll.setVirtualContainer(emojiScroll.container);
|
||||
|
||||
emoticonsMenuOnClick(menu, heights, emojiScroll);
|
||||
}
|
||||
|
||||
let stickersInit = () => {
|
||||
let contentStickersDiv = document.getElementById('content-stickers') as HTMLDivElement;
|
||||
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
|
||||
|
||||
let menuWrapper = contentStickersDiv.nextElementSibling as HTMLDivElement;
|
||||
let menu = menuWrapper.firstElementChild as HTMLUListElement;
|
||||
|
||||
let menuScroll = new Scrollable(menuWrapper, true, false);
|
||||
|
||||
let stickersDiv = document.createElement('div');
|
||||
stickersDiv.classList.add('stickers-categories');
|
||||
contentStickersDiv.append(stickersDiv);
|
||||
|
||||
stickersDiv.addEventListener('mouseover', (e) => {
|
||||
let target = e.target as HTMLElement;
|
||||
|
||||
if(target.tagName == 'CANVAS') { // turn on sticker
|
||||
let animation = lottieLoader.getAnimation(target.parentElement, EMOTICONSSTICKERGROUP);
|
||||
|
||||
if(animation) {
|
||||
// @ts-ignore
|
||||
if(animation.currentFrame == animation.totalFrames - 1) {
|
||||
animation.goToAndPlay(0, true);
|
||||
} else {
|
||||
animation.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
stickersDiv.addEventListener('click', (e) => {
|
||||
let target = e.target as HTMLDivElement;
|
||||
target = findUpTag(target, 'DIV');
|
||||
|
||||
let fileID = target.getAttribute('file-id');
|
||||
let document = appStickersManager.getSticker(fileID);
|
||||
|
||||
if(document) {
|
||||
appMessagesManager.sendFile(appImManager.peerID, document, {isMedia: true});
|
||||
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
|
||||
dropdown.classList.remove('active');
|
||||
toggleEl.classList.remove('active');
|
||||
} else {
|
||||
console.warn('got no sticker by id:', fileID);
|
||||
}
|
||||
});
|
||||
|
||||
let heights: number[] = [];
|
||||
|
||||
let categoryPush = (categoryDiv: HTMLDivElement, docs: MTDocument[], prepend?: boolean) => {
|
||||
//if((docs.length % 5) != 0) categoryDiv.classList.add('not-full');
|
||||
|
||||
docs.forEach(doc => {
|
||||
let div = document.createElement('div');
|
||||
wrapSticker(doc, div, undefined, lazyLoadQueue, EMOTICONSSTICKERGROUP, true);
|
||||
|
||||
categoryDiv.append(div);
|
||||
});
|
||||
|
||||
/* if(prepend) {
|
||||
stickersDiv.prepend(categoryDiv);
|
||||
} else {
|
||||
stickersDiv.append(categoryDiv);
|
||||
} */
|
||||
|
||||
setTimeout(() => lazyLoadQueue.check(), 0);
|
||||
|
||||
/* 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;
|
||||
} */
|
||||
|
||||
heights.length = 0;
|
||||
Array.from(stickersDiv.children).forEach((div, i) => {
|
||||
heights[i] = (heights[i - 1] || 0) + div.scrollHeight;
|
||||
});
|
||||
|
||||
//stickersScroll.onScroll();
|
||||
|
||||
//return heights.push(prevHeight + scrollHeight) - 1;
|
||||
};
|
||||
|
||||
apiManager.invokeApi('messages.getRecentStickers', {flags: 0, hash: 0}).then((res) => {
|
||||
let stickers: {
|
||||
_: string,
|
||||
hash: number,
|
||||
packs: any[],
|
||||
stickers: MTDocument[],
|
||||
dates: number[]
|
||||
} = res as any;
|
||||
|
||||
let categoryDiv = document.createElement('div');
|
||||
categoryDiv.classList.add('sticker-category');
|
||||
|
||||
stickersDiv.prepend(categoryDiv);
|
||||
|
||||
categoryPush(categoryDiv, stickers.stickers, true);
|
||||
});
|
||||
|
||||
apiManager.invokeApi('messages.getAllStickers', {hash: 0}).then((res) => {
|
||||
let stickers: {
|
||||
_: 'messages.allStickers',
|
||||
hash: number,
|
||||
sets: Array<MTStickerSet>
|
||||
} = res as any;
|
||||
|
||||
stickers.sets/* .slice(0, 10) */.forEach(async(set) => {
|
||||
let categoryDiv = document.createElement('div');
|
||||
categoryDiv.classList.add('sticker-category');
|
||||
|
||||
let li = document.createElement('li');
|
||||
li.classList.add('btn-icon');
|
||||
|
||||
menu.append(li);
|
||||
|
||||
stickersDiv.append(categoryDiv);
|
||||
|
||||
let stickerSet = await appStickersManager.getStickerSet(set);
|
||||
|
||||
if(stickerSet.set.thumb) {
|
||||
let thumb = stickerSet.set.thumb;
|
||||
|
||||
appStickersManager.getStickerSetThumb(stickerSet.set).then(async(blob) => {
|
||||
if(thumb.w == 1 && thumb.h == 1) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.addEventListener('loadend', async(e) => {
|
||||
// @ts-ignore
|
||||
const text = e.srcElement.result;
|
||||
let json = await CryptoWorker.gzipUncompress<string>(text, true);
|
||||
|
||||
let animation = await lottieLoader.loadAnimation({
|
||||
container: li,
|
||||
loop: true,
|
||||
autoplay: false,
|
||||
animationData: JSON.parse(json)
|
||||
}, EMOTICONSSTICKERGROUP);
|
||||
});
|
||||
|
||||
reader.readAsArrayBuffer(blob);
|
||||
} else {
|
||||
let image = new Image();
|
||||
image.src = URL.createObjectURL(blob);
|
||||
|
||||
li.append(image);
|
||||
}
|
||||
});
|
||||
} else { // as thumb will be used first sticker
|
||||
wrapSticker(stickerSet.documents[0], li as any, undefined, undefined, EMOTICONSSTICKERGROUP); // kostil
|
||||
}
|
||||
|
||||
categoryPush(categoryDiv, stickerSet.documents);
|
||||
});
|
||||
});
|
||||
|
||||
let prevCategoryIndex = 0;
|
||||
let stickersScroll = new Scrollable(contentStickersDiv);
|
||||
stickersScroll.container.addEventListener('scroll', (e) => {
|
||||
lazyLoadQueue.check();
|
||||
lottieLoader.checkAnimations();
|
||||
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, stickersScroll.container);
|
||||
});
|
||||
stickersScroll.setVirtualContainer(stickersDiv);
|
||||
|
||||
emoticonsMenuOnClick(menu, heights, stickersScroll);
|
||||
|
||||
stickersInit = null;
|
||||
};
|
||||
|
||||
return {dropdown, lazyLoadQueue};
|
||||
};
|
||||
|
||||
export default initEmoticonsDropdown;
|
@ -807,6 +807,7 @@ export function openBtnMenu(menuElement: HTMLDivElement) {
|
||||
|
||||
openedMenu = menuElement;
|
||||
openedMenu.classList.add('active');
|
||||
openedMenu.parentElement.classList.add('menu-open');
|
||||
|
||||
window.addEventListener('click', () => {
|
||||
if(openedMenu) {
|
||||
|
@ -1,368 +1,13 @@
|
||||
//import { appImManager, appMessagesManager, appDialogsManager, apiUpdatesManager, appUsersManager } from "../lib/services";
|
||||
import { horizontalMenu, wrapSticker, MTDocument, LazyLoadQueue, openBtnMenu } from "./misc";
|
||||
import { LazyLoadQueue, openBtnMenu } from "./misc";
|
||||
import Scrollable from './scrollable';
|
||||
|
||||
import { whichChild, findUpTag } from "../lib/utils";
|
||||
import {stackBlurImage} from '../lib/StackBlur';
|
||||
import * as Config from '../lib/config';
|
||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
import { MTProto } from "../lib/mtproto/mtproto";
|
||||
import lottieLoader from "../lib/lottieLoader";
|
||||
import CryptoWorker from '../lib/crypto/cryptoworker';
|
||||
|
||||
import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickersManager";
|
||||
import { AppImManager } from "../lib/appManagers/appImManager";
|
||||
import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
|
||||
import appSidebarLeft from "../lib/appManagers/appSidebarLeft";
|
||||
|
||||
const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
||||
|
||||
let initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
appImManager: AppImManager, appMessagesManager: AppMessagesManager,
|
||||
messageInput: HTMLDivElement, toggleEl: HTMLButtonElement, btnSend: HTMLButtonElement) => {
|
||||
let dropdown = pageEl.querySelector('.emoji-dropdown') as HTMLDivElement;
|
||||
dropdown.classList.add('active'); // need
|
||||
|
||||
let lazyLoadQueue = new LazyLoadQueue();
|
||||
|
||||
let container = pageEl.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
|
||||
let tabs = pageEl.querySelector('.emoji-dropdown .emoji-tabs') as HTMLUListElement;
|
||||
horizontalMenu(tabs, container, (id) => {
|
||||
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||
|
||||
if(id == 1 && stickersInit) {
|
||||
stickersInit();
|
||||
}
|
||||
}, () => {
|
||||
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||
lazyLoadQueue.check(); // for stickers
|
||||
});
|
||||
(tabs.children[0] as HTMLLIElement).click(); // set media
|
||||
|
||||
let emoticonsMenuOnClick = (menu: HTMLUListElement, heights: number[], scroll: Scrollable) => {
|
||||
menu.addEventListener('click', function(e) {
|
||||
let target = e.target as HTMLLIElement;
|
||||
target = findUpTag(target, 'LI');
|
||||
|
||||
let index = whichChild(target);
|
||||
let y = heights[index - 1/* 2 */] || 0; // 10 == padding .scrollable
|
||||
|
||||
console.log('emoticonsMenuOnClick', index, y, scroll.container.scrollHeight, scroll);
|
||||
|
||||
scroll.onAddedBottom = () => { // привет, костыль, давно не виделись!
|
||||
scroll.container.scrollTop = y;
|
||||
scroll.onAddedBottom = () => {};
|
||||
};
|
||||
scroll.container.scrollTop = y;
|
||||
});
|
||||
};
|
||||
|
||||
let emoticonsContentOnScroll = (menu: HTMLUListElement, heights: number[], prevCategoryIndex: number, scroll: HTMLDivElement) => {
|
||||
let y = 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');
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return prevCategoryIndex;
|
||||
};
|
||||
|
||||
{
|
||||
let categories = ["Smileys & Emotion", "Animals & Nature", "Food & Drink", "Travel & Places", "Activities", "Objects", "Symbols", "Flags", "Skin Tones"];
|
||||
let divs: {
|
||||
[category: string]: HTMLDivElement
|
||||
} = {};
|
||||
|
||||
let keyCategory = Config.Emoji.keyCategory;
|
||||
let sorted: {
|
||||
[category: string]: any[]
|
||||
} = {};
|
||||
|
||||
for(let unified in Config.Emoji.emoji) {
|
||||
// @ts-ignore
|
||||
let details = Config.Emoji.emoji[unified];
|
||||
let category = details[keyCategory];
|
||||
|
||||
details.unified = unified;
|
||||
|
||||
if(!sorted[category]) sorted[category] = [];
|
||||
sorted[category][details.sort_order] = details;
|
||||
}
|
||||
|
||||
Object.keys(sorted).forEach(c => sorted[c].sort());
|
||||
|
||||
categories.pop();
|
||||
delete sorted["Skin Tones"];
|
||||
|
||||
console.time('emojiParse');
|
||||
for(let category in sorted) {
|
||||
let div = document.createElement('div');
|
||||
div.classList.add('emoji-category');
|
||||
|
||||
let emojis = sorted[category];
|
||||
emojis.forEach(details => {
|
||||
let emoji = details.unified;
|
||||
//let emoji = (details.unified as string).split('-')
|
||||
//.reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), '');
|
||||
|
||||
let spanEmoji = document.createElement('span');
|
||||
let kek = RichTextProcessor.wrapRichText(emoji);
|
||||
|
||||
if(!kek.includes('emoji')) {
|
||||
console.log(details, emoji, kek, spanEmoji, emoji.length, new TextEncoder().encode(emoji));
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log(kek);
|
||||
|
||||
spanEmoji.innerHTML = kek;
|
||||
|
||||
//spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement;
|
||||
//spanEmoji.setAttribute('emoji', emoji);
|
||||
div.appendChild(spanEmoji);
|
||||
});
|
||||
|
||||
divs[category] = div;
|
||||
}
|
||||
console.timeEnd('emojiParse');
|
||||
|
||||
let heights: number[] = [0];
|
||||
|
||||
let contentEmojiDiv = document.getElementById('content-emoji') as HTMLDivElement;
|
||||
categories.forEach(category => {
|
||||
let div = divs[category];
|
||||
|
||||
if(!div) {
|
||||
console.error('no div by category:', category);
|
||||
}
|
||||
|
||||
contentEmojiDiv.append(div);
|
||||
heights.push((heights[heights.length - 1] || 0) + div.scrollHeight);
|
||||
|
||||
//console.log(div, div.scrollHeight);
|
||||
});
|
||||
|
||||
contentEmojiDiv.addEventListener('click', function(e) {
|
||||
let target = e.target as any;
|
||||
//if(target.tagName != 'SPAN') return;
|
||||
|
||||
if(target.tagName == 'SPAN' && !target.classList.contains('emoji')) {
|
||||
target = target.firstElementChild;
|
||||
} else if(target.tagName == 'DIV') return;
|
||||
|
||||
//console.log('contentEmoji div', target);
|
||||
|
||||
/* if(!target.classList.contains('emoji')) {
|
||||
target = target.parentElement as HTMLSpanElement;
|
||||
|
||||
if(!target.classList.contains('emoji')) {
|
||||
return;
|
||||
}
|
||||
} */
|
||||
|
||||
//messageInput.innerHTML += target.innerHTML;
|
||||
messageInput.innerHTML += target.outerHTML;
|
||||
|
||||
btnSend.classList.add('tgico-send');
|
||||
btnSend.classList.remove('tgico-microphone2');
|
||||
});
|
||||
|
||||
let prevCategoryIndex = 1;
|
||||
let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement;
|
||||
let emojiScroll = new Scrollable(contentEmojiDiv);
|
||||
emojiScroll.container.addEventListener('scroll', (e) => {
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container);
|
||||
});
|
||||
//emojiScroll.setVirtualContainer(emojiScroll.container);
|
||||
|
||||
emoticonsMenuOnClick(menu, heights, emojiScroll);
|
||||
}
|
||||
|
||||
let stickersInit = () => {
|
||||
let contentStickersDiv = document.getElementById('content-stickers') as HTMLDivElement;
|
||||
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
|
||||
|
||||
let menuWrapper = contentStickersDiv.nextElementSibling as HTMLDivElement;
|
||||
let menu = menuWrapper.firstElementChild as HTMLUListElement;
|
||||
|
||||
let menuScroll = new Scrollable(menuWrapper, true, false);
|
||||
|
||||
let stickersDiv = document.createElement('div');
|
||||
stickersDiv.classList.add('stickers-categories');
|
||||
contentStickersDiv.append(stickersDiv);
|
||||
|
||||
stickersDiv.addEventListener('mouseover', (e) => {
|
||||
let target = e.target as HTMLElement;
|
||||
|
||||
if(target.tagName == 'CANVAS') { // turn on sticker
|
||||
let animation = lottieLoader.getAnimation(target.parentElement, EMOTICONSSTICKERGROUP);
|
||||
|
||||
if(animation) {
|
||||
// @ts-ignore
|
||||
if(animation.currentFrame == animation.totalFrames - 1) {
|
||||
animation.goToAndPlay(0, true);
|
||||
} else {
|
||||
animation.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
stickersDiv.addEventListener('click', (e) => {
|
||||
let target = e.target as HTMLDivElement;
|
||||
target = findUpTag(target, 'DIV');
|
||||
|
||||
let fileID = target.getAttribute('file-id');
|
||||
let document = appStickersManager.getSticker(fileID);
|
||||
|
||||
if(document) {
|
||||
appMessagesManager.sendFile(appImManager.peerID, document, {isMedia: true});
|
||||
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
|
||||
dropdown.classList.remove('active');
|
||||
toggleEl.classList.remove('active');
|
||||
} else {
|
||||
console.warn('got no sticker by id:', fileID);
|
||||
}
|
||||
});
|
||||
|
||||
let heights: number[] = [];
|
||||
|
||||
let categoryPush = (categoryDiv: HTMLDivElement, docs: MTDocument[], prepend?: boolean) => {
|
||||
//if((docs.length % 5) != 0) categoryDiv.classList.add('not-full');
|
||||
|
||||
docs.forEach(doc => {
|
||||
let div = document.createElement('div');
|
||||
wrapSticker(doc, div, undefined, lazyLoadQueue, EMOTICONSSTICKERGROUP, true);
|
||||
|
||||
categoryDiv.append(div);
|
||||
});
|
||||
|
||||
/* if(prepend) {
|
||||
stickersDiv.prepend(categoryDiv);
|
||||
} else {
|
||||
stickersDiv.append(categoryDiv);
|
||||
} */
|
||||
|
||||
setTimeout(() => lazyLoadQueue.check(), 0);
|
||||
|
||||
/* 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;
|
||||
} */
|
||||
|
||||
heights.length = 0;
|
||||
Array.from(stickersDiv.children).forEach((div, i) => {
|
||||
heights[i] = (heights[i - 1] || 0) + div.scrollHeight;
|
||||
});
|
||||
|
||||
//stickersScroll.onScroll();
|
||||
|
||||
//return heights.push(prevHeight + scrollHeight) - 1;
|
||||
};
|
||||
|
||||
MTProto.apiManager.invokeApi('messages.getRecentStickers', {flags: 0, hash: 0}).then((res) => {
|
||||
let stickers: {
|
||||
_: string,
|
||||
hash: number,
|
||||
packs: any[],
|
||||
stickers: MTDocument[],
|
||||
dates: number[]
|
||||
} = res as any;
|
||||
|
||||
let categoryDiv = document.createElement('div');
|
||||
categoryDiv.classList.add('sticker-category');
|
||||
|
||||
stickersDiv.prepend(categoryDiv);
|
||||
|
||||
categoryPush(categoryDiv, stickers.stickers, true);
|
||||
});
|
||||
|
||||
MTProto.apiManager.invokeApi('messages.getAllStickers', {hash: 0}).then((res) => {
|
||||
let stickers: {
|
||||
_: 'messages.allStickers',
|
||||
hash: number,
|
||||
sets: Array<MTStickerSet>
|
||||
} = res as any;
|
||||
|
||||
stickers.sets/* .slice(0, 10) */.forEach(async(set) => {
|
||||
let categoryDiv = document.createElement('div');
|
||||
categoryDiv.classList.add('sticker-category');
|
||||
|
||||
let li = document.createElement('li');
|
||||
li.classList.add('btn-icon');
|
||||
|
||||
menu.append(li);
|
||||
|
||||
stickersDiv.append(categoryDiv);
|
||||
|
||||
let stickerSet = await appStickersManager.getStickerSet(set);
|
||||
|
||||
if(stickerSet.set.thumb) {
|
||||
let thumb = stickerSet.set.thumb;
|
||||
|
||||
appStickersManager.getStickerSetThumb(stickerSet.set).then(async(blob) => {
|
||||
if(thumb.w == 1 && thumb.h == 1) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.addEventListener('loadend', async(e) => {
|
||||
// @ts-ignore
|
||||
const text = e.srcElement.result;
|
||||
let json = await CryptoWorker.gzipUncompress<string>(text, true);
|
||||
|
||||
let animation = await lottieLoader.loadAnimation({
|
||||
container: li,
|
||||
loop: true,
|
||||
autoplay: false,
|
||||
animationData: JSON.parse(json)
|
||||
}, EMOTICONSSTICKERGROUP);
|
||||
});
|
||||
|
||||
reader.readAsArrayBuffer(blob);
|
||||
} else {
|
||||
let image = new Image();
|
||||
image.src = URL.createObjectURL(blob);
|
||||
|
||||
li.append(image);
|
||||
}
|
||||
});
|
||||
} else { // as thumb will be used first sticker
|
||||
wrapSticker(stickerSet.documents[0], li as any, undefined, undefined, EMOTICONSSTICKERGROUP); // kostil
|
||||
}
|
||||
|
||||
categoryPush(categoryDiv, stickerSet.documents);
|
||||
});
|
||||
});
|
||||
|
||||
let prevCategoryIndex = 0;
|
||||
let stickersScroll = new Scrollable(contentStickersDiv);
|
||||
stickersScroll.container.addEventListener('scroll', (e) => {
|
||||
lazyLoadQueue.check();
|
||||
lottieLoader.checkAnimations();
|
||||
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, stickersScroll.container);
|
||||
});
|
||||
stickersScroll.setVirtualContainer(stickersDiv);
|
||||
|
||||
emoticonsMenuOnClick(menu, heights, stickersScroll);
|
||||
|
||||
stickersInit = null;
|
||||
};
|
||||
|
||||
return {dropdown, lazyLoadQueue};
|
||||
};
|
||||
|
||||
export default () => import('../lib/services').then(services => {
|
||||
console.log('included services', services);
|
||||
@ -476,142 +121,7 @@ export default () => import('../lib/services').then(services => {
|
||||
});
|
||||
return;
|
||||
*/
|
||||
let messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */;
|
||||
messageInput.addEventListener('keydown', function(this: typeof messageInput, e: KeyboardEvent) {
|
||||
if(e.key == 'Enter') {
|
||||
if(e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
let lastTimeType = 0;
|
||||
messageInput.addEventListener('input', function(this: typeof messageInput, e) {
|
||||
//console.log('messageInput input', this.innerText, serializeNodes(Array.from(messageInput.childNodes)));
|
||||
if(!this.innerText.trim() && !serializeNodes(Array.from(messageInput.childNodes)).trim()) {
|
||||
this.innerHTML = '';
|
||||
btnSend.classList.remove('tgico-send');
|
||||
btnSend.classList.add('tgico-microphone2');
|
||||
|
||||
appImManager.setTyping('sendMessageCancelAction');
|
||||
} else if(!btnSend.classList.contains('tgico-send')) {
|
||||
btnSend.classList.add('tgico-send');
|
||||
btnSend.classList.remove('tgico-microphone2');
|
||||
|
||||
let time = Date.now();
|
||||
if(time - lastTimeType >= 6000) {
|
||||
lastTimeType = time;
|
||||
appImManager.setTyping('sendMessageTypingAction');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let serializeNodes = (nodes: Node[]): string => {
|
||||
return nodes.reduce((str, child: any) => {
|
||||
//console.log('childNode', str, child, typeof(child), typeof(child) === 'string', child.innerText);
|
||||
|
||||
if(typeof(child) === 'object' && child.textContent) return str += child.textContent;
|
||||
if(child.innerText) return str += child.innerText;
|
||||
if(child.tagName == 'IMG' && child.classList && child.classList.contains('emoji')) return str += child.getAttribute('emoji');
|
||||
|
||||
return str;
|
||||
}, '');
|
||||
};
|
||||
|
||||
messageInput.addEventListener('copy', function(e) {
|
||||
const selection = document.getSelection();
|
||||
|
||||
let range = selection.getRangeAt(0);
|
||||
let ancestorContainer = range.commonAncestorContainer;
|
||||
|
||||
let str = '';
|
||||
|
||||
let selectedNodes = Array.from(ancestorContainer.childNodes).slice(range.startOffset, range.endOffset);
|
||||
if(selectedNodes.length) {
|
||||
str = serializeNodes(selectedNodes);
|
||||
} else {
|
||||
str = selection.toString();
|
||||
}
|
||||
|
||||
console.log('messageInput copy', str, ancestorContainer.childNodes, range);
|
||||
|
||||
// @ts-ignore
|
||||
event.clipboardData.setData('text/plain', str);
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
messageInput.addEventListener('paste', function(this: typeof messageInput, e) {
|
||||
e.preventDefault();
|
||||
// @ts-ignore
|
||||
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||
|
||||
// console.log('messageInput paste', text);
|
||||
|
||||
text = RichTextProcessor.wrapRichText(text);
|
||||
|
||||
// console.log('messageInput paste after', text);
|
||||
|
||||
// @ts-ignore
|
||||
//let html = (e.originalEvent || e).clipboardData.getData('text/html');
|
||||
|
||||
// @ts-ignore
|
||||
//console.log('paste text', text, );
|
||||
window.document.execCommand('insertHTML', false, text);
|
||||
});
|
||||
|
||||
let fileInput = document.getElementById('input-file') as HTMLInputElement;
|
||||
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
var file = (e.target as HTMLInputElement & EventTarget).files[0];
|
||||
if(!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('selected file:', file, typeof(file));
|
||||
|
||||
fileInput.value = '';
|
||||
|
||||
appMessagesManager.sendFile(appImManager.peerID, file, {isMedia: true});
|
||||
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
|
||||
|
||||
/* MTProto.apiFileManager.uploadFile(file).then((inputFile) => {
|
||||
console.log('uploaded smthn', inputFile);
|
||||
}); */
|
||||
}, false);
|
||||
|
||||
pageEl.querySelector('#attach-file').addEventListener('click', () => {
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
let inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
|
||||
|
||||
let inputScroll = new Scrollable(inputMessageContainer);
|
||||
|
||||
let sendMessage = () => {
|
||||
let str = serializeNodes(Array.from(messageInput.childNodes));
|
||||
|
||||
//console.log('childnode str after:', str);
|
||||
|
||||
appMessagesManager.sendText(appImManager.peerID, str, {
|
||||
replyToMsgID: appImManager.replyToMsgID == 0 ? undefined : appImManager.replyToMsgID
|
||||
});
|
||||
appImManager.replyToMsgID = 0;
|
||||
appImManager.replyElements.container.classList.remove('active');
|
||||
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
|
||||
messageInput.innerText = '';
|
||||
|
||||
btnSend.classList.remove('tgico-send');
|
||||
btnSend.classList.add('tgico-microphone2');
|
||||
};
|
||||
|
||||
let btnSend = document.getElementById('btn-send') as HTMLButtonElement;
|
||||
btnSend.addEventListener('click', () => {
|
||||
if(btnSend.classList.contains('tgico-send')) {
|
||||
sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
/* function placeCaretAfterNode(node: HTMLElement) {
|
||||
if (typeof window.getSelection != "undefined") {
|
||||
@ -668,43 +178,6 @@ export default () => import('../lib/services').then(services => {
|
||||
};
|
||||
});
|
||||
|
||||
let emoticonsDropdown: HTMLDivElement = null;
|
||||
let emoticonsTimeout: number = 0;
|
||||
let toggleEmoticons = pageEl.querySelector('.toggle-emoticons') as HTMLButtonElement;
|
||||
let emoticonsLazyLoadQueue: LazyLoadQueue = null;
|
||||
toggleEmoticons.onmouseover = (e) => {
|
||||
clearTimeout(emoticonsTimeout);
|
||||
emoticonsTimeout = setTimeout(() => {
|
||||
if(!emoticonsDropdown) {
|
||||
let res = initEmoticonsDropdown(pageEl, appImManager,
|
||||
appMessagesManager, messageInput, toggleEmoticons, btnSend);
|
||||
|
||||
emoticonsDropdown = res.dropdown;
|
||||
emoticonsLazyLoadQueue = res.lazyLoadQueue;
|
||||
|
||||
toggleEmoticons.onmouseout = emoticonsDropdown.onmouseout = (e) => {
|
||||
clearTimeout(emoticonsTimeout);
|
||||
emoticonsTimeout = setTimeout(() => {
|
||||
emoticonsDropdown.classList.remove('active');
|
||||
toggleEmoticons.classList.remove('active');
|
||||
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
emoticonsDropdown.onmouseover = (e) => {
|
||||
clearTimeout(emoticonsTimeout);
|
||||
};
|
||||
} else {
|
||||
emoticonsDropdown.classList.add('active');
|
||||
emoticonsLazyLoadQueue.check();
|
||||
}
|
||||
|
||||
toggleEmoticons.classList.add('active');
|
||||
|
||||
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||
}, 0/* 200 */);
|
||||
};
|
||||
|
||||
/* toggleEmoticons.onclick = (e) => {
|
||||
if(!emoticonsDropdown) {
|
||||
emoticonsDropdown = initEmoticonsDropdown(pageEl, appImManager,
|
||||
@ -729,8 +202,6 @@ export default () => import('../lib/services').then(services => {
|
||||
el.classList.remove('menu-open');
|
||||
openedMenu.classList.remove('active');
|
||||
} else {
|
||||
el.classList.add('menu-open');
|
||||
|
||||
openBtnMenu(openedMenu);
|
||||
}
|
||||
});
|
||||
|
@ -4,11 +4,12 @@ import appUsersManager from "./appUsersManager";
|
||||
import appMessagesManager from "./appMessagesManager";
|
||||
import appPeersManager from "./appPeersManager";
|
||||
import appProfileManager from "./appProfileManager";
|
||||
import { ProgressivePreloader, wrapDocument, wrapSticker, wrapVideo, wrapPhoto, openBtnMenu } from "../../components/misc";
|
||||
import { ProgressivePreloader, wrapDocument, wrapSticker, wrapVideo, wrapPhoto, openBtnMenu, LazyLoadQueue } from "../../components/misc";
|
||||
import appDialogsManager from "./appDialogsManager";
|
||||
import { RichTextProcessor } from "../richtextprocessor";
|
||||
import appPhotosManager from "./appPhotosManager";
|
||||
import appSidebarRight from './appSidebarRight';
|
||||
import Scrollable from '../../components/scrollable';
|
||||
|
||||
import { logger } from "../polyfill";
|
||||
import lottieLoader from "../lottieLoader";
|
||||
@ -17,6 +18,7 @@ import appSidebarLeft from "./appSidebarLeft";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import appMessagesIDsManager from "./appMessagesIDsManager";
|
||||
import apiUpdatesManager from './apiUpdatesManager';
|
||||
import initEmoticonsDropdown, { EMOTICONSSTICKERGROUP } from '../../components/emoticonsDropdown';
|
||||
|
||||
console.log('appImManager included!');
|
||||
|
||||
@ -86,6 +88,221 @@ class ScrollPosition {
|
||||
}
|
||||
}
|
||||
|
||||
class ChatInput {
|
||||
public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
|
||||
public messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */;
|
||||
public fileInput = document.getElementById('input-file') as HTMLInputElement;
|
||||
public inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
|
||||
public inputScroll = new Scrollable(this.inputMessageContainer);
|
||||
public btnSend = document.getElementById('btn-send') as HTMLButtonElement;
|
||||
public emoticonsDropdown: HTMLDivElement = null;
|
||||
public emoticonsTimeout: number = 0;
|
||||
public toggleEmoticons: HTMLButtonElement;
|
||||
public emoticonsLazyLoadQueue: LazyLoadQueue = null;
|
||||
public lastUrl = '';
|
||||
public lastTimeType = 0;
|
||||
|
||||
constructor() {
|
||||
this.toggleEmoticons = this.pageEl.querySelector('.toggle-emoticons') as HTMLButtonElement;
|
||||
|
||||
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if(e.key == 'Enter') {
|
||||
if(e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
this.messageInput.addEventListener('input', (e) => {
|
||||
console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
|
||||
|
||||
let value = this.messageInput.innerText;
|
||||
|
||||
let entities = RichTextProcessor.parseEntities(value);
|
||||
console.log('messageInput entities', entities);
|
||||
|
||||
let entityUrl = entities.find(e => e._ == 'messageEntityUrl');
|
||||
if(entityUrl) { // need to get webpage
|
||||
let url = value.slice(entityUrl.offset, entityUrl.offset + entityUrl.length);
|
||||
|
||||
console.log('messageInput url:', url);
|
||||
|
||||
if(this.lastUrl != url) {
|
||||
this.lastUrl = url;
|
||||
apiManager.invokeApi('messages.getWebPage', {
|
||||
url: url,
|
||||
hash: 0
|
||||
}).then((webpage: any) => {
|
||||
if(this.lastUrl != url) return;
|
||||
console.log(webpage);
|
||||
|
||||
appImManager.replyElements.titleEl.innerText = webpage.site_name || webpage.title || '';
|
||||
appImManager.replyElements.subtitleEl.innerText = webpage.description || webpage.url || '';
|
||||
appImManager.replyElements.container.classList.add('active');
|
||||
appImManager.replyToMsgID = 0;
|
||||
appImManager.noWebPage = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(!value.trim() && !this.serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
|
||||
this.messageInput.innerHTML = '';
|
||||
this.btnSend.classList.remove('tgico-send');
|
||||
this.btnSend.classList.add('tgico-microphone2');
|
||||
|
||||
appImManager.setTyping('sendMessageCancelAction');
|
||||
} else if(!this.btnSend.classList.contains('tgico-send')) {
|
||||
this.btnSend.classList.add('tgico-send');
|
||||
this.btnSend.classList.remove('tgico-microphone2');
|
||||
|
||||
let time = Date.now();
|
||||
if(time - this.lastTimeType >= 6000) {
|
||||
this.lastTimeType = time;
|
||||
appImManager.setTyping('sendMessageTypingAction');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.messageInput.addEventListener('copy', (e) => {
|
||||
const selection = document.getSelection();
|
||||
|
||||
let range = selection.getRangeAt(0);
|
||||
let ancestorContainer = range.commonAncestorContainer;
|
||||
|
||||
let str = '';
|
||||
|
||||
let selectedNodes = Array.from(ancestorContainer.childNodes).slice(range.startOffset, range.endOffset);
|
||||
if(selectedNodes.length) {
|
||||
str = this.serializeNodes(selectedNodes);
|
||||
} else {
|
||||
str = selection.toString();
|
||||
}
|
||||
|
||||
console.log('messageInput copy', str, ancestorContainer.childNodes, range);
|
||||
|
||||
// @ts-ignore
|
||||
event.clipboardData.setData('text/plain', str);
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
this.messageInput.addEventListener('paste', (e) => {
|
||||
e.preventDefault();
|
||||
// @ts-ignore
|
||||
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||
|
||||
// console.log('messageInput paste', text);
|
||||
let entities = RichTextProcessor.parseEntities(text);
|
||||
|
||||
text = RichTextProcessor.wrapRichText(text, {
|
||||
entities: entities.filter(e => e._ == 'messageEntityEmoji')
|
||||
});
|
||||
|
||||
// console.log('messageInput paste after', text);
|
||||
|
||||
// @ts-ignore
|
||||
//let html = (e.originalEvent || e).clipboardData.getData('text/html');
|
||||
|
||||
// @ts-ignore
|
||||
//console.log('paste text', text, );
|
||||
window.document.execCommand('insertHTML', false, text);
|
||||
});
|
||||
|
||||
this.fileInput.addEventListener('change', (e) => {
|
||||
var file = (e.target as HTMLInputElement & EventTarget).files[0];
|
||||
if(!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('selected file:', file, typeof(file));
|
||||
|
||||
this.fileInput.value = '';
|
||||
|
||||
appMessagesManager.sendFile(appImManager.peerID, file, {isMedia: true});
|
||||
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
|
||||
|
||||
/* MTProto.apiFileManager.uploadFile(file).then((inputFile) => {
|
||||
console.log('uploaded smthn', inputFile);
|
||||
}); */
|
||||
}, false);
|
||||
|
||||
this.pageEl.querySelector('#attach-file').addEventListener('click', () => {
|
||||
this.fileInput.click();
|
||||
});
|
||||
|
||||
this.btnSend.addEventListener('click', () => {
|
||||
if(this.btnSend.classList.contains('tgico-send')) {
|
||||
this.sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
this.toggleEmoticons.onmouseover = (e) => {
|
||||
clearTimeout(this.emoticonsTimeout);
|
||||
this.emoticonsTimeout = setTimeout(() => {
|
||||
if(!this.emoticonsDropdown) {
|
||||
let res = initEmoticonsDropdown(this.pageEl, appImManager,
|
||||
appMessagesManager, this.messageInput, this.toggleEmoticons, this.btnSend);
|
||||
|
||||
this.emoticonsDropdown = res.dropdown;
|
||||
this.emoticonsLazyLoadQueue = res.lazyLoadQueue;
|
||||
|
||||
this.toggleEmoticons.onmouseout = this.emoticonsDropdown.onmouseout = (e) => {
|
||||
clearTimeout(this.emoticonsTimeout);
|
||||
this.emoticonsTimeout = setTimeout(() => {
|
||||
this.emoticonsDropdown.classList.remove('active');
|
||||
this.toggleEmoticons.classList.remove('active');
|
||||
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
this.emoticonsDropdown.onmouseover = (e) => {
|
||||
clearTimeout(this.emoticonsTimeout);
|
||||
};
|
||||
} else {
|
||||
this.emoticonsDropdown.classList.add('active');
|
||||
this.emoticonsLazyLoadQueue.check();
|
||||
}
|
||||
|
||||
this.toggleEmoticons.classList.add('active');
|
||||
|
||||
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||
}, 0/* 200 */);
|
||||
};
|
||||
}
|
||||
|
||||
public serializeNodes(nodes: Node[]): string {
|
||||
return nodes.reduce((str, child: any) => {
|
||||
//console.log('childNode', str, child, typeof(child), typeof(child) === 'string', child.innerText);
|
||||
|
||||
if(typeof(child) === 'object' && child.textContent) return str += child.textContent;
|
||||
if(child.innerText) return str += child.innerText;
|
||||
if(child.tagName == 'IMG' && child.classList && child.classList.contains('emoji')) return str += child.getAttribute('emoji');
|
||||
|
||||
return str;
|
||||
}, '');
|
||||
};
|
||||
|
||||
public sendMessage() {
|
||||
let str = this.serializeNodes(Array.from(this.messageInput.childNodes));
|
||||
|
||||
//console.log('childnode str after:', str);
|
||||
this.lastUrl = '';
|
||||
appMessagesManager.sendText(appImManager.peerID, str, {
|
||||
replyToMsgID: appImManager.replyToMsgID == 0 ? undefined : appImManager.replyToMsgID,
|
||||
noWebPage: appImManager.noWebPage
|
||||
});
|
||||
appImManager.replyToMsgID = 0;
|
||||
appImManager.noWebPage = false;
|
||||
appImManager.replyElements.container.classList.remove('active');
|
||||
appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight;
|
||||
this.messageInput.innerText = '';
|
||||
|
||||
this.btnSend.classList.remove('tgico-send');
|
||||
this.btnSend.classList.add('tgico-microphone2');
|
||||
};
|
||||
}
|
||||
|
||||
export class AppImManager {
|
||||
public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
|
||||
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
|
||||
@ -100,6 +317,8 @@ export class AppImManager {
|
||||
private getHistoryPromise: Promise<boolean>;
|
||||
private getHistoryTimeout = 0;
|
||||
|
||||
private chatInputC: ChatInput = null;
|
||||
|
||||
public myID = 0;
|
||||
public peerID = 0;
|
||||
public muted = false;
|
||||
@ -155,10 +374,13 @@ export class AppImManager {
|
||||
} = {};
|
||||
|
||||
public replyToMsgID = 0;
|
||||
public noWebPage = false;
|
||||
|
||||
constructor() {
|
||||
this.log = logger('IM');
|
||||
|
||||
this.chatInputC = new ChatInput();
|
||||
|
||||
this.preloader = new ProgressivePreloader(null, false);
|
||||
|
||||
this.popupDeleteMessage.popupEl = this.pageEl.querySelector('.popup-delete-message') as HTMLDivElement;
|
||||
@ -265,6 +487,15 @@ export class AppImManager {
|
||||
}
|
||||
|
||||
appMediaViewer.openMedia(message, true);
|
||||
} else if(target.tagName == 'DIV') {
|
||||
let bubble = findUpClassName(e.target, 'bubble');
|
||||
|
||||
if(bubble) {
|
||||
if(bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) {
|
||||
let originalMessageID = +bubble.getAttribute('data-original-mid');
|
||||
this.setPeer(this.peerID, originalMessageID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('chatInner click', e);
|
||||
@ -288,7 +519,12 @@ export class AppImManager {
|
||||
this.btnMute.addEventListener('click', () => this.mutePeer());
|
||||
|
||||
this.chatInner.addEventListener('contextmenu', e => {
|
||||
let bubble = findUpClassName(e.target, 'bubble');
|
||||
let bubble: HTMLDivElement = null;
|
||||
|
||||
try {
|
||||
bubble = findUpClassName(e.target, 'bubble');
|
||||
} catch(e) {}
|
||||
|
||||
if(bubble) {
|
||||
e.preventDefault();
|
||||
e.cancelBubble = true;
|
||||
@ -394,6 +630,7 @@ export class AppImManager {
|
||||
this.replyElements.cancelBtn.addEventListener('click', () => {
|
||||
this.replyElements.container.classList.remove('active');
|
||||
this.replyToMsgID = 0;
|
||||
this.noWebPage = true;
|
||||
});
|
||||
|
||||
this.popupDeleteMessage.deleteBothBtn.addEventListener('click', () => {
|
||||
@ -684,14 +921,12 @@ export class AppImManager {
|
||||
|
||||
lottieLoader.checkAnimations(false, 'chat', true);
|
||||
|
||||
console.time('chatInner clear');
|
||||
// clear input
|
||||
this.chatInputC.messageInput.innerHTML = '';
|
||||
this.replyElements.cancelBtn.click();
|
||||
|
||||
// clear messages
|
||||
this.chatInner.innerHTML = '';
|
||||
/* Array.from(this.chatInner.children).forEach(c => {
|
||||
this.chatInner.removeChild(c);
|
||||
}); */
|
||||
|
||||
console.timeEnd('chatInner clear');
|
||||
|
||||
//appSidebarRight.minMediaID = {};
|
||||
}
|
||||
@ -706,13 +941,18 @@ export class AppImManager {
|
||||
|
||||
let samePeer = this.peerID == peerID;
|
||||
|
||||
if(samePeer && !testScroll && !lastMsgID) {
|
||||
return Promise.resolve(true); // uncomment
|
||||
}
|
||||
if(samePeer) {
|
||||
if(!testScroll && !lastMsgID) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
if(samePeer && lastMsgID == this.lastDialog.top_message) {
|
||||
if(this.bubbles[lastMsgID]) {
|
||||
this.scroll.scrollTop = this.scroll.scrollHeight;
|
||||
if(lastMsgID == this.lastDialog.top_message) {
|
||||
this.scroll.scrollTop = this.scroll.scrollHeight;
|
||||
} else {
|
||||
this.bubbles[lastMsgID].scrollIntoView();
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
@ -1135,17 +1375,19 @@ export class AppImManager {
|
||||
}
|
||||
}
|
||||
|
||||
if(message.fwd_from) {
|
||||
let fwd = message.fwd_from;
|
||||
//let peerFrom = appPeersManager.getPeerTitle()
|
||||
/* let fromTitle = */appPeersManager.getPeerTitle(fwd.from_id);
|
||||
}
|
||||
|
||||
if((this.peerID < 0 && !our) || message.fwd_from || message.reply_to_mid) { // chat
|
||||
let title = appPeersManager.getPeerTitle(message.fwdFromID || message.fromID);
|
||||
|
||||
let isHidden = message.fwd_from && !message.fwd_from.from_id;
|
||||
if(isHidden) {
|
||||
this.log('message render hidden', message);
|
||||
title = message.fwd_from.from_name;
|
||||
bubble.classList.add('hidden-profile');
|
||||
}
|
||||
|
||||
//this.log(title);
|
||||
|
||||
if(message.fwdFromID) {
|
||||
if(message.fwdFromID || message.fwd_from) {
|
||||
bubble.classList.add('forwarded');
|
||||
|
||||
if(!bubble.classList.contains('sticker')) {
|
||||
@ -1171,16 +1413,39 @@ export class AppImManager {
|
||||
let originalMessage = appMessagesManager.getMessage(message.reply_to_mid);
|
||||
let originalPeerTitle = appPeersManager.getPeerTitle(originalMessage.fromID) || '';
|
||||
|
||||
this.log('message to render one more time punks not dead', originalMessage, originalPeerTitle, bubble);
|
||||
|
||||
let originalText = '';
|
||||
if(originalMessage.message) {
|
||||
originalText = RichTextProcessor.wrapRichText(originalMessage.message, {
|
||||
entities: originalMessage.totalEntities
|
||||
});
|
||||
}
|
||||
|
||||
if(originalMessage.media) {
|
||||
switch(originalMessage.media._) {
|
||||
case 'messageMediaPhoto':
|
||||
if(!originalText) originalText = 'Photo';
|
||||
break;
|
||||
|
||||
default:
|
||||
if(!originalText) originalText = originalMessage.media._;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nameEl.innerText = originalPeerTitle;
|
||||
textDiv.innerHTML = RichTextProcessor.wrapRichText(originalMessage.message, {
|
||||
entities: originalMessage.totalEntities
|
||||
});
|
||||
textDiv.innerHTML = originalText;
|
||||
|
||||
quote.append(nameEl, textDiv);
|
||||
box.append(quote);
|
||||
|
||||
if(originalMessage.mid) {
|
||||
bubble.setAttribute('data-original-mid', originalMessage.mid);
|
||||
}
|
||||
|
||||
bubble.append(box);
|
||||
//bubble.classList.add('reply');
|
||||
bubble.classList.add('is-reply');
|
||||
}
|
||||
|
||||
/* if(message.media) {
|
||||
@ -1212,7 +1477,8 @@ export class AppImManager {
|
||||
//}
|
||||
}
|
||||
|
||||
if(!our && this.peerID < 0) {
|
||||
if(!our && this.peerID < 0 &&
|
||||
(!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) {
|
||||
let avatarDiv = document.createElement('div');
|
||||
avatarDiv.classList.add('user-avatar');
|
||||
|
||||
@ -1556,4 +1822,5 @@ export class AppImManager {
|
||||
}
|
||||
}
|
||||
|
||||
export default new AppImManager();
|
||||
const appImManager = new AppImManager();
|
||||
export default appImManager;
|
||||
|
@ -186,6 +186,7 @@ export class AppMessagesManager {
|
||||
var isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID);
|
||||
var asChannel = isChannel && !isMegagroup ? true : false;
|
||||
var message: any;
|
||||
let noWebPage = options.noWebPage || false;
|
||||
|
||||
if(historyStorage === undefined) {
|
||||
historyStorage = this.historiesStorage[peerID] = {count: null, history: [], pending: []};
|
||||
@ -267,6 +268,10 @@ export class AppMessagesManager {
|
||||
flags |= 128;
|
||||
}
|
||||
|
||||
if(noWebPage) {
|
||||
flags |= 2;
|
||||
}
|
||||
|
||||
var apiPromise: any;
|
||||
if(options.viaBotID) {
|
||||
apiPromise = MTProto.apiManager.invokeApi('messages.sendInlineBotResult', {
|
||||
@ -284,6 +289,7 @@ export class AppMessagesManager {
|
||||
|
||||
apiPromise = MTProto.apiManager.invokeApi('messages.sendMessage', {
|
||||
flags: flags,
|
||||
no_webpage: noWebPage,
|
||||
peer: AppPeersManager.getInputPeerByID(peerID),
|
||||
message: text,
|
||||
random_id: randomID,
|
||||
|
@ -57,8 +57,11 @@ class AppSidebarLeft {
|
||||
this.listsContainer = new Scrollable(this.searchContainer).container;
|
||||
this.searchMessagesList = document.createElement('ul');
|
||||
|
||||
this.savedBtn.addEventListener('click', () => {
|
||||
appImManager.setPeer(appImManager.myID);
|
||||
this.savedBtn.addEventListener('click', (e) => {
|
||||
this.log('savedbtn click');
|
||||
setTimeout(() => { // menu doesn't close if no timeout (lol)
|
||||
appImManager.setPeer(appImManager.myID);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
/* this.listsContainer.insertBefore(this.searchMessagesList, this.listsContainer.lastElementChild);
|
||||
@ -141,6 +144,8 @@ class AppSidebarLeft {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}, true);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
|
@ -257,7 +257,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.message:not(.message-empty) + .attachment {
|
||||
.message:not(.message-empty) + .attachment,
|
||||
&.is-reply .attachment {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
@ -682,6 +683,7 @@
|
||||
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07);
|
||||
margin-right: .5rem;
|
||||
padding: 4.5px .5rem;
|
||||
/* padding: 3px .5rem 6px .5rem; */
|
||||
min-height: 3.25rem;
|
||||
max-height: 30rem;
|
||||
caret-color: $button-primary-background;
|
||||
@ -716,7 +718,7 @@
|
||||
height: 0px;
|
||||
|
||||
&.active {
|
||||
height: 35px;
|
||||
height: 39px;
|
||||
}
|
||||
|
||||
.reply {
|
||||
@ -732,7 +734,7 @@
|
||||
align-items: flex-end;
|
||||
|
||||
.btn-icon:before {
|
||||
vertical-align: middle;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user