Browse Source

Refactored links from /# to t.me/

master
morethanwords 3 years ago
parent
commit
4d9793efb7
  1. 43
      src/components/chat/bubbles.ts
  2. 90
      src/lib/appManagers/appImManager.ts
  3. 51
      src/lib/richtextprocessor.ts
  4. 1
      src/scss/partials/_chatBubble.scss

43
src/components/chat/bubbles.ts

@ -43,7 +43,7 @@ import LazyLoadQueue from "../lazyLoadQueue";
import ListenerSetter from "../../helpers/listenerSetter"; import ListenerSetter from "../../helpers/listenerSetter";
import PollElement from "../poll"; import PollElement from "../poll";
import AudioElement from "../audio"; import AudioElement from "../audio";
import { Message, MessageEntity, MessageReplyHeader, ReplyMarkup, Update } from "../../layer"; import { Message, MessageEntity, MessageReplyHeader, Photo, PhotoSize, ReplyMarkup, Update, WebPage } from "../../layer";
import { REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config"; import { REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import { FocusDirection } from "../../helpers/fastSmoothScroll"; import { FocusDirection } from "../../helpers/fastSmoothScroll";
import useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation } from "../../hooks/useHeavyAnimationCheck"; import useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation } from "../../hooks/useHeavyAnimationCheck";
@ -841,11 +841,8 @@ export default class ChatBubbles {
const message = this.chat.getMessage(bubbleMid) as Message.message; const message = this.chat.getMessage(bubbleMid) as Message.message;
const peerId = this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id); const peerId = this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id);
const threadId = message.reply_to.reply_to_top_id; const threadId = message.reply_to.reply_to_top_id;
const lastMsgId = message.fwd_from.saved_from_msg_id;
this.appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => { this.chat.appImManager.openThread(peerId, lastMsgId, threadId);
this.appMessagesManager.generateThreadServiceStartMessage(this.appMessagesManager.getMessageByPeer(peerId, threadId));
this.chat.appImManager.setInnerPeer(peerId, message.fwd_from.saved_from_msg_id, 'discussion', threadId);
});
} else { } else {
const message = this.appMessagesManager.filterMessages(this.chat.getMessage(bubbleMid), message => !!(message as Message.message).replies)[0] as Message.message; const message = this.appMessagesManager.filterMessages(this.chat.getMessage(bubbleMid), message => !!(message as Message.message).replies)[0] as Message.message;
const replies = message.replies; const replies = message.replies;
@ -2424,7 +2421,7 @@ export default class ChatBubbles {
case 'messageMediaWebPage': { case 'messageMediaWebPage': {
processingWebPage = true; processingWebPage = true;
let webpage = messageMedia.webpage; let webpage: WebPage.webPage | WebPage.webPageEmpty = messageMedia.webpage;
////////this.log('messageMediaWebPage', webpage); ////////this.log('messageMediaWebPage', webpage);
if(webpage._ === 'webPageEmpty') { if(webpage._ === 'webPageEmpty') {
break; break;
@ -2439,7 +2436,8 @@ export default class ChatBubbles {
quote.classList.add('quote'); quote.classList.add('quote');
let previewResizer: HTMLDivElement, preview: HTMLDivElement; let previewResizer: HTMLDivElement, preview: HTMLDivElement;
if(webpage.photo || webpage.document) { const photo: Photo.photo = webpage.photo as any;
if(photo || webpage.document) {
previewResizer = document.createElement('div'); previewResizer = document.createElement('div');
previewResizer.classList.add('preview-resizer'); previewResizer.classList.add('preview-resizer');
preview = document.createElement('div'); preview = document.createElement('div');
@ -2487,15 +2485,14 @@ export default class ChatBubbles {
quoteTextDiv.append(previewResizer); quoteTextDiv.append(previewResizer);
} }
// let t: HTMLElement; let t: HTMLElement;
if(webpage.site_name) { if(webpage.site_name) {
let nameEl = document.createElement('a'); const html = RichTextProcessor.wrapRichText(webpage.url);
nameEl.classList.add('webpage-name'); const a: HTMLAnchorElement = htmlToDocumentFragment(html).firstElementChild as any;
nameEl.setAttribute('target', '_blank'); a.classList.add('webpage-name');
nameEl.href = webpage.url || '#'; setInnerHTML(a, RichTextProcessor.wrapEmojiText(webpage.site_name));
setInnerHTML(nameEl, RichTextProcessor.wrapEmojiText(webpage.site_name)); quoteTextDiv.append(a);
quoteTextDiv.append(nameEl); t = a;
// t = nameEl;
} }
if(webpage.rTitle) { if(webpage.rTitle) {
@ -2503,7 +2500,7 @@ export default class ChatBubbles {
titleDiv.classList.add('title'); titleDiv.classList.add('title');
setInnerHTML(titleDiv, webpage.rTitle); setInnerHTML(titleDiv, webpage.rTitle);
quoteTextDiv.append(titleDiv); quoteTextDiv.append(titleDiv);
// t = titleDiv; t = titleDiv;
} }
if(webpage.rDescription) { if(webpage.rDescription) {
@ -2511,7 +2508,7 @@ export default class ChatBubbles {
textDiv.classList.add('text'); textDiv.classList.add('text');
setInnerHTML(textDiv, webpage.rDescription); setInnerHTML(textDiv, webpage.rDescription);
quoteTextDiv.append(textDiv); quoteTextDiv.append(textDiv);
// t = textDiv; t = textDiv;
} }
/* if(t) { /* if(t) {
@ -2522,15 +2519,15 @@ export default class ChatBubbles {
quote.append(quoteTextDiv); quote.append(quoteTextDiv);
if(webpage.photo && !doc) { if(photo && !doc) {
bubble.classList.add('photo'); bubble.classList.add('photo');
const size = webpage.photo.sizes[webpage.photo.sizes.length - 1]; const size: PhotoSize.photoSize = photo.sizes[photo.sizes.length - 1] as any;
let isSquare = false; let isSquare = false;
if(size.w === size.h && quoteTextDiv.childElementCount) { if(size.w === size.h && t) {
bubble.classList.add('is-square-photo'); bubble.classList.add('is-square-photo');
isSquare = true; isSquare = true;
this.appPhotosManager.setAttachmentSize(webpage.photo, preview, 32, 32, false); this.appPhotosManager.setAttachmentSize(photo, preview, 32, 32, false);
/* if(t) { /* if(t) {
t.append(timeSpan); t.append(timeSpan);
@ -2540,7 +2537,7 @@ export default class ChatBubbles {
} }
wrapPhoto({ wrapPhoto({
photo: webpage.photo, photo,
message, message,
container: preview, container: preview,
boxWidth: isSquare ? 0 : mediaSizes.active.webpage.width, boxWidth: isSquare ? 0 : mediaSizes.active.webpage.width,

90
src/lib/appManagers/appImManager.ts

@ -272,11 +272,11 @@ export class AppImManager {
this.addAnchorListener<{hashtag: string}>({ this.addAnchorListener<{hashtag: string}>({
name: 'searchByHashtag', name: 'searchByHashtag',
callback: (params) => { callback: (params) => {
if(!params) { const {hashtag} = params;
if(!hashtag) {
return; return;
} }
const {hashtag} = params;
this.chat.initSearch('#' + hashtag + ' '); this.chat.initSearch('#' + hashtag + ' ');
} }
}); });
@ -316,34 +316,75 @@ export class AppImManager {
}, },
parsePathname: true parsePathname: true
}); });
this.addAnchorListener<{
// pathnameParams: ['c', string, string],
// uriParams: {thread?: number}
// } | {
// pathnameParams: [string, string?],
// uriParams: {comment?: number}
pathnameParams: ['c', string, string] | [string, string?],
uriParams: {thread?: number} | {comment?: number}
}>({
name: 'im',
callback: (params) => {
console.log(params);
const {pathnameParams, uriParams} = params;
if(pathnameParams[0] === 'c') {
const peerId = -+pathnameParams[1];
const postId = appMessagesIdsManager.generateMessageId(+pathnameParams[2]);
const threadId = 'thread' in uriParams ? appMessagesIdsManager.generateMessageId(+uriParams.thread) : undefined;
if(threadId) this.openThread(peerId, postId, threadId);
else this.setInnerPeer(peerId, postId);
} else {
const username = pathnameParams[0];
const postId = pathnameParams[1] ? appMessagesIdsManager.generateMessageId(+pathnameParams[1]) : undefined;
const commentId = 'comment' in uriParams ? appMessagesIdsManager.generateMessageId(uriParams.comment) : undefined;
this.openUsername(username, postId, undefined, commentId);
}
},
parsePathname: true,
parseUriParams: true
});
} }
private addAnchorListener<Params extends any>(options: { private addAnchorListener<Params extends any>(options: {
name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'joinchat', name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'joinchat' | 'im',
callback: (params: Params, element: HTMLAnchorElement) => boolean | void, callback: (params: Params, element: HTMLAnchorElement) => boolean | void,
noParams?: boolean, noParams?: boolean,
parsePathname?: boolean parsePathname?: boolean,
parseUriParams?: boolean,
}) { }) {
(window as any)[options.name] = (element: HTMLAnchorElement/* , e: Event */) => { (window as any)[options.name] = (element: HTMLAnchorElement/* , e: Event */) => {
cancelEvent(null); cancelEvent(null);
const href = element.href; const href = element.href;
let params: any; let pathnameParams: any[];
let uriParams: any;
if(!options.noParams) { if(!options.noParams) {
params = options.parsePathname ? new URL(element.href).pathname.split('/').slice(1) : this.parseUriParams(href); if(options.parsePathname) pathnameParams = new URL(element.href).pathname.split('/').slice(1);
if(options.parseUriParams) uriParams = this.parseUriParams(href);
} }
const res = options.callback(params, element); let out: any;
if(pathnameParams && uriParams) {
out = {pathnameParams, uriParams};
} else {
out = pathnameParams || uriParams;
}
const res = options.callback(out, element);
return res === undefined ? res : false; return res === undefined ? res : false;
}; };
} }
private parseUriParams(uri: string, splitted = uri.split('?')) { private parseUriParams(uri: string, splitted = uri.split('?')) {
if(!splitted[1]) {
return;
}
const params: any = {}; const params: any = {};
if(!splitted[1]) return params;
splitted[1].split('&').forEach(item => { splitted[1].split('&').forEach(item => {
params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]); params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);
}); });
@ -382,12 +423,14 @@ export class AppImManager {
//location.hash = ''; //location.hash = '';
}; };
public openUsername(username: string, msgId?: number) { public openUsername(username: string, msgId?: number, threadId?: number, commentId?: number) {
return appUsersManager.resolveUsername(username).then(peer => { return appUsersManager.resolveUsername(username).then(peer => {
const isUser = peer._ === 'user'; const isUser = peer._ === 'user';
const peerId = isUser ? peer.id : -peer.id; const peerId = isUser ? peer.id : -peer.id;
return this.setInnerPeer(peerId, msgId); if(threadId) return this.openThread(peerId, msgId, threadId);
else if(commentId) return this.openComment(peerId, msgId, commentId);
else return this.setInnerPeer(peerId, msgId);
}, (err) => { }, (err) => {
if(err.type === 'USERNAME_NOT_OCCUPIED') { if(err.type === 'USERNAME_NOT_OCCUPIED') {
toast(i18n('NoUsernameFound')); toast(i18n('NoUsernameFound'));
@ -395,6 +438,27 @@ export class AppImManager {
}); });
} }
/**
* Opens thread when peerId of discussion group is known
*/
public openThread(peerId: number, lastMsgId: number, threadId: number) {
return appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => {
const message = appMessagesManager.getMessageByPeer(peerId, threadId);
appMessagesManager.generateThreadServiceStartMessage(message);
return this.setInnerPeer(peerId, lastMsgId, 'discussion', threadId);
});
}
/**
* Opens comment directly from original channel
*/
public openComment(peerId: number, msgId: number, commentId: number) {
return appMessagesManager.getDiscussionMessage(peerId, msgId).then(message => {
return this.openThread(message.peerId, commentId, message.mid);
});
}
public setCurrentBackground(broadcastEvent = false) { public setCurrentBackground(broadcastEvent = false) {
const theme = rootScope.getTheme(); const theme = rootScope.getTheme();

51
src/lib/richtextprocessor.ts

@ -597,7 +597,7 @@ namespace RichTextProcessor {
//inner = encodeEntities(replaceUrlEncodings(entityText)); //inner = encodeEntities(replaceUrlEncodings(entityText));
} }
const currentContext = url[0] === '#'; const currentContext = !!onclick;
if(!onclick && masked && !currentContext) { if(!onclick && masked && !currentContext) {
onclick = 'showMaskedAlert'; onclick = 'showMaskedAlert';
} }
@ -644,12 +644,15 @@ namespace RichTextProcessor {
} }
case 'messageEntityMention': { case 'messageEntityMention': {
const contextUrl = !options.noLinks && siteMentions[contextSite]; // const contextUrl = !options.noLinks && siteMentions[contextSite];
if(contextUrl) { if(!options.noLinks) {
const entityText = text.substr(entity.offset, entity.length); const entityText = text.substr(entity.offset, entity.length);
const username = entityText.substr(1); const username = entityText.substr(1);
insertPart(entity, `<a class="mention" href="${contextUrl.replace('{1}', encodeURIComponent(username))}"${contextExternal ? ' target="_blank" rel="noopener noreferrer"' : ''}>`, '</a>'); const {url, onclick} = wrapUrl('t.me/' + username);
// insertPart(entity, `<a class="mention" href="${contextUrl.replace('{1}', encodeURIComponent(username))}"${contextExternal ? ' target="_blank" rel="noopener noreferrer"' : ''}>`, '</a>');
insertPart(entity, `<a class="mention" href="${url}" ${onclick ? `onclick=${onclick}(this)` : ''}>`, '</a>');
} }
break; break;
@ -811,43 +814,11 @@ namespace RichTextProcessor {
case 'addstickers': case 'addstickers':
onclick = path[0]; onclick = path[0];
break; break;
/* case 'joinchat':
onclick = 'joinchat';
url = 'tg://join?invite=' + path[1];
break;
case 'addstickers':
onclick = 'addstickers';
url = 'tg://addstickers?set=' + path[1];
break; */
default: default:
if(path[1] && path[1].match(/^\d+$/)) { // https://t.me/.+/[0-9]+ (channel w/ username) if((path[1] && path[1].match(/^\d+(?:\?(?:comment|thread)=\d+)?$/)) || path.length === 1) {
if(path[0] === 'c' && path[2]) { // https://t.me/c/111111111/111 (channel w/o username) onclick = 'im';
url = '#/im?p=' + path[1] + '&post=' + path[2]; break;
} else { // https://t.me/durov/151 (channel w/ username)
url = siteMentions['Telegram'].replace('{1}', path[0] + '&post=' + path[1]);
}
} else if(path.length === 1) {
const domainQuery = path[0].split('?');
const domain = domainQuery[0];
const query = domainQuery[1];
if(domain === 'iv') {
const match = (query || '').match(/url=([^&=]+)/);
if(match) {
url = match[1];
try {
url = decodeURIComponent(url);
} catch (e) {}
return wrapUrl(url, unsafe);
}
}
url = siteMentions['Telegram'].replace('{1}', domain + (query ? '&' + query : ''));
//url = 'tg://resolve?domain=' + domain + (query ? '&' + query : '');
} }
break; break;

1
src/scss/partials/_chatBubble.scss

@ -860,6 +860,7 @@ $bubble-margin: .25rem;
.webpage-name { .webpage-name {
font-size: var(--messages-secondary-text-size); font-size: var(--messages-secondary-text-size);
font-weight: 500 !important; font-weight: 500 !important;
text-decoration: none;
@include hover() { @include hover() {
text-decoration: underline; text-decoration: underline;

Loading…
Cancel
Save