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

90
src/lib/appManagers/appImManager.ts

@ -272,11 +272,11 @@ export class AppImManager { @@ -272,11 +272,11 @@ export class AppImManager {
this.addAnchorListener<{hashtag: string}>({
name: 'searchByHashtag',
callback: (params) => {
if(!params) {
const {hashtag} = params;
if(!hashtag) {
return;
}
const {hashtag} = params;
this.chat.initSearch('#' + hashtag + ' ');
}
});
@ -316,34 +316,75 @@ export class AppImManager { @@ -316,34 +316,75 @@ export class AppImManager {
},
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: {
name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'joinchat',
name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'joinchat' | 'im',
callback: (params: Params, element: HTMLAnchorElement) => boolean | void,
noParams?: boolean,
parsePathname?: boolean
parsePathname?: boolean,
parseUriParams?: boolean,
}) {
(window as any)[options.name] = (element: HTMLAnchorElement/* , e: Event */) => {
cancelEvent(null);
const href = element.href;
let params: any;
let pathnameParams: any[];
let uriParams: any;
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;
};
}
private parseUriParams(uri: string, splitted = uri.split('?')) {
if(!splitted[1]) {
return;
}
const params: any = {};
if(!splitted[1]) return params;
splitted[1].split('&').forEach(item => {
params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);
});
@ -382,12 +423,14 @@ export class AppImManager { @@ -382,12 +423,14 @@ export class AppImManager {
//location.hash = '';
};
public openUsername(username: string, msgId?: number) {
public openUsername(username: string, msgId?: number, threadId?: number, commentId?: number) {
return appUsersManager.resolveUsername(username).then(peer => {
const isUser = peer._ === 'user';
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) => {
if(err.type === 'USERNAME_NOT_OCCUPIED') {
toast(i18n('NoUsernameFound'));
@ -395,6 +438,27 @@ export class AppImManager { @@ -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) {
const theme = rootScope.getTheme();

51
src/lib/richtextprocessor.ts

@ -597,7 +597,7 @@ namespace RichTextProcessor { @@ -597,7 +597,7 @@ namespace RichTextProcessor {
//inner = encodeEntities(replaceUrlEncodings(entityText));
}
const currentContext = url[0] === '#';
const currentContext = !!onclick;
if(!onclick && masked && !currentContext) {
onclick = 'showMaskedAlert';
}
@ -644,12 +644,15 @@ namespace RichTextProcessor { @@ -644,12 +644,15 @@ namespace RichTextProcessor {
}
case 'messageEntityMention': {
const contextUrl = !options.noLinks && siteMentions[contextSite];
if(contextUrl) {
// const contextUrl = !options.noLinks && siteMentions[contextSite];
if(!options.noLinks) {
const entityText = text.substr(entity.offset, entity.length);
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;
@ -811,43 +814,11 @@ namespace RichTextProcessor { @@ -811,43 +814,11 @@ namespace RichTextProcessor {
case 'addstickers':
onclick = path[0];
break;
/* case 'joinchat':
onclick = 'joinchat';
url = 'tg://join?invite=' + path[1];
break;
case 'addstickers':
onclick = 'addstickers';
url = 'tg://addstickers?set=' + path[1];
break; */
default:
if(path[1] && path[1].match(/^\d+$/)) { // https://t.me/.+/[0-9]+ (channel w/ username)
if(path[0] === 'c' && path[2]) { // https://t.me/c/111111111/111 (channel w/o username)
url = '#/im?p=' + path[1] + '&post=' + path[2];
} 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 : '');
if((path[1] && path[1].match(/^\d+(?:\?(?:comment|thread)=\d+)?$/)) || path.length === 1) {
onclick = 'im';
break;
}
break;

1
src/scss/partials/_chatBubble.scss

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

Loading…
Cancel
Save