Browse Source

Fix links tab in shared media

Minor improvements
master
morethanwords 4 years ago
parent
commit
9948bab8b0
  1. 113
      src/components/sidebarRight/sharedMedia.ts
  2. 2
      src/components/wrappers.ts
  3. 2
      src/lib/appManagers/apiUpdatesManager.ts
  4. 4
      src/lib/appManagers/appDialogsManager.ts
  5. 88
      src/lib/appManagers/appMessagesManager.ts
  6. 14
      src/lib/appManagers/appStateManager.ts
  7. 7
      src/lib/appManagers/appWebPagesManager.ts
  8. 4
      src/lib/mtproto/tl_utils.ts
  9. 55
      src/lib/richtextprocessor.ts
  10. 12
      src/lib/utils.ts

113
src/components/sidebarRight/sharedMedia.ts

@ -8,6 +8,7 @@ import appUsersManager from "../../lib/appManagers/appUsersManager"; @@ -8,6 +8,7 @@ import appUsersManager from "../../lib/appManagers/appUsersManager";
import { logger, LogLevels } from "../../lib/logger";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import $rootScope from "../../lib/rootScope";
import { getAbbreviation, limitSymbols } from "../../lib/utils";
import AvatarElement from "../avatar";
import { horizontalMenu } from "../horizontalMenu";
import LazyLoadQueue from "../lazyLoadQueue";
@ -108,7 +109,7 @@ export default class AppSharedMediaTab implements SliderTab { @@ -108,7 +109,7 @@ export default class AppSharedMediaTab implements SliderTab {
private loadMutex: Promise<any> = Promise.resolve();
private log = logger('SM', LogLevels.error);
private log = logger('SM'/* , LogLevels.error */);
public init() {
this.container = document.getElementById('shared-media-container');
@ -226,11 +227,16 @@ export default class AppSharedMediaTab implements SliderTab { @@ -226,11 +227,16 @@ export default class AppSharedMediaTab implements SliderTab {
container.style.paddingRight = '0';
};
public filterMessagesByType(ids: number[], type: string) {
public filterMessagesByType(ids: number[], type: SharedMediaType) {
let messages: any[] = [];
for(let mid of ids) {
let message = appMessagesManager.getMessage(mid);
if(message.media) messages.push(message);
if(type != 'inputMessagesFilterUrl') {
for(let mid of ids) {
let message = appMessagesManager.getMessage(mid);
if(message.media) messages.push(message);
}
} else {
messages = ids.slice().map(mid => appMessagesManager.getMessage(mid));
}
let filtered: any[] = [];
@ -257,7 +263,7 @@ export default class AppSharedMediaTab implements SliderTab { @@ -257,7 +263,7 @@ export default class AppSharedMediaTab implements SliderTab {
case 'inputMessagesFilterDocument': {
for(let message of messages) {
if(!message.media.document || message.media.document.type == 'voice' || message.media.document.type == 'audio') {
if(!message.media.document || ['voice', 'audio', 'gif'].includes(message.media.document.type)) {
continue;
}
@ -274,12 +280,11 @@ export default class AppSharedMediaTab implements SliderTab { @@ -274,12 +280,11 @@ export default class AppSharedMediaTab implements SliderTab {
}
case 'inputMessagesFilterUrl': {
this.log('inputMessagesFilterUrl', messages);
for(let message of messages) {
if(!message.media.webpage || message.media.webpage._ == 'webPageEmpty') {
continue;
}
filtered.push(message);
//if((message.media.webpage && message.media.webpage._ != 'webPageEmpty')) {
filtered.push(message);
//}
}
break;
@ -443,15 +448,63 @@ export default class AppSharedMediaTab implements SliderTab { @@ -443,15 +448,63 @@ export default class AppSharedMediaTab implements SliderTab {
sharedMediaDiv = this.sharedMedia.contentLinks;
for(let message of messages) {
let webpage = message.media.webpage;
let webpage: any;
if(message.media?.webpage && message.media.webpage._ != 'webPageEmpty') {
webpage = message.media.webpage;
} else {
const entity = message.totalEntities.find((e: any) => e._ == 'messageEntityUrl' || e._ == 'messageEntityTextUrl');
let url: string, display_url: string, sliced: string;
if(!entity) {
this.log.error('NO ENTITY:', message);
const match = RichTextProcessor.matchUrl(message.message);
if(!match) {
this.log.error('NO ENTITY AND NO MATCH:', message);
}
url = match[0];
} else {
sliced = message.message.slice(entity.offset, entity.offset + entity.length);
}
if(entity?._ == 'messageEntityTextUrl') {
url = entity.url;
//display_url = sliced;
} else {
url = url || sliced;
}
display_url = url;
const same = message.message == url;
if(!url.match(/^(ftp|http|https):\/\//)) {
display_url = 'https://' + url;
url = url.includes('@') ? url : 'https://' + url;
}
display_url = new URL(display_url).hostname;
webpage = {
url,
display_url
};
if(!same) {
webpage.description = message.message;
webpage.rDescription = RichTextProcessor.wrapRichText(limitSymbols(message.message, 150, 180));
}
}
let div = document.createElement('div');
div.dataset.mid = '' + message.mid;
let previewDiv = document.createElement('div');
previewDiv.classList.add('preview');
//this.log('wrapping webpage', webpage);
previewDiv.innerText = (webpage.title || webpage.description || webpage.url || webpage.display_url).slice(0, 1);
previewDiv.innerHTML = getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true);
previewDiv.classList.add('empty');
if(webpage.photo) {
let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, appPhotosManager.choosePhotoSize(webpage.photo, 60, 60))
@ -476,7 +529,11 @@ export default class AppSharedMediaTab implements SliderTab { @@ -476,7 +529,11 @@ export default class AppSharedMediaTab implements SliderTab {
if(!title) {
//title = new URL(webpage.url).hostname;
title = webpage.display_url.split('/', 1)[0];
title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);
}
if(webpage.description?.includes('Еще в начале')) {
this.log.error('FROM THE START', webpage);
}
div.append(previewDiv);
@ -566,6 +623,8 @@ export default class AppSharedMediaTab implements SliderTab { @@ -566,6 +623,8 @@ export default class AppSharedMediaTab implements SliderTab {
const history = historyStorage[type] ?? (historyStorage[type] = []);
const logStr = `loadSidebarMedia [${type}]: `;
// render from cache
if(history.length && this.usedFromHistory[type] < history.length) {
let messages: any[] = [];
@ -573,7 +632,7 @@ export default class AppSharedMediaTab implements SliderTab { @@ -573,7 +632,7 @@ export default class AppSharedMediaTab implements SliderTab {
do {
let ids = history.slice(used, used + loadCount);
this.log('loadSidebarMedia: will render from cache', used, history, ids, loadCount);
this.log(logStr + 'will render from cache', used, history, ids, loadCount);
used += ids.length;
messages.push(...this.filterMessagesByType(ids, type));
@ -597,19 +656,14 @@ export default class AppSharedMediaTab implements SliderTab { @@ -597,19 +656,14 @@ export default class AppSharedMediaTab implements SliderTab {
// заливать новую картинку сюда только после полной отправки!
let maxID = history[history.length - 1] || 0;
let ids = !maxID && appMessagesManager.historiesStorage[peerID]
? appMessagesManager.historiesStorage[peerID].history.slice() : [];
maxID = !maxID && ids.length ? ids[ids.length - 1] : maxID;
this.log('loadSidebarMedia: search house of glass pre', type, ids, maxID);
this.log(logStr + 'search house of glass pre', type, maxID);
//let loadCount = history.length ? 50 : 15;
return this.loadSidebarMediaPromises[type] = appMessagesManager.getSearch(peerID, '', {_: type}, maxID, loadCount)
.then(value => {
ids = ids.concat(value.history);
history.push(...ids);
history.push(...value.history);
this.log('loadSidebarMedia: search house of glass', type, value, ids);
this.log(logStr + 'search house of glass', type, value);
if($rootScope.selectedPeerID != peerID) {
this.log.warn('peer changed');
@ -617,22 +671,25 @@ export default class AppSharedMediaTab implements SliderTab { @@ -617,22 +671,25 @@ export default class AppSharedMediaTab implements SliderTab {
}
if(value.history.length < loadCount) {
this.log(logStr + 'loaded all media', value, loadCount);
this.loadedAllMedia[type] = true;
}
this.usedFromHistory[type] = history.length;
//if(ids.length) {
return this.performSearchResult(this.filterMessagesByType(ids, type), type);
//if(value.history.length) {
return this.performSearchResult(this.filterMessagesByType(value.history, type), type);
//}
}, (err) => {
}).catch(err => {
this.log.error('load error:', err);
}).then(() => {
}).finally(() => {
this.loadSidebarMediaPromises[type] = null;
});
});
return Promise.all(promises);
return Promise.all(promises).catch(err => {
this.log.error('Load error all promises:', err);
});
}
public cleanup() {

2
src/components/wrappers.ts

@ -308,7 +308,7 @@ export function wrapDocument(doc: MyDocument, withTime = false, uploading = fals @@ -308,7 +308,7 @@ export function wrapDocument(doc: MyDocument, withTime = false, uploading = fals
const icoDiv = document.createElement('div');
icoDiv.classList.add('document-ico');
if(doc.type == 'photo') {
if(doc.thumbs?.length || uploading) {
docDiv.classList.add('photo');
if(uploading) {

2
src/lib/appManagers/apiUpdatesManager.ts

@ -168,7 +168,7 @@ export class ApiUpdatesManager { @@ -168,7 +168,7 @@ export class ApiUpdatesManager {
date: updateMessage.date,
message: updateMessage.message,
fwd_from: updateMessage.fwd_from,
reply_to_msg_id: updateMessage.reply_to_msg_id,
reply_to: updateMessage.reply_to,
entities: updateMessage.entities
},
pts: updateMessage.pts,

4
src/lib/appManagers/appDialogsManager.ts

@ -969,7 +969,7 @@ export class AppDialogsManager { @@ -969,7 +969,7 @@ export class AppDialogsManager {
}
let messageWrapped = RichTextProcessor.wrapRichText(messageText, {
noLinebreakers: true,
noLinebreaks: true,
entities: entities,
noTextFormat: true
});
@ -995,7 +995,7 @@ export class AppDialogsManager { @@ -995,7 +995,7 @@ export class AppDialogsManager {
}
//senderBold.innerText = str + ': ';
senderBold.innerHTML = RichTextProcessor.wrapRichText(str, {noLinebreakers: true}) + ': ';
senderBold.innerHTML = RichTextProcessor.wrapRichText(str, {noLinebreaks: true}) + ': ';
//console.log(sender, senderBold.innerText);
dom.lastMessageSpan.prepend(senderBold);
} //////// else console.log('no sender', lastMessage, peerID);

88
src/lib/appManagers/appMessagesManager.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { copy, tsNow, safeReplaceObject, listMergeSorted, deepEqual, langPack, getObjectKeysAndSort } from "../utils";
import { copy, tsNow, safeReplaceObject, listMergeSorted, deepEqual, langPack, getObjectKeysAndSort, limitSymbols } from "../utils";
import appMessagesIDsManager from "./appMessagesIDsManager";
import appChatsManager from "./appChatsManager";
import appUsersManager from "./appUsersManager";
@ -822,7 +822,7 @@ export class AppMessagesManager { @@ -822,7 +822,7 @@ export class AppMessagesManager {
date: tsNow(true) + serverTimeManager.serverTimeOffset,
message: text,
random_id: randomIDS,
reply_to_msg_id: replyToMsgID,
reply_to: {reply_to_msg_id: replyToMsgID},
via_bot_id: options.viaBotID,
reply_markup: options.reply_markup,
entities: entities,
@ -1184,7 +1184,7 @@ export class AppMessagesManager { @@ -1184,7 +1184,7 @@ export class AppMessagesManager {
document: file
} : media,
random_id: randomIDS,
reply_to_msg_id: replyToMsgID,
reply_to: {reply_to_msg_id: replyToMsgID},
views: asChannel && 1,
pending: true
};
@ -1459,7 +1459,7 @@ export class AppMessagesManager { @@ -1459,7 +1459,7 @@ export class AppMessagesManager {
media: media,
random_id: randomIDS,
randomID: randomID,
reply_to_msg_id: replyToMsgID,
reply_to: {reply_to_msg_id: replyToMsgID},
views: asChannel && 1,
pending: true,
error: false
@ -1752,7 +1752,7 @@ export class AppMessagesManager { @@ -1752,7 +1752,7 @@ export class AppMessagesManager {
message: '',
media: media,
random_id: randomIDS,
reply_to_msg_id: replyToMsgID,
reply_to: {reply_to_msg_id: replyToMsgID},
via_bot_id: options.viaBotID,
reply_markup: options.reply_markup,
views: asChannel && 1,
@ -2132,7 +2132,8 @@ export class AppMessagesManager { @@ -2132,7 +2132,8 @@ export class AppMessagesManager {
return this.messagesStorage[messageID] || {
_: 'messageEmpty',
id: messageID,
deleted: true
deleted: true,
pFlags: {}
};
}
@ -2308,8 +2309,8 @@ export class AppMessagesManager { @@ -2308,8 +2309,8 @@ export class AppMessagesManager {
}
// this.log(dT(), 'msg unread', mid, apiMessage.pFlags.out, dialog && dialog[apiMessage.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id'])
if(apiMessage.reply_to_msg_id) {
apiMessage.reply_to_mid = appMessagesIDsManager.getFullMessageID(apiMessage.reply_to_msg_id, channelID);
if(apiMessage.reply_to && apiMessage.reply_to.reply_to_msg_id) {
apiMessage.reply_to_mid = appMessagesIDsManager.getFullMessageID(apiMessage.reply_to.reply_to_msg_id, channelID);
}
apiMessage.date -= serverTimeManager.serverTimeOffset;
@ -2575,14 +2576,12 @@ export class AppMessagesManager { @@ -2575,14 +2576,12 @@ export class AppMessagesManager {
let messageWrapped = '';
if(text) {
// * 80 for chatlist in landscape orientation
if(text.length > 80) {
text = text.substr(0, 75) + '...';
}
text = limitSymbols(text, 75, 80);
let entities = RichTextProcessor.parseEntities(text.replace(/\n/g, ' '), {noLinebreakers: true});
messageWrapped = RichTextProcessor.wrapRichText(text, {
noLinebreakers: true,
noLinebreaks: true,
entities: entities,
noTextFormat: true
});
@ -2827,6 +2826,10 @@ export class AppMessagesManager { @@ -2827,6 +2826,10 @@ export class AppMessagesManager {
this.saveMessages([message]);
}
if(!message?.pFlags) {
this.log.error('saveConversation no message:', dialog, message);
}
if(!channelID && peerID < 0) {
const chat = appChatsManager.getChat(-peerID);
if(chat && chat.migrated_to && chat.pFlags.deactivated) {
@ -2886,7 +2889,7 @@ export class AppMessagesManager { @@ -2886,7 +2889,7 @@ export class AppMessagesManager {
public mergeReplyKeyboard(historyStorage: HistoryStorage, message: any) {
// this.log('merge', message.mid, message.reply_markup, historyStorage.reply_markup)
if(!message.reply_markup &&
!message.pFlags.out &&
!message.pFlags?.out &&
!message.action) {
return false;
}
@ -2966,10 +2969,10 @@ export class AppMessagesManager { @@ -2966,10 +2969,10 @@ export class AppMessagesManager {
history: number[]
}> {
//peerID = peerID ? parseInt(peerID) : 0;
var foundMsgs: number[] = [];
var useSearchCache = !query;
var newSearchFilter = {peer: peerID, filter: inputFilter};
var sameSearchCache = useSearchCache && deepEqual(this.lastSearchFilter, newSearchFilter);
const foundMsgs: number[] = [];
const useSearchCache = !query;
const newSearchFilter = {peer: peerID, filter: inputFilter};
const sameSearchCache = useSearchCache && deepEqual(this.lastSearchFilter, newSearchFilter);
if(useSearchCache && !sameSearchCache) {
// this.log.warn(dT(), 'new search filter', lastSearchFilter, newSearchFilter)
@ -2987,7 +2990,6 @@ export class AppMessagesManager { @@ -2987,7 +2990,6 @@ export class AppMessagesManager {
[messageMediaType: string]: boolean
} = {},
neededDocTypes: string[] = [];
var message;
switch(inputFilter._) {
case 'inputMessagesFilterPhotos':
@ -3033,9 +3035,9 @@ export class AppMessagesManager { @@ -3033,9 +3035,9 @@ export class AppMessagesManager {
neededContents['url'] = true;
break;
case 'inputMessagesFilterMyMentions':
/* case 'inputMessagesFilterMyMentions':
neededContents['mentioned'] = true;
break;
break; */
default:
return Promise.resolve({
@ -3045,8 +3047,12 @@ export class AppMessagesManager { @@ -3045,8 +3047,12 @@ export class AppMessagesManager {
});
}
for(let i = 0; i < historyStorage.history.length; i++) {
message = this.messagesStorage[historyStorage.history[i]];
for(let i = 0, length = historyStorage.history.length; i < length; i++) {
const message = this.messagesStorage[historyStorage.history[i]];
//|| (neededContents['mentioned'] && message.totalEntities.find((e: any) => e._ == 'messageEntityMention'));
let found = false;
if(message.media && neededContents[message.media._]) {
if(neededDocTypes.length &&
message.media._ == 'messageMediaDocument' &&
@ -3054,6 +3060,12 @@ export class AppMessagesManager { @@ -3054,6 +3060,12 @@ export class AppMessagesManager {
continue;
}
found = true;
} else if(neededContents['url'] && message.message && RichTextProcessor.matchUrl(message.message)) {
found = true;
}
if(found) {
foundMsgs.push(message.mid);
if(foundMsgs.length >= limit) {
break;
@ -3078,15 +3090,20 @@ export class AppMessagesManager { @@ -3078,15 +3090,20 @@ export class AppMessagesManager {
}
if(foundMsgs.length) {
if(useSearchCache) {
this.lastSearchResults = listMergeSorted(this.lastSearchResults, foundMsgs)
if(foundMsgs.length < limit) {
maxID = foundMsgs[foundMsgs.length - 1];
limit = limit - foundMsgs.length;
} else {
if(useSearchCache) {
this.lastSearchResults = listMergeSorted(this.lastSearchResults, foundMsgs)
}
return Promise.resolve({
count: 0,
next_rate: 0,
history: foundMsgs
});
}
return Promise.resolve({
count: 0,
next_rate: 0,
history: foundMsgs
});
}
let apiPromise: Promise<any>;
@ -3141,15 +3158,14 @@ export class AppMessagesManager { @@ -3141,15 +3158,14 @@ export class AppMessagesManager {
appChatsManager.saveApiChats(searchResult.chats);
this.saveMessages(searchResult.messages);
///////////this.log('messages.search result:', searchResult);
this.log('messages.search result:', inputFilter, searchResult);
var foundCount: number = searchResult.count || searchResult.messages.length;
const foundCount: number = searchResult.count || (foundMsgs.length + searchResult.messages.length);
foundMsgs = [];
searchResult.messages.forEach((message: any) => {
var peerID = this.getMessagePeer(message);
const peerID = this.getMessagePeer(message);
if(peerID < 0) {
var chat = appChatsManager.getChat(-peerID);
const chat = appChatsManager.getChat(-peerID);
if(chat.migrated_to) {
this.migrateChecks(peerID, -chat.migrated_to.channel_id);
}
@ -3413,7 +3429,7 @@ export class AppMessagesManager { @@ -3413,7 +3429,7 @@ export class AppMessagesManager {
}
public handleUpdate(update: any) {
this.log('AMM: handleUpdate:', update._);
this.log.debug('AMM: handleUpdate:', update._);
switch(update._) {
case 'updateMessageID': {
var randomID = update.random_id;

14
src/lib/appManagers/appStateManager.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import type { Dialog, DialogsStorage, FiltersStorage } from './appMessagesManager';
import type { AppStickersManager } from './appStickersManager';
import type { AppPeersManager } from './appPeersManager';
import { App, MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import { App, MOUNT_CLASS_TO, UserAuth } from '../mtproto/mtproto_config';
import EventListenerBase from '../../helpers/eventListenerBase';
import $rootScope from '../rootScope';
import AppStorage from '../storage';
@ -45,14 +45,14 @@ export class AppStateManager extends EventListenerBase<{ @@ -45,14 +45,14 @@ export class AppStateManager extends EventListenerBase<{
public loadSavedState() {
if(this.loaded) return this.loaded;
console.time('load state');
//console.time('load state');
return this.loaded = new Promise((resolve) => {
AppStorage.get<[State, {id: number}]>('state', 'user_auth').then(([state, auth]) => {
AppStorage.get<[State, UserAuth]>('state', 'user_auth').then(([state, auth]) => {
const time = Date.now();
if(state) {
if(state?.version != STATE_VERSION) {
if(state.version != STATE_VERSION) {
state = {};
} else if((state?.stateCreatedTime ?? 0) + REFRESH_EVERY < time) {
} else if((state.stateCreatedTime || 0) + REFRESH_EVERY < time) {
this.log('will refresh state', state.stateCreatedTime, time);
REFRESH_KEYS.forEach(key => {
delete state[key];
@ -62,7 +62,7 @@ export class AppStateManager extends EventListenerBase<{ @@ -62,7 +62,7 @@ export class AppStateManager extends EventListenerBase<{
}
// will not throw error because state can be `FALSE`
const {peers, updates} = state;
const {peers} = state;
this.state = state || {};
this.state.peers = peers || {};
@ -81,7 +81,7 @@ export class AppStateManager extends EventListenerBase<{ @@ -81,7 +81,7 @@ export class AppStateManager extends EventListenerBase<{
$rootScope.$broadcast('user_auth', {id: auth.id});
}
console.timeEnd('load state');
//console.timeEnd('load state');
resolve(state);
}).catch(resolve).finally(() => {
setInterval(() => this.saveState(), 10000);

7
src/lib/appManagers/appWebPagesManager.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { safeReplaceObject } from "../utils";
import { limitSymbols, safeReplaceObject } from "../utils";
import appPhotosManager from "./appPhotosManager";
import appDocsManager from "./appDocsManager";
import { RichTextProcessor } from "../richtextprocessor";
@ -59,10 +59,7 @@ class AppWebPagesManager { @@ -59,10 +59,7 @@ class AppWebPagesManager {
}
// delete apiWebPage.description
var shortDescriptionText = (apiWebPage.description || '');
if(shortDescriptionText.length > 180) {
shortDescriptionText = shortDescriptionText.substr(0, 150).replace(/(\n|\s)+$/, '') + '...';
}
var shortDescriptionText = limitSymbols(apiWebPage.description || '', 150, 180);
apiWebPage.rDescription = RichTextProcessor.wrapRichText(shortDescriptionText, {
contextSite: siteName || 'external',
contextHashtag: contextHashtag

4
src/lib/mtproto/tl_utils.ts

@ -204,7 +204,9 @@ class TLSerialization { @@ -204,7 +204,9 @@ class TLSerialization {
var len = bytes.length;
if((bits % 32) || (len * 8) != bits) {
throw new Error('Invalid bits: ' + bits + ', ' + bytes.length);
const error = new Error('Invalid bits: ' + bits + ', ' + bytes.length);
console.error(error, bytes, field);
throw error;
}
this.debug && console.log('>>>', bytesToHex(bytes), (field || '') + ':int' + bits);

55
src/lib/richtextprocessor.ts

@ -271,7 +271,7 @@ function parseMarkdown(text: string, entities: any[], noTrim?: any) { @@ -271,7 +271,7 @@ function parseMarkdown(text: string, entities: any[], noTrim?: any) {
}
return newText
}
function mergeEntities (currentEntities: any[], newEntities: any[], fromApi: any) {
function mergeEntities(currentEntities: any[], newEntities: any[], fromApi: any) {
var totalEntities = newEntities.slice();
var i;
var len = currentEntities.length;
@ -337,14 +337,26 @@ function mergeEntities (currentEntities: any[], newEntities: any[], fromApi: any @@ -337,14 +337,26 @@ function mergeEntities (currentEntities: any[], newEntities: any[], fromApi: any
// console.log('merge', currentEntities, newEntities, totalEntities)
return totalEntities;
}
function wrapRichNestedText (text: string, nested: any, options: any) {
if (nested === undefined) {
return encodeEntities(text)
function wrapRichNestedText(text: string, nested: any, options: any) {
if(nested === undefined) {
return encodeEntities(text);
}
options.hasNested = true
return wrapRichText(text, {entities: nested, nested: true})
options.hasNested = true;
return wrapRichText(text, {entities: nested, nested: true});
}
function wrapRichText (text: string, options: any = {}) {
function wrapRichText(text: string, options: Partial<{
entities: any,
contextSite: string,
highlightUsername: string,
noLinks: boolean,
noLinebreaks: boolean,
noCommands: boolean,
fromBot: boolean,
noTextFormat: boolean,
nested?: boolean,
contextHashtag?: string
}> = {}) {
if(!text || !text.length) {
return ''
}
@ -713,7 +725,7 @@ function wrapEmojiText(text: string) { @@ -713,7 +725,7 @@ function wrapEmojiText(text: string) {
let entities = parseEntities(text).filter(e => e._ == 'messageEntityEmoji');
return wrapRichText(text, {entities});
}
function wrapUrl(url: string, unsafe: any): string {
function wrapUrl(url: string, unsafe: number | boolean): string {
if(!url.match(/^https?:\/\//i)) {
url = 'http://' + url;
}
@ -765,18 +777,23 @@ function wrapUrl(url: string, unsafe: any): string { @@ -765,18 +777,23 @@ function wrapUrl(url: string, unsafe: any): string {
return url;
}
function matchUrl(text: string) {
return text.match(urlRegExp);
}
let RichTextProcessor = {
wrapRichText: wrapRichText,
wrapPlainText: wrapPlainText,
wrapDraftText: wrapDraftText,
wrapUrl: wrapUrl,
wrapEmojiText: wrapEmojiText,
parseEntities: parseEntities,
parseMarkdown: parseMarkdown,
parseEmojis: parseEmojis,
mergeEntities: mergeEntities,
getEmojiSpritesheetCoords: getEmojiSpritesheetCoords,
emojiSupported: emojiSupported
wrapRichText,
wrapPlainText,
wrapDraftText,
wrapUrl,
wrapEmojiText,
parseEntities,
parseMarkdown,
parseEmojis,
mergeEntities,
getEmojiSpritesheetCoords,
emojiSupported,
matchUrl
};
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.RichTextProcessor = RichTextProcessor);

12
src/lib/utils.ts

@ -235,7 +235,7 @@ export function tsNow(seconds?: boolean) { @@ -235,7 +235,7 @@ export function tsNow(seconds?: boolean) {
}
const el = document.createElement('span');
export function getAbbreviation(str: string) {
export function getAbbreviation(str: string, onlyFirst = false) {
const wrapped = RichTextProcessor.wrapEmojiText(str);
el.innerHTML = wrapped;
@ -246,6 +246,8 @@ export function getAbbreviation(str: string) { @@ -246,6 +246,8 @@ export function getAbbreviation(str: string) {
if('length' in firstNode) first = (firstNode as any).textContent.charAt(0).toUpperCase();
else first = (firstNode as HTMLElement).outerHTML;
if(onlyFirst) return first;
if(str.indexOf(' ') !== -1) {
const lastNode = childNodes[childNodes.length - 1];
if(lastNode == firstNode) last = lastNode.textContent.split(' ').pop().charAt(0).toUpperCase();
@ -292,6 +294,14 @@ export function safeReplaceArrayInObject<K>(key: K, wasObject: any, newObject: a @@ -292,6 +294,14 @@ export function safeReplaceArrayInObject<K>(key: K, wasObject: any, newObject: a
}
}
export function limitSymbols(str: string, length: number, limitFrom = length + 10) {
if(str.length > limitFrom) {
str = str.slice(0, length).replace(/(\n|\s)+$/, '') + '...';
}
return str;
}
export function numberWithCommas(x: number) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");

Loading…
Cancel
Save