Browse Source

Copy messages/posts link

master
Eduard Kuzmenko 3 years ago
parent
commit
fb434d751b
  1. 21
      src/components/chat/contextMenu.ts
  2. 44
      src/lib/appManagers/appChatsManager.ts
  3. 10
      src/lib/appManagers/appImManager.ts
  4. 4
      src/lib/appManagers/appPeersManager.ts
  5. 16
      src/lib/richtextprocessor.ts

21
src/components/chat/contextMenu.ts

@ -12,6 +12,7 @@ import PopupForward from "../popups/forward"; @@ -12,6 +12,7 @@ import PopupForward from "../popups/forward";
import PopupPinMessage from "../popups/unpinMessage";
import { copyTextToClipboard } from "../../helpers/clipboard";
import PopupSendNow from "../popups/sendNow";
import { toast } from "../toast";
export default class ChatContextMenu {
private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[];
@ -195,6 +196,11 @@ export default class ChatContextMenu { @@ -195,6 +196,11 @@ export default class ChatContextMenu {
verify: () => this.chat.selection.selectedMids.has(this.mid) && !![...this.chat.selection.selectedMids].find(mid => !!this.chat.getMessage(mid).message),
notDirect: () => true,
withSelection: true
}, {
icon: 'link',
text: 'Copy Link',
onClick: this.onCopyLinkClick,
verify: () => this.appPeersManager.isChannel(this.peerId)
}, {
icon: 'pin',
text: 'Pin',
@ -300,6 +306,21 @@ export default class ChatContextMenu { @@ -300,6 +306,21 @@ export default class ChatContextMenu {
copyTextToClipboard(str);
};
private onCopyLinkClick = () => {
const username = this.appPeersManager.getPeerUsername(this.peerId);
const msgId = this.appMessagesManager.getServerMessageId(this.mid);
let url = 'https://t.me/';
if(username) {
url += username + '/' + msgId;
toast('Link copied to clipboard.');
} else {
url += 'c/' + Math.abs(this.peerId) + '/' + msgId;
toast('This link will only work for chat members.');
}
copyTextToClipboard(url);
};
private onPinClick = () => {
new PopupPinMessage(this.peerId, this.mid);
};

44
src/lib/appManagers/appChatsManager.ts

@ -90,13 +90,13 @@ export class AppChatsManager { @@ -90,13 +90,13 @@ export class AppChatsManager {
case 'updateUserTyping':
case 'updateChatUserTyping': {
if(rootScope.myId == update.user_id) {
if(rootScope.myId === update.user_id) {
return;
}
const peerId = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id;
const peerId = update._ === 'updateUserTyping' ? update.user_id : -update.chat_id;
const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []);
let typing = typings.find(t => t.userId == update.user_id);
let typing = typings.find(t => t.userId === update.user_id);
if(!typing) {
typing = {
userId: update.user_id
@ -110,7 +110,7 @@ export class AppChatsManager { @@ -110,7 +110,7 @@ export class AppChatsManager {
typing.action = update.action;
if(!appUsersManager.hasUser(update.user_id)) {
if(update._ == 'updateChatUserTyping') {
if(update._ === 'updateChatUserTyping') {
if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) {
appProfileManager.getChatFull(update.chat_id);
}
@ -125,7 +125,7 @@ export class AppChatsManager { @@ -125,7 +125,7 @@ export class AppChatsManager {
typing.timeout = window.setTimeout(() => {
delete typing.timeout;
typings.findAndSplice(t => t.userId == update.user_id);
typings.findAndSplice(t => t.userId === update.user_id);
rootScope.broadcast('peer_typings', {peerId, typings});
@ -174,7 +174,7 @@ export class AppChatsManager { @@ -174,7 +174,7 @@ export class AppChatsManager {
}
}
if(chat._ == 'channel' &&
if(chat._ === 'channel' &&
chat.participants_count === undefined &&
oldChat !== undefined &&
oldChat.participants_count) {
@ -217,10 +217,10 @@ export class AppChatsManager { @@ -217,10 +217,10 @@ export class AppChatsManager {
public hasRights(id: number, action: ChatRights, flag?: keyof ChatBannedRights['pFlags']) {
const chat = this.getChat(id);
if(chat._ == 'chatEmpty') return false;
if(chat._ === 'chatEmpty') return false;
if(chat._ == 'chatForbidden' ||
chat._ == 'channelForbidden' ||
if(chat._ === 'chatForbidden' ||
chat._ === 'channelForbidden' ||
chat.pFlags.kicked ||
(chat.pFlags.left && !chat.pFlags.megagroup)) {
return false;
@ -241,7 +241,7 @@ export class AppChatsManager { @@ -241,7 +241,7 @@ export class AppChatsManager {
return false;
}
if(chat._ == 'channel') {
if(chat._ === 'channel') {
if((!chat.pFlags.megagroup && !myFlags?.post_messages)) {
return false;
}
@ -252,7 +252,7 @@ export class AppChatsManager { @@ -252,7 +252,7 @@ export class AppChatsManager {
// good
case 'deleteRevoke': {
if(chat._ == 'channel') {
if(chat._ === 'channel') {
return !!myFlags?.delete_messages;
} else if(!chat.pFlags.admin) {
return false;
@ -263,7 +263,7 @@ export class AppChatsManager { @@ -263,7 +263,7 @@ export class AppChatsManager {
// good
case 'pin': {
if(chat._ == 'channel') {
if(chat._ === 'channel') {
return chat.admin_rights ? !!myFlags.pin_messages || !!myFlags.post_messages : myFlags && !myFlags.pin_messages;
} else {
if(myFlags?.pin_messages && !chat.pFlags.admin) {
@ -277,9 +277,9 @@ export class AppChatsManager { @@ -277,9 +277,9 @@ export class AppChatsManager {
case 'edit_title':
case 'edit_photo':
case 'invite': {
if(chat._ == 'channel') {
if(chat._ === 'channel') {
if(chat.pFlags.megagroup) {
if(!(action == 'invite' && chat.pFlags.democracy)) {
if(!(action === 'invite' && chat.pFlags.democracy)) {
return false;
}
} else {
@ -314,7 +314,7 @@ export class AppChatsManager { @@ -314,7 +314,7 @@ export class AppChatsManager {
public isChannel(id: number) {
if(id < 0) id = -id;
const chat = this.chats[id];
if(chat && (chat._ == 'channel' || chat._ == 'channelForbidden')/* || this.channelAccess[id] */) {
if(chat && (chat._ === 'channel' || chat._ === 'channelForbidden')/* || this.channelAccess[id] */) {
return true;
}
return false;
@ -326,7 +326,7 @@ export class AppChatsManager { @@ -326,7 +326,7 @@ export class AppChatsManager {
} */
const chat = this.chats[id];
if(chat && chat._ == 'channel' && chat.pFlags.megagroup) {
if(chat && chat._ === 'channel' && chat.pFlags.megagroup) {
return true;
}
return false;
@ -410,7 +410,7 @@ export class AppChatsManager { @@ -410,7 +410,7 @@ export class AppChatsManager {
}
if(chatFull.participants &&
chatFull.participants._ == 'chatParticipants') {
chatFull.participants._ === 'chatParticipants') {
chatFull.participants.participants = this.wrapParticipants(id, chatFull.participants.participants);
}
@ -430,8 +430,8 @@ export class AppChatsManager { @@ -430,8 +430,8 @@ export class AppChatsManager {
if(this.isChannel(id)) {
const isAdmin = chat.pFlags.creator;
participants.forEach((participant) => {
participant.canLeave = myId == participant.user_id;
participant.canKick = isAdmin && participant._ == 'channelParticipant';
participant.canLeave = myId === participant.user_id;
participant.canKick = isAdmin && participant._ === 'channelParticipant';
// just for order by last seen
participant.user = appUsersManager.getUser(participant.user_id);
@ -439,10 +439,10 @@ export class AppChatsManager { @@ -439,10 +439,10 @@ export class AppChatsManager {
} else {
const isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin;
participants.forEach((participant) => {
participant.canLeave = myId == participant.user_id;
participant.canLeave = myId === participant.user_id;
participant.canKick = !participant.canLeave && (
chat.pFlags.creator ||
participant._ == 'chatParticipant' && (isAdmin || myId == participant.inviter_id)
participant._ === 'chatParticipant' && (isAdmin || myId === participant.inviter_id)
);
// just for order by last seen
@ -541,7 +541,7 @@ export class AppChatsManager { @@ -541,7 +541,7 @@ export class AppChatsManager {
return participants.reduce((acc: number, participant) => {
const user = appUsersManager.getUser(participant.user_id);
if(user && user.status && user.status._ == 'userStatusOnline') {
if(user && user.status && user.status._ === 'userStatusOnline') {
return acc + 1;
}

10
src/lib/appManagers/appImManager.ts

@ -136,7 +136,7 @@ export class AppImManager { @@ -136,7 +136,7 @@ export class AppImManager {
switch(p[0]) {
case '@': {
appUsersManager.resolveUsername(p).then(peer => {
const isUser = peer._ == 'user';
const isUser = peer._ === 'user';
const peerId = isUser ? peer.id : -peer.id;
this.setInnerPeer(peerId, postId);
@ -365,7 +365,7 @@ export class AppImManager { @@ -365,7 +365,7 @@ export class AppImManager {
const drops: ChatDragAndDrop[] = [];
let mounted = false;
const toggle = async(e: DragEvent, mount: boolean) => {
if(mount == mounted) return;
if(mount === mounted) return;
const _types = e.dataTransfer.types;
// @ts-ignore
@ -489,7 +489,7 @@ export class AppImManager { @@ -489,7 +489,7 @@ export class AppImManager {
getFilesFromEvent(e).then((files: File[]) => {
if(files.length) {
if(attachType == 'media' && files.find(file => !['image', 'video'].includes(file.type.split('/')[0]))) {
if(attachType === 'media' && files.find(file => !['image', 'video'].includes(file.type.split('/')[0]))) {
attachType = 'document';
}
@ -704,7 +704,7 @@ export class AppImManager { @@ -704,7 +704,7 @@ export class AppImManager {
} else { // user
const user = appUsersManager.getUser(peerId);
if(rootScope.myId == peerId) {
if(rootScope.myId === peerId) {
return '';
} else if(user) {
subtitle = appUsersManager.getUserStatusString(user.id);
@ -713,7 +713,7 @@ export class AppImManager { @@ -713,7 +713,7 @@ export class AppImManager {
const typings = appChatsManager.typingsInPeer[peerId];
if(typings && typings.length) {
return '<span class="online">typing...</span>';
} else if(subtitle == 'online') {
} else if(subtitle === 'online') {
return `<span class="online">${subtitle}</span>`;
} else {
return subtitle;

4
src/lib/appManagers/appPeersManager.ts

@ -118,7 +118,7 @@ export class AppPeersManager { @@ -118,7 +118,7 @@ export class AppPeersManager {
else if(isObject(peerString)) return peerString.user_id ? peerString.user_id : -(peerString.channel_id || peerString.chat_id);
else if(!peerString) return 0;
const isUser = peerString.charAt(0) == 'u';
const isUser = peerString.charAt(0) === 'u';
const peerParams = peerString.substr(1).split('_');
return isUser ? peerParams[0] : -peerParams[0] || 0;
@ -238,7 +238,7 @@ export class AppPeersManager { @@ -238,7 +238,7 @@ export class AppPeersManager {
} else if(peerId < 0) {
return 'group';
} else {
return peerId == rootScope.myId ? 'saved' : 'chat';
return peerId === rootScope.myId ? 'saved' : 'chat';
}
}

16
src/lib/richtextprocessor.ts

@ -95,7 +95,7 @@ namespace RichTextProcessor { @@ -95,7 +95,7 @@ namespace RichTextProcessor {
export function getEmojiSpritesheetCoords(emojiCode: string) {
let unified = encodeEmoji(emojiCode)/* .replace(/(-fe0f|fe0f)/g, '') */;
if(unified == '1f441-200d-1f5e8') {
if(unified === '1f441-200d-1f5e8') {
unified = '1f441-fe0f-200d-1f5e8-fe0f';
}
@ -236,7 +236,7 @@ namespace RichTextProcessor { @@ -236,7 +236,7 @@ namespace RichTextProcessor {
if(text.match(/^`*$/)) {
newText.push(match[0]);
} else if(match[3]) { // pre
if(match[5] == '\n') {
if(match[5] === '\n') {
match[5] = '';
rawOffset -= 1;
}
@ -251,7 +251,7 @@ namespace RichTextProcessor { @@ -251,7 +251,7 @@ namespace RichTextProcessor {
rawOffset -= match[2].length + match[4].length;
} else if(match[7]) { // code|italic|bold
const isSOH = match[6] == '\x01';
const isSOH = match[6] === '\x01';
if(!isSOH) {
newText.push(match[6] + text + match[9]);
} else {
@ -311,7 +311,7 @@ namespace RichTextProcessor { @@ -311,7 +311,7 @@ namespace RichTextProcessor {
export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[]) {
currentEntities = currentEntities.slice();
const filtered = newEntities.filter(e => !currentEntities.find(_e => e._ == _e._ && e.offset == _e.offset && e.length == _e.length));
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;
@ -496,7 +496,7 @@ namespace RichTextProcessor { @@ -496,7 +496,7 @@ namespace RichTextProcessor {
let inner: string;
let url: string;
if(entity._ == 'messageEntityTextUrl') {
if(entity._ === 'messageEntityTextUrl') {
url = (entity as MessageEntity.messageEntityTextUrl).url;
url = wrapUrl(url, true);
//inner = wrapRichNestedText(entityText, entity.nested, options);
@ -659,7 +659,7 @@ namespace RichTextProcessor { @@ -659,7 +659,7 @@ namespace RichTextProcessor {
export function wrapEmojiText(text: string) {
if(!text) return '';
let entities = parseEntities(text).filter(e => e._ == 'messageEntityEmoji');
let entities = parseEntities(text).filter(e => e._ === 'messageEntityEmoji');
return wrapRichText(text, {entities});
}
@ -670,7 +670,7 @@ namespace RichTextProcessor { @@ -670,7 +670,7 @@ namespace RichTextProcessor {
let tgMeMatch;
let telescoPeMatch;
/* if(unsafe == 2) {
/* if(unsafe === 2) {
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
} else */if((tgMeMatch = url.match(/^https?:\/\/t(?:elegram)?\.me\/(.+)/))) {
const fullPath = tgMeMatch[1];
@ -733,7 +733,7 @@ namespace RichTextProcessor { @@ -733,7 +733,7 @@ namespace RichTextProcessor {
const first = [...splitted[0]][0];
if(onlyFirst || splitted.length == 1) return wrapEmojiText(first);
if(onlyFirst || splitted.length === 1) return wrapEmojiText(first);
const last = [...splitted[splitted.length - 1]][0];

Loading…
Cancel
Save