Browse Source

Copy messages/posts link

master
Eduard Kuzmenko 4 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";
import PopupPinMessage from "../popups/unpinMessage"; import PopupPinMessage from "../popups/unpinMessage";
import { copyTextToClipboard } from "../../helpers/clipboard"; import { copyTextToClipboard } from "../../helpers/clipboard";
import PopupSendNow from "../popups/sendNow"; import PopupSendNow from "../popups/sendNow";
import { toast } from "../toast";
export default class ChatContextMenu { export default class ChatContextMenu {
private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[]; 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), verify: () => this.chat.selection.selectedMids.has(this.mid) && !![...this.chat.selection.selectedMids].find(mid => !!this.chat.getMessage(mid).message),
notDirect: () => true, notDirect: () => true,
withSelection: true withSelection: true
}, {
icon: 'link',
text: 'Copy Link',
onClick: this.onCopyLinkClick,
verify: () => this.appPeersManager.isChannel(this.peerId)
}, { }, {
icon: 'pin', icon: 'pin',
text: 'Pin', text: 'Pin',
@ -300,6 +306,21 @@ export default class ChatContextMenu {
copyTextToClipboard(str); 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 = () => { private onPinClick = () => {
new PopupPinMessage(this.peerId, this.mid); new PopupPinMessage(this.peerId, this.mid);
}; };

44
src/lib/appManagers/appChatsManager.ts

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

10
src/lib/appManagers/appImManager.ts

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

4
src/lib/appManagers/appPeersManager.ts

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

16
src/lib/richtextprocessor.ts

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

Loading…
Cancel
Save