diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts
index a5a623f1..9d417d78 100644
--- a/src/components/chat/bubbles.ts
+++ b/src/components/chat/bubbles.ts
@@ -548,14 +548,14 @@ export default class ChatBubbles {
return;
}
- if(['IMG', 'DIV', "AVATAR-ELEMENT"].indexOf(target.tagName) === -1) target = findUpTag(target, 'DIV');
+ if(['IMG', 'DIV', "AVATAR-ELEMENT", 'A'].indexOf(target.tagName) === -1) target = findUpTag(target, 'DIV');
- if(target.tagName == 'DIV' || target.tagName == "AVATAR-ELEMENT") {
+ if(target.tagName == 'DIV' || target.tagName == "AVATAR-ELEMENT" || target.tagName == 'A') {
if(target.classList.contains('goto-original')) {
- let savedFrom = bubble.dataset.savedFrom;
- let splitted = savedFrom.split('_');
- let peerId = +splitted[0];
- let msgId = +splitted[1];
+ const savedFrom = bubble.dataset.savedFrom;
+ const splitted = savedFrom.split('_');
+ const peerId = +splitted[0];
+ const msgId = +splitted[1];
////this.log('savedFrom', peerId, msgID);
this.chat.appImManager.setInnerPeer(peerId, msgId);
return;
@@ -564,8 +564,23 @@ export default class ChatBubbles {
new PopupForward([mid]);
//appSidebarRight.forwardTab.open([mid]);
return;
- } else if(target.classList.contains('name')) {
- let peerId = +target.dataset.peerId;
+ }/* else if(target.classList.contains('follow')) {
+ cancelEvent(e);
+ const savedFrom = target.dataset.follow;
+ const splitted = savedFrom.split('_');
+ this.chat.appImManager.setInnerPeer(+splitted[0], splitted.length > 1 ? +splitted[1] : undefined);
+
+ return;
+ } else if(target.classList.contains('mention')) {
+ cancelEvent(e);
+ const username = target.innerText;
+ this.appUsersManager.resolveUsername(username.slice(1)).then(peer => {
+ this.chat.appImManager.setInnerPeer(peer._ == 'user' ? peer.id : -peer.id);
+ });
+
+ return;
+ } */ else if(target.classList.contains('name')) {
+ const peerId = +target.dataset.peerId;
if(peerId) {
this.chat.appImManager.setInnerPeer(peerId);
@@ -573,7 +588,7 @@ export default class ChatBubbles {
return;
} else if(target.tagName == "AVATAR-ELEMENT") {
- let peerId = +target.getAttribute('peer');
+ const peerId = +target.getAttribute('peer');
if(peerId) {
this.chat.appImManager.setInnerPeer(peerId);
@@ -1405,12 +1420,17 @@ export default class ChatBubbles {
} else if(message.grouped_id && albumMustBeRenderedFull) {
const t = this.appMessagesManager.getAlbumText(message.grouped_id);
messageMessage = t.message;
+ //totalEntities = t.entities;
totalEntities = t.totalEntities;
} else if(messageMedia?.document?.type != 'sticker') {
messageMessage = message.message;
+ //totalEntities = message.entities;
totalEntities = message.totalEntities;
}
+ /* let richText = RichTextProcessor.wrapRichText(messageMessage, {
+ entities: totalEntities
+ }); */
let richText = RichTextProcessor.wrapRichText(messageMessage, {
entities: totalEntities
});
diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts
index 139512cf..0d4b429e 100644
--- a/src/lib/appManagers/appImManager.ts
+++ b/src/lib/appManagers/appImManager.ts
@@ -30,6 +30,7 @@ import appPollsManager from './appPollsManager';
import SetTransition from '../../components/singleTransition';
import { isSafari } from '../../helpers/userAgent';
import ChatDragAndDrop from '../../components/chat/dragAndDrop';
+import appMessagesIdsManager from './appMessagesIdsManager';
//console.log('appImManager included33!');
@@ -134,6 +135,38 @@ export class AppImManager {
this.createNewChat();
this.chatsSelectTab(0);
+ window.addEventListener('hashchange', (e) => {
+ const hash = location.hash;
+ const splitted = hash.split('?');
+
+ const params: any = {};
+ splitted[1].split('&').forEach(item => {
+ params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);
+ });
+
+ this.log('hashchange', splitted[0], params);
+
+ switch(splitted[0]) {
+ case '#/im': {
+ const p = params.p;
+ if(p[0] === '@') {
+ let postId = params.post !== undefined ? +params.post : undefined;
+ appUsersManager.resolveUsername(p).then(peer => {
+ const isUser = peer._ == 'user';
+ const peerId = isUser ? peer.id : -peer.id;
+ if(postId) {
+ postId = appMessagesIdsManager.getFullMessageId(postId, -peerId);
+ }
+
+ this.setInnerPeer(peerId, postId);
+ });
+ }
+ }
+ }
+
+ location.hash = '';
+ });
+
//apiUpdatesManager.attach();
}
diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts
index e84068b4..5830abe9 100644
--- a/src/lib/appManagers/appMessagesManager.ts
+++ b/src/lib/appManagers/appMessagesManager.ts
@@ -1695,22 +1695,24 @@ export class AppMessagesManager {
public getAlbumText(grouped_id: string) {
const group = appMessagesManager.groupedMessagesStorage[grouped_id];
- let foundMessages = 0, message: string, totalEntities: MessageEntity[];
+ let foundMessages = 0, message: string, totalEntities: MessageEntity[], entities: MessageEntity[];
for(const i in group) {
const m = group[i];
if(m.message) {
if(++foundMessages > 1) break;
message = m.message;
totalEntities = m.totalEntities;
+ entities = m.entities;
}
}
if(foundMessages > 1) {
message = undefined;
totalEntities = undefined;
+ entities = undefined;
}
- return {message, totalEntities};
+ return {message, entities, totalEntities};
}
public getMidsByAlbum(grouped_id: string) {
@@ -1946,9 +1948,14 @@ export class AppMessagesManager {
}
if(message.message && message.message.length && !message.totalEntities) {
+ //message.totalEntities = (message.entities || []).slice();
const myEntities = RichTextProcessor.parseEntities(message.message);
const apiEntities = message.entities || [];
- message.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !message.pending);
+ //message.totalEntities = RichTextProcessor.mergeEntitiesNew(myEntities, apiEntities, !message.pending);
+ message.totalEntities = RichTextProcessor.mergeEntities(apiEntities, myEntities, !message.pending); // ! only in this order, otherwise bold and emoji formatting won't work
+ /* message.totalEntities = RichTextProcessor.mergeEntities(apiEntities, apiEntities, !message.pending);
+ message.totalEntities = RichTextProcessor.mergeEntities(myEntities, message.totalEntities, !message.pending); */
+ //message.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !message.pending);
}
//if(!options.isEdited) {
diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts
index 0ce2d87f..8132ef6f 100644
--- a/src/lib/appManagers/appUsersManager.ts
+++ b/src/lib/appManagers/appUsersManager.ts
@@ -147,16 +147,21 @@ export class AppUsersManager {
return this.contactsFillPromise || (this.contactsFillPromise = promise);
}
- public async resolveUsername(username: string) {
+ public resolveUsername(username: string) {
+ if(username[0] == '@') {
+ username = username.slice(1);
+ }
+
+ username = username.toLowerCase();
if(this.usernames[username]) {
- return this.users[this.usernames[username]];
+ return Promise.resolve(this.users[this.usernames[username]]);
}
- return await apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => {
- this.saveApiUser(resolvedPeer.users[0] as User);
+ return apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => {
+ this.saveApiUsers(resolvedPeer.users);
appChatsManager.saveApiChats(resolvedPeer.chats);
- return this.users[this.usernames[username]];
+ return appPeersManager.getPeer(appPeersManager.getPeerId(resolvedPeer.peer));
});
}
diff --git a/src/lib/richtextprocessor.ts b/src/lib/richtextprocessor.ts
index d740613c..9ab79aaf 100644
--- a/src/lib/richtextprocessor.ts
+++ b/src/lib/richtextprocessor.ts
@@ -306,17 +306,18 @@ namespace RichTextProcessor {
return newText;
}
- export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[], fromApi?: boolean) {
+ /* export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[], fromApi?: boolean) {
const totalEntities = newEntities.slice();
const newLength = newEntities.length;
let startJ = 0;
for(let i = 0, length = currentEntities.length; i < length; i++) {
const curEntity = currentEntities[i];
- /* if(fromApi &&
- curEntity._ != 'messageEntityLinebreak' &&
- curEntity._ != 'messageEntityEmoji') {
- continue;
- } */
+ // if(fromApi &&
+ // curEntity._ != 'messageEntityLinebreak' &&
+ // curEntity._ != 'messageEntityEmoji') {
+ // continue;
+ // }
+
// console.log('s', curEntity, newEntities);
const start = curEntity.offset;
const end = start + curEntity.length;
@@ -362,6 +363,14 @@ namespace RichTextProcessor {
});
// console.log('merge', currentEntities, newEntities, totalEntities)
return totalEntities;
+ } */
+
+ export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[], fromApi?: boolean) {
+ currentEntities = currentEntities.slice();
+ const filtered = newEntities.filter(e => !currentEntities.find(_e => e._ == _e._ && e.offset == _e.offset && e.length == _e.length));
+ currentEntities.push(...filtered);
+ currentEntities.sort((a, b) => a.offset - b.offset);
+ return currentEntities;
}
export function wrapRichNestedText(text: string, nested: MessageEntity[], options: any) {
@@ -387,6 +396,245 @@ namespace RichTextProcessor {
[_ in MessageEntity['_']]: true
}>,
+ nested?: true,
+ contextHashtag?: string
+ }> = {}) {
+ if(!text || !text.length) {
+ return '';
+ }
+
+ const lol: {
+ part: string,
+ offset: number
+ }[] = [];
+ const entities = options.entities || parseEntities(text);
+
+ const passEntities: typeof options.passEntities = options.passEntities || {};
+ const contextSite = options.contextSite || 'Telegram';
+ const contextExternal = contextSite != 'Telegram';
+
+ const insertPart = (entity: MessageEntity, startPart: string, endPart?: string) => {
+ lol.push({part: startPart, offset: entity.offset});
+
+ if(endPart) {
+ lol.unshift({part: endPart, offset: entity.offset + entity.length});
+ }
+ };
+
+ for(const entity of entities) {
+ switch(entity._) {
+ case 'messageEntityBold': {
+ if(!options.noTextFormat) {
+ if(options.wrappingDraft) {
+ insertPart(entity, '', '');
+ } else {
+ insertPart(entity, '', '');
+ }
+ }
+
+ break;
+ }
+
+ case 'messageEntityItalic': {
+ if(!options.noTextFormat) {
+ if(options.wrappingDraft) {
+ insertPart(entity, '', '');
+ } else {
+ insertPart(entity, '', '');
+ }
+ }
+
+ break;
+ }
+
+ case 'messageEntityStrike': {
+ if(options.wrappingDraft) {
+ const styleName = isSafari ? 'text-decoration' : 'text-decoration-line';
+ insertPart(entity, ``, '');
+ } else {
+ insertPart(entity, '', '');
+ }
+
+ break;
+ }
+
+ case 'messageEntityUnderline': {
+ if(options.wrappingDraft) {
+ const styleName = isSafari ? 'text-decoration' : 'text-decoration-line';
+ insertPart(entity, ``, '');
+ } else {
+ insertPart(entity, '', '');
+ }
+
+ break;
+ }
+
+ case 'messageEntityCode': {
+ if(options.wrappingDraft) {
+ insertPart(entity, '', '');
+ } else {
+ insertPart(entity, '', '
');
+ }
+
+ break;
+ }
+
+ case 'messageEntityPre': {
+ if(!options.noTextFormat) {
+ insertPart(entity, `
`, '
');
+ }
+
+ break;
+ }
+
+ case 'messageEntityHighlight': {
+ insertPart(entity, '', '');
+ break;
+ }
+
+ case 'messageEntityBotCommand': {
+ if(!(options.noLinks || options.noCommands || contextExternal)) {
+ const entityText = text.substr(entity.offset, entity.length);
+ let command = entityText.substr(1);
+ let bot: string | boolean;
+ let atPos: number;
+ if((atPos = command.indexOf('@')) != -1) {
+ bot = command.substr(atPos + 1);
+ command = command.substr(0, atPos);
+ } else {
+ bot = options.fromBot;
+ }
+
+ insertPart(entity, ``, ``);
+ }
+
+ break;
+ }
+
+ case 'messageEntityEmoji': {
+ if(!(options.wrappingDraft && emojiSupported)) { // * fix safari emoji
+ if(emojiSupported) { // ! contenteditable="false" нужен для поля ввода, иначе там будет меняться шрифт в Safari, или же рендерить смайлик напрямую, без контейнера
+ insertPart(entity, '', '');
+ } else {
+ insertPart(entity, `