Copy messages/posts link
This commit is contained in:
parent
4e35e481fd
commit
fb434d751b
@ -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 {
|
||||
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 {
|
||||
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);
|
||||
};
|
||||
|
@ -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 {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
||||
if(chat._ == 'channel' &&
|
||||
if(chat._ === 'channel' &&
|
||||
chat.participants_count === undefined &&
|
||||
oldChat !== undefined &&
|
||||
oldChat.participants_count) {
|
||||
@ -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 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(chat._ == 'channel') {
|
||||
if(chat._ === 'channel') {
|
||||
if((!chat.pFlags.megagroup && !myFlags?.post_messages)) {
|
||||
return false;
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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 {
|
||||
} */
|
||||
|
||||
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 {
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
} 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 {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
} 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 {
|
||||
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;
|
||||
|
@ -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 {
|
||||
} else if(peerId < 0) {
|
||||
return 'group';
|
||||
} else {
|
||||
return peerId == rootScope.myId ? 'saved' : 'chat';
|
||||
return peerId === rootScope.myId ? 'saved' : 'chat';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
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…
Reference in New Issue
Block a user