Refactor wrapping rich text
This commit is contained in:
parent
68fbe05f36
commit
4336260293
@ -467,8 +467,8 @@ export class AppMediaPlaybackController {
|
|||||||
|
|
||||||
if(!isVoice) {
|
if(!isVoice) {
|
||||||
const attribute = doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;
|
const attribute = doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;
|
||||||
title = attribute && attribute.title || doc.file_name;
|
title = attribute?.title ?? doc.file_name;
|
||||||
artist = attribute && attribute.performer;
|
artist = attribute?.performer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!artwork.length) {
|
if(!artwork.length) {
|
||||||
@ -529,7 +529,7 @@ export class AppMediaPlaybackController {
|
|||||||
|
|
||||||
const message = this.getMessageByMedia(playingMedia);
|
const message = this.getMessageByMedia(playingMedia);
|
||||||
return {
|
return {
|
||||||
doc: appMessagesManager.getMediaFromMessage(message),
|
doc: appMessagesManager.getMediaFromMessage(message) as MyDocument,
|
||||||
message,
|
message,
|
||||||
media: playingMedia,
|
media: playingMedia,
|
||||||
playbackParams: this.getPlaybackParams()
|
playbackParams: this.getPlaybackParams()
|
||||||
|
@ -236,7 +236,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
|||||||
|
|
||||||
private setCaption(message: MyMessage) {
|
private setCaption(message: MyMessage) {
|
||||||
const caption = (message as Message.message).message;
|
const caption = (message as Message.message).message;
|
||||||
let html = '';
|
let html: Parameters<typeof setInnerHTML>[1] = '';
|
||||||
if(caption) {
|
if(caption) {
|
||||||
html = RichTextProcessor.wrapRichText(caption, {
|
html = RichTextProcessor.wrapRichText(caption, {
|
||||||
entities: (message as Message.message).totalEntities
|
entities: (message as Message.message).totalEntities
|
||||||
|
@ -1165,7 +1165,7 @@ export default class AppMediaViewerBase<
|
|||||||
}).element;
|
}).element;
|
||||||
} else {
|
} else {
|
||||||
title = document.createElement('span');
|
title = document.createElement('span');
|
||||||
title.innerHTML = RichTextProcessor.wrapEmojiText(fromId);
|
title.append(RichTextProcessor.wrapEmojiText(fromId));
|
||||||
title.classList.add('peer-title');
|
title.classList.add('peer-title');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ import escapeRegExp from "../helpers/string/escapeRegExp";
|
|||||||
import limitSymbols from "../helpers/string/limitSymbols";
|
import limitSymbols from "../helpers/string/limitSymbols";
|
||||||
import findAndSplice from "../helpers/array/findAndSplice";
|
import findAndSplice from "../helpers/array/findAndSplice";
|
||||||
import { ScrollStartCallbackDimensions } from "../helpers/fastSmoothScroll";
|
import { ScrollStartCallbackDimensions } from "../helpers/fastSmoothScroll";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
|
import appWebPagesManager from "../lib/appManagers/appWebPagesManager";
|
||||||
|
|
||||||
//const testScroll = false;
|
//const testScroll = false;
|
||||||
|
|
||||||
@ -699,7 +701,6 @@ export default class AppSearchSuper {
|
|||||||
|
|
||||||
if(!same) {
|
if(!same) {
|
||||||
webpage.description = message.message;
|
webpage.description = message.message;
|
||||||
webpage.rDescription = RichTextProcessor.wrapRichText(limitSymbols(message.message, 150, 180));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -724,13 +725,12 @@ export default class AppSearchSuper {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
previewDiv.classList.add('empty');
|
previewDiv.classList.add('empty');
|
||||||
previewDiv.innerHTML = RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true);
|
setInnerHTML(previewDiv, RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = webpage.rTitle || '';
|
let title = appWebPagesManager.wrapTitle(webpage);
|
||||||
let subtitle = webpage.rDescription || '';
|
|
||||||
|
|
||||||
const subtitleFragment = htmlToDocumentFragment(subtitle);
|
const subtitleFragment = appWebPagesManager.wrapDescription(webpage);
|
||||||
const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));
|
const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));
|
||||||
const a = aFragment.firstElementChild;
|
const a = aFragment.firstElementChild;
|
||||||
if(a instanceof HTMLAnchorElement) {
|
if(a instanceof HTMLAnchorElement) {
|
||||||
@ -751,9 +751,9 @@ export default class AppSearchSuper {
|
|||||||
subtitleFragment.append('\n', appMessagesManager.wrapSenderToPeer(message));
|
subtitleFragment.append('\n', appMessagesManager.wrapSenderToPeer(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!title) {
|
if(!title.textContent) {
|
||||||
//title = new URL(webpage.url).hostname;
|
//title = new URL(webpage.url).hostname;
|
||||||
title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);
|
title.append(RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const row = new Row({
|
const row = new Row({
|
||||||
|
@ -32,6 +32,8 @@ import { animateSingle } from "../helpers/animation";
|
|||||||
import clamp from "../helpers/number/clamp";
|
import clamp from "../helpers/number/clamp";
|
||||||
import toHHMMSS from "../helpers/string/toHHMMSS";
|
import toHHMMSS from "../helpers/string/toHHMMSS";
|
||||||
import MediaProgressLine from "./mediaProgressLine";
|
import MediaProgressLine from "./mediaProgressLine";
|
||||||
|
import RichTextProcessor from "../lib/richtextprocessor";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
rootScope.addEventListener('messages_media_read', ({mids, peerId}) => {
|
rootScope.addEventListener('messages_media_read', ({mids, peerId}) => {
|
||||||
mids.forEach(mid => {
|
mids.forEach(mid => {
|
||||||
@ -264,11 +266,13 @@ function wrapAudio(audioEl: AudioElement) {
|
|||||||
const isVoice = doc.type === 'voice' || doc.type === 'round';
|
const isVoice = doc.type === 'voice' || doc.type === 'round';
|
||||||
const descriptionEl = document.createElement('div');
|
const descriptionEl = document.createElement('div');
|
||||||
descriptionEl.classList.add('audio-description');
|
descriptionEl.classList.add('audio-description');
|
||||||
|
|
||||||
|
const audioAttribute = doc.attributes.find((attr) => attr._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;
|
||||||
|
|
||||||
if(!isVoice) {
|
if(!isVoice) {
|
||||||
const parts: (Node | string)[] = [];
|
const parts: (Node | string)[] = [];
|
||||||
if(doc.audioPerformer) {
|
if(audioAttribute?.performer) {
|
||||||
parts.push(htmlToSpan(doc.audioPerformer));
|
parts.push(RichTextProcessor.wrapEmojiText(audioAttribute.performer));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(withTime) {
|
if(withTime) {
|
||||||
@ -299,7 +303,7 @@ function wrapAudio(audioEl: AudioElement) {
|
|||||||
if(isVoice) {
|
if(isVoice) {
|
||||||
middleEllipsisEl.append(appMessagesManager.wrapSenderToPeer(message));
|
middleEllipsisEl.append(appMessagesManager.wrapSenderToPeer(message));
|
||||||
} else {
|
} else {
|
||||||
middleEllipsisEl.innerHTML = doc.audioTitle || doc.fileName;
|
setInnerHTML(middleEllipsisEl, RichTextProcessor.wrapEmojiText(audioAttribute?.title ?? doc.file_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
titleEl.append(middleEllipsisEl);
|
titleEl.append(middleEllipsisEl);
|
||||||
|
@ -11,7 +11,6 @@ import ControlsHover from "../../helpers/dom/controlsHover";
|
|||||||
import findUpClassName from "../../helpers/dom/findUpClassName";
|
import findUpClassName from "../../helpers/dom/findUpClassName";
|
||||||
import { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from "../../helpers/dom/fullScreen";
|
import { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from "../../helpers/dom/fullScreen";
|
||||||
import { onMediaLoad } from "../../helpers/files";
|
import { onMediaLoad } from "../../helpers/files";
|
||||||
import { MediaSize } from "../../helpers/mediaSizes";
|
|
||||||
import MovablePanel from "../../helpers/movablePanel";
|
import MovablePanel from "../../helpers/movablePanel";
|
||||||
import safeAssign from "../../helpers/object/safeAssign";
|
import safeAssign from "../../helpers/object/safeAssign";
|
||||||
import toggleClassName from "../../helpers/toggleClassName";
|
import toggleClassName from "../../helpers/toggleClassName";
|
||||||
@ -457,7 +456,7 @@ export default class PopupCall extends PopupElement {
|
|||||||
|
|
||||||
if(!this.emojisSubtitle.textContent && connectionState < CALL_STATE.EXCHANGING_KEYS) {
|
if(!this.emojisSubtitle.textContent && connectionState < CALL_STATE.EXCHANGING_KEYS) {
|
||||||
Promise.resolve(instance.getEmojisFingerprint()).then(emojis => {
|
Promise.resolve(instance.getEmojisFingerprint()).then(emojis => {
|
||||||
this.emojisSubtitle.innerHTML = RichTextProcessor.wrapEmojiText(emojis.join(''));
|
this.emojisSubtitle.append(RichTextProcessor.wrapEmojiText(emojis.join('')));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,10 +18,10 @@ import PeerTitle from "../peerTitle";
|
|||||||
import { i18n } from "../../lib/langPack";
|
import { i18n } from "../../lib/langPack";
|
||||||
import { formatFullSentTime } from "../../helpers/date";
|
import { formatFullSentTime } from "../../helpers/date";
|
||||||
import ButtonIcon from "../buttonIcon";
|
import ButtonIcon from "../buttonIcon";
|
||||||
import { MyDocument } from "../../lib/appManagers/appDocsManager";
|
import { DocumentAttribute } from "../../layer";
|
||||||
import { Message } from "../../layer";
|
|
||||||
import MediaProgressLine from "../mediaProgressLine";
|
import MediaProgressLine from "../mediaProgressLine";
|
||||||
import VolumeSelector from "../volumeSelector";
|
import VolumeSelector from "../volumeSelector";
|
||||||
|
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||||
|
|
||||||
export default class ChatAudio extends PinnedContainer {
|
export default class ChatAudio extends PinnedContainer {
|
||||||
private toggleEl: HTMLElement;
|
private toggleEl: HTMLElement;
|
||||||
@ -149,7 +149,7 @@ export default class ChatAudio extends PinnedContainer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private onMediaPlay = ({doc, message, media, playbackParams}: ReturnType<AppMediaPlaybackController['getPlayingDetails']>) => {
|
private onMediaPlay = ({doc, message, media, playbackParams}: ReturnType<AppMediaPlaybackController['getPlayingDetails']>) => {
|
||||||
let title: string | HTMLElement, subtitle: string | HTMLElement | DocumentFragment;
|
let title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment;
|
||||||
const isMusic = doc.type !== 'voice' && doc.type !== 'round';
|
const isMusic = doc.type !== 'voice' && doc.type !== 'round';
|
||||||
if(!isMusic) {
|
if(!isMusic) {
|
||||||
title = new PeerTitle({peerId: message.fromId, fromName: message.fwd_from?.from_name}).element;
|
title = new PeerTitle({peerId: message.fromId, fromName: message.fwd_from?.from_name}).element;
|
||||||
@ -157,8 +157,9 @@ export default class ChatAudio extends PinnedContainer {
|
|||||||
//subtitle = 'Voice message';
|
//subtitle = 'Voice message';
|
||||||
subtitle = formatFullSentTime(message.date);
|
subtitle = formatFullSentTime(message.date);
|
||||||
} else {
|
} else {
|
||||||
title = doc.audioTitle || doc.fileName;
|
const audioAttribute = doc.attributes.find((attr) => attr._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;
|
||||||
subtitle = doc.audioPerformer || i18n('AudioUnknownArtist');
|
title = RichTextProcessor.wrapEmojiText(audioAttribute?.title ?? doc.file_name);
|
||||||
|
subtitle = audioAttribute?.performer ? RichTextProcessor.wrapEmojiText(audioAttribute.performer) : i18n('AudioUnknownArtist');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fasterEl.classList.toggle('hide', isMusic);
|
this.fasterEl.classList.toggle('hide', isMusic);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
import RichTextProcessor from "../../lib/richtextprocessor";
|
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||||
import AvatarElement from "../avatar";
|
import AvatarElement from "../avatar";
|
||||||
import PeerTitle from "../peerTitle";
|
import PeerTitle from "../peerTitle";
|
||||||
@ -106,7 +107,7 @@ export default class AutocompletePeerHelper extends AutocompleteHelper {
|
|||||||
plainText: false
|
plainText: false
|
||||||
}).element);
|
}).element);
|
||||||
} else {
|
} else {
|
||||||
name.innerHTML = RichTextProcessor.wrapEmojiText(options.name);
|
setInnerHTML(name, RichTextProcessor.wrapEmojiText(options.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
div.append(avatar, name);
|
div.append(avatar, name);
|
||||||
@ -114,7 +115,7 @@ export default class AutocompletePeerHelper extends AutocompleteHelper {
|
|||||||
if(options.description) {
|
if(options.description) {
|
||||||
const description = document.createElement('div');
|
const description = document.createElement('div');
|
||||||
description.classList.add(BASE + '-description', options.className + '-description');
|
description.classList.add(BASE + '-description', options.className + '-description');
|
||||||
description.innerHTML = RichTextProcessor.wrapEmojiText(options.description);
|
setInnerHTML(description, RichTextProcessor.wrapEmojiText(options.description));
|
||||||
div.append(description);
|
div.append(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import type { AppChatsManager } from "../../lib/appManagers/appChatsManager";
|
|||||||
import type { AppProfileManager } from "../../lib/appManagers/appProfileManager";
|
import type { AppProfileManager } from "../../lib/appManagers/appProfileManager";
|
||||||
import type { AppDraftsManager } from "../../lib/appManagers/appDraftsManager";
|
import type { AppDraftsManager } from "../../lib/appManagers/appDraftsManager";
|
||||||
import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIdsManager";
|
import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIdsManager";
|
||||||
|
import type { AppWebPagesManager } from "../../lib/appManagers/appWebPagesManager";
|
||||||
import type Chat from "./chat";
|
import type Chat from "./chat";
|
||||||
import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager";
|
import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager";
|
||||||
import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
|
import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
|
||||||
@ -98,9 +99,6 @@ import findAndSplice from "../../helpers/array/findAndSplice";
|
|||||||
import getViewportSlice from "../../helpers/dom/getViewportSlice";
|
import getViewportSlice from "../../helpers/dom/getViewportSlice";
|
||||||
import SuperIntersectionObserver from "../../helpers/dom/superIntersectionObserver";
|
import SuperIntersectionObserver from "../../helpers/dom/superIntersectionObserver";
|
||||||
import generateFakeIcon from "../generateFakeIcon";
|
import generateFakeIcon from "../generateFakeIcon";
|
||||||
import selectElementContents from "../../helpers/dom/selectElementContents";
|
|
||||||
import cancelSelection from "../../helpers/dom/cancelSelection";
|
|
||||||
import SelectionSaver from "../../helpers/selectionSaver";
|
|
||||||
import copyFromElement from "../../helpers/dom/copyFromElement";
|
import copyFromElement from "../../helpers/dom/copyFromElement";
|
||||||
|
|
||||||
const USE_MEDIA_TAILS = false;
|
const USE_MEDIA_TAILS = false;
|
||||||
@ -230,7 +228,8 @@ export default class ChatBubbles {
|
|||||||
private appDraftsManager: AppDraftsManager,
|
private appDraftsManager: AppDraftsManager,
|
||||||
private appMessagesIdsManager: AppMessagesIdsManager,
|
private appMessagesIdsManager: AppMessagesIdsManager,
|
||||||
private appChatsManager: AppChatsManager,
|
private appChatsManager: AppChatsManager,
|
||||||
private appReactionsManager: AppReactionsManager
|
private appReactionsManager: AppReactionsManager,
|
||||||
|
private appWebPagesManager: AppWebPagesManager
|
||||||
) {
|
) {
|
||||||
//this.chat.log.error('Bubbles construction');
|
//this.chat.log.error('Bubbles construction');
|
||||||
|
|
||||||
@ -3133,7 +3132,7 @@ export default class ChatBubbles {
|
|||||||
let attachmentDiv = document.createElement('div');
|
let attachmentDiv = document.createElement('div');
|
||||||
attachmentDiv.classList.add('attachment');
|
attachmentDiv.classList.add('attachment');
|
||||||
|
|
||||||
attachmentDiv.innerHTML = richText;
|
setInnerHTML(attachmentDiv, richText);
|
||||||
|
|
||||||
bubble.classList.add('emoji-' + emojiEntities.length + 'x');
|
bubble.classList.add('emoji-' + emojiEntities.length + 'x');
|
||||||
|
|
||||||
@ -3259,7 +3258,11 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttonEl.classList.add('reply-markup-button', 'rp');
|
buttonEl.classList.add('reply-markup-button', 'rp');
|
||||||
buttonEl.insertAdjacentHTML('beforeend', text);
|
if(typeof(text) === 'string') {
|
||||||
|
buttonEl.insertAdjacentHTML('beforeend', text);
|
||||||
|
} else {
|
||||||
|
buttonEl.append(text);
|
||||||
|
}
|
||||||
|
|
||||||
ripple(buttonEl);
|
ripple(buttonEl);
|
||||||
|
|
||||||
@ -3477,20 +3480,22 @@ export default class ChatBubbles {
|
|||||||
t = a;
|
t = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(webpage.rTitle) {
|
const title = this.appWebPagesManager.wrapTitle(webpage);
|
||||||
|
if(title.textContent) {
|
||||||
let titleDiv = document.createElement('div');
|
let titleDiv = document.createElement('div');
|
||||||
titleDiv.classList.add('title');
|
titleDiv.classList.add('title');
|
||||||
const strong = document.createElement('strong');
|
const strong = document.createElement('strong');
|
||||||
setInnerHTML(strong, webpage.rTitle);
|
setInnerHTML(strong, title);
|
||||||
titleDiv.append(strong);
|
titleDiv.append(strong);
|
||||||
quoteTextDiv.append(titleDiv);
|
quoteTextDiv.append(titleDiv);
|
||||||
t = titleDiv;
|
t = titleDiv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(webpage.rDescription) {
|
const description = this.appWebPagesManager.wrapDescription(webpage);
|
||||||
|
if(description.textContent) {
|
||||||
let textDiv = document.createElement('div');
|
let textDiv = document.createElement('div');
|
||||||
textDiv.classList.add('text');
|
textDiv.classList.add('text');
|
||||||
setInnerHTML(textDiv, webpage.rDescription);
|
setInnerHTML(textDiv, description);
|
||||||
quoteTextDiv.append(textDiv);
|
quoteTextDiv.append(textDiv);
|
||||||
t = textDiv;
|
t = textDiv;
|
||||||
}
|
}
|
||||||
@ -3738,15 +3743,23 @@ export default class ChatBubbles {
|
|||||||
|
|
||||||
processingWebPage = true;
|
processingWebPage = true;
|
||||||
|
|
||||||
const texts = [];
|
const contactDetails = document.createElement('div');
|
||||||
if(contact.first_name) texts.push(RichTextProcessor.wrapEmojiText(contact.first_name));
|
contactDetails.className = 'contact-details';
|
||||||
if(contact.last_name) texts.push(RichTextProcessor.wrapEmojiText(contact.last_name));
|
const contactNameDiv = document.createElement('div');
|
||||||
|
contactNameDiv.className = 'contact-name';
|
||||||
|
contactNameDiv.append(
|
||||||
|
RichTextProcessor.wrapEmojiText([
|
||||||
|
contact.first_name,
|
||||||
|
contact.last_name
|
||||||
|
].filter(Boolean).join(' '))
|
||||||
|
);
|
||||||
|
|
||||||
contactDiv.innerHTML = `
|
const contactNumberDiv = document.createElement('div');
|
||||||
<div class="contact-details">
|
contactNumberDiv.className = 'contact-number';
|
||||||
<div class="contact-name">${texts.join(' ')}</div>
|
contactNumberDiv.textContent = contact.phone_number ? '+' + formatPhoneNumber(contact.phone_number).formatted : 'Unknown phone number';
|
||||||
<div class="contact-number">${contact.phone_number ? '+' + formatPhoneNumber(contact.phone_number).formatted : 'Unknown phone number'}</div>
|
|
||||||
</div>`;
|
contactDiv.append(contactDetails);
|
||||||
|
contactDetails.append(contactNameDiv, contactNumberDiv);
|
||||||
|
|
||||||
const avatarElem = new AvatarElement();
|
const avatarElem = new AvatarElement();
|
||||||
avatarElem.updateWithOptions({
|
avatarElem.updateWithOptions({
|
||||||
@ -3823,7 +3836,7 @@ export default class ChatBubbles {
|
|||||||
if(isHidden) {
|
if(isHidden) {
|
||||||
///////this.log('message to render hidden', message);
|
///////this.log('message to render hidden', message);
|
||||||
title = document.createElement('span');
|
title = document.createElement('span');
|
||||||
title.innerHTML = RichTextProcessor.wrapEmojiText(fwdFrom.from_name);
|
setInnerHTML(title, RichTextProcessor.wrapEmojiText(fwdFrom.from_name));
|
||||||
title.classList.add('peer-title');
|
title.classList.add('peer-title');
|
||||||
//title = fwdFrom.from_name;
|
//title = fwdFrom.from_name;
|
||||||
bubble.classList.add('hidden-profile');
|
bubble.classList.add('hidden-profile');
|
||||||
|
@ -323,7 +323,7 @@ export default class Chat extends EventListenerBase<{
|
|||||||
// this.initPeerId = peerId;
|
// this.initPeerId = peerId;
|
||||||
|
|
||||||
this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager, this.appProfileManager, this.appUsersManager, this.appGroupCallsManager);
|
this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager, this.appProfileManager, this.appUsersManager, this.appGroupCallsManager);
|
||||||
this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appPeersManager, this.appProfileManager, this.appDraftsManager, this.appMessagesIdsManager, this.appChatsManager, this.appReactionsManager);
|
this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appPeersManager, this.appProfileManager, this.appDraftsManager, this.appMessagesIdsManager, this.appChatsManager, this.appReactionsManager, this.appWebPagesManager);
|
||||||
this.input = new ChatInput(this, this.appMessagesManager, this.appMessagesIdsManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager, this.appUsersManager, this.appInlineBotsManager, this.appProfileManager);
|
this.input = new ChatInput(this, this.appMessagesManager, this.appMessagesIdsManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager, this.appUsersManager, this.appInlineBotsManager, this.appProfileManager);
|
||||||
this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);
|
this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);
|
||||||
this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appPeersManager, this.appPollsManager, this.appDocsManager, this.appMessagesIdsManager, this.appReactionsManager);
|
this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appPeersManager, this.appPollsManager, this.appDocsManager, this.appMessagesIdsManager, this.appReactionsManager);
|
||||||
|
@ -25,6 +25,7 @@ import GifsMasonry from "../gifsMasonry";
|
|||||||
import { SuperStickerRenderer } from "../emoticonsDropdown/tabs/stickers";
|
import { SuperStickerRenderer } from "../emoticonsDropdown/tabs/stickers";
|
||||||
import mediaSizes from "../../helpers/mediaSizes";
|
import mediaSizes from "../../helpers/mediaSizes";
|
||||||
import readBlobAsDataURL from "../../helpers/blob/readBlobAsDataURL";
|
import readBlobAsDataURL from "../../helpers/blob/readBlobAsDataURL";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
const ANIMATION_GROUP = 'INLINE-HELPER';
|
const ANIMATION_GROUP = 'INLINE-HELPER';
|
||||||
// const GRID_ITEMS = 5;
|
// const GRID_ITEMS = 5;
|
||||||
@ -131,18 +132,18 @@ export default class InlineHelper extends AutocompleteHelper {
|
|||||||
|
|
||||||
if(!isGallery) {
|
if(!isGallery) {
|
||||||
preview.classList.add('empty');
|
preview.classList.add('empty');
|
||||||
preview.innerHTML = RichTextProcessor.wrapEmojiText([...item.title.trim()][0]);
|
setInnerHTML(preview, RichTextProcessor.wrapEmojiText([...item.title.trim()][0]));
|
||||||
|
|
||||||
const title = document.createElement('div');
|
const title = document.createElement('div');
|
||||||
title.classList.add('inline-helper-result-title');
|
title.classList.add('inline-helper-result-title');
|
||||||
title.innerHTML = RichTextProcessor.wrapEmojiText(item.title);
|
setInnerHTML(title, RichTextProcessor.wrapEmojiText(item.title));
|
||||||
|
|
||||||
const description = document.createElement('div');
|
const description = document.createElement('div');
|
||||||
description.classList.add('inline-helper-result-description');
|
description.classList.add('inline-helper-result-description');
|
||||||
description.innerHTML = RichTextProcessor.wrapRichText(item.description, {
|
setInnerHTML(description, RichTextProcessor.wrapRichText(item.description, {
|
||||||
noCommands: true,
|
noCommands: true,
|
||||||
noLinks: true
|
noLinks: true
|
||||||
});
|
}));
|
||||||
|
|
||||||
container.append(title, description);
|
container.append(title, description);
|
||||||
|
|
||||||
@ -239,7 +240,7 @@ export default class InlineHelper extends AutocompleteHelper {
|
|||||||
parent.textContent = '';
|
parent.textContent = '';
|
||||||
if(botResults.switch_pm) {
|
if(botResults.switch_pm) {
|
||||||
const btnSwitchToPM = Button('btn-primary btn-secondary btn-primary-transparent primary');
|
const btnSwitchToPM = Button('btn-primary btn-secondary btn-primary-transparent primary');
|
||||||
btnSwitchToPM.insertAdjacentHTML('beforeend', RichTextProcessor.wrapEmojiText(botResults.switch_pm.text));
|
setInnerHTML(btnSwitchToPM, RichTextProcessor.wrapEmojiText(botResults.switch_pm.text));
|
||||||
attachClickEvent(btnSwitchToPM, (e) => {
|
attachClickEvent(btnSwitchToPM, (e) => {
|
||||||
this.appInlineBotsManager.switchToPM(peerId, peer.id, botResults.switch_pm.start_param);
|
this.appInlineBotsManager.switchToPM(peerId, peer.id, botResults.switch_pm.start_param);
|
||||||
});
|
});
|
||||||
|
@ -93,6 +93,7 @@ import ChatBotCommands from './botCommands';
|
|||||||
import copy from '../../helpers/object/copy';
|
import copy from '../../helpers/object/copy';
|
||||||
import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
|
import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
|
||||||
import toHHMMSS from '../../helpers/string/toHHMMSS';
|
import toHHMMSS from '../../helpers/string/toHHMMSS';
|
||||||
|
import documentFragmentToHTML from '../../helpers/dom/documentFragmentToHTML';
|
||||||
|
|
||||||
const RECORD_MIN_TIME = 500;
|
const RECORD_MIN_TIME = 500;
|
||||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||||
@ -2053,7 +2054,7 @@ export default class ChatInput {
|
|||||||
|
|
||||||
//const saveExecuted = this.prepareDocumentExecute();
|
//const saveExecuted = this.prepareDocumentExecute();
|
||||||
// can't exec .value here because it will instantly check for autocomplete
|
// can't exec .value here because it will instantly check for autocomplete
|
||||||
const value = RichTextProcessor.wrapDraftText(newValue, {entities});
|
const value = documentFragmentToHTML(RichTextProcessor.wrapDraftText(newValue, {entities}));
|
||||||
this.messageInputField.setValueSilently(value, true);
|
this.messageInputField.setValueSilently(value, true);
|
||||||
|
|
||||||
const caret = this.messageInput.querySelector('.composer-sel');
|
const caret = this.messageInput.querySelector('.composer-sel');
|
||||||
@ -2615,7 +2616,7 @@ export default class ChatInput {
|
|||||||
public initMessageEditing(mid: number) {
|
public initMessageEditing(mid: number) {
|
||||||
const message: Message.message = this.chat.getMessage(mid);
|
const message: Message.message = this.chat.getMessage(mid);
|
||||||
|
|
||||||
let input = RichTextProcessor.wrapDraftText(message.message, {entities: message.totalEntities});
|
let input = documentFragmentToHTML(RichTextProcessor.wrapDraftText(message.message, {entities: message.totalEntities}));
|
||||||
const f = () => {
|
const f = () => {
|
||||||
const replyFragment = this.appMessagesManager.wrapMessageForReply(message, undefined, [message.mid]);
|
const replyFragment = this.appMessagesManager.wrapMessageForReply(message, undefined, [message.mid]);
|
||||||
this.setTopInfo('edit', f, i18n('AccDescrEditing'), replyFragment, input, message);
|
this.setTopInfo('edit', f, i18n('AccDescrEditing'), replyFragment, input, message);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { formatTime, getFullDate } from "../../helpers/date";
|
import { formatTime, getFullDate } from "../../helpers/date";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
import formatNumber from "../../helpers/number/formatNumber";
|
import formatNumber from "../../helpers/number/formatNumber";
|
||||||
import { Message } from "../../layer";
|
import { Message } from "../../layer";
|
||||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||||
@ -62,7 +63,8 @@ export namespace MessageRender {
|
|||||||
args.push(postViewsSpan, channelViews);
|
args.push(postViewsSpan, channelViews);
|
||||||
if(postAuthor) {
|
if(postAuthor) {
|
||||||
const span = document.createElement('span');
|
const span = document.createElement('span');
|
||||||
span.innerHTML = RichTextProcessor.wrapEmojiText(postAuthor) + ',' + NBSP;
|
setInnerHTML(span, RichTextProcessor.wrapEmojiText(postAuthor));
|
||||||
|
span.insertAdjacentHTML('beforeend', ',' + NBSP)
|
||||||
args.push(span);
|
args.push(span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import cancelEvent from "../../helpers/dom/cancelEvent";
|
|||||||
import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck";
|
import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck";
|
||||||
import confirmationPopup from "../confirmationPopup";
|
import confirmationPopup from "../confirmationPopup";
|
||||||
import safeAssign from "../../helpers/object/safeAssign";
|
import safeAssign from "../../helpers/object/safeAssign";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
export default class ReplyKeyboard extends DropdownHover {
|
export default class ReplyKeyboard extends DropdownHover {
|
||||||
private static BASE_CLASS = 'reply-keyboard';
|
private static BASE_CLASS = 'reply-keyboard';
|
||||||
@ -141,7 +142,7 @@ export default class ReplyKeyboard extends DropdownHover {
|
|||||||
for(const button of row.buttons) {
|
for(const button of row.buttons) {
|
||||||
const btn = document.createElement('button');
|
const btn = document.createElement('button');
|
||||||
btn.classList.add(ReplyKeyboard.BASE_CLASS + '-button', 'btn');
|
btn.classList.add(ReplyKeyboard.BASE_CLASS + '-button', 'btn');
|
||||||
btn.innerHTML = RichTextProcessor.wrapEmojiText(button.text);
|
setInnerHTML(btn, RichTextProcessor.wrapEmojiText(button.text));
|
||||||
btn.dataset.text = button.text;
|
btn.dataset.text = button.text;
|
||||||
btn.dataset.type = button._;
|
btn.dataset.type = button._;
|
||||||
div.append(btn);
|
div.append(btn);
|
||||||
|
@ -32,7 +32,7 @@ export function appendEmoji(emoji: string, container: HTMLElement, prepend = fal
|
|||||||
const spanEmoji = document.createElement('span');
|
const spanEmoji = document.createElement('span');
|
||||||
spanEmoji.classList.add('super-emoji');
|
spanEmoji.classList.add('super-emoji');
|
||||||
|
|
||||||
let kek: string;
|
let kek: DocumentFragment;
|
||||||
if(unify && !IS_EMOJI_SUPPORTED) {
|
if(unify && !IS_EMOJI_SUPPORTED) {
|
||||||
kek = RichTextProcessor.wrapSingleEmoji(emoji);
|
kek = RichTextProcessor.wrapSingleEmoji(emoji);
|
||||||
} else {
|
} else {
|
||||||
@ -47,7 +47,7 @@ export function appendEmoji(emoji: string, container: HTMLElement, prepend = fal
|
|||||||
|
|
||||||
//console.log(kek);
|
//console.log(kek);
|
||||||
|
|
||||||
spanEmoji.innerHTML = kek;
|
spanEmoji.append(kek);
|
||||||
|
|
||||||
if(spanEmoji.children.length > 1) {
|
if(spanEmoji.children.length > 1) {
|
||||||
const first = spanEmoji.firstElementChild;
|
const first = spanEmoji.firstElementChild;
|
||||||
|
@ -151,7 +151,7 @@ export default class StickersTab implements EmoticonsTab {
|
|||||||
|
|
||||||
private superStickerRenderer: SuperStickerRenderer;
|
private superStickerRenderer: SuperStickerRenderer;
|
||||||
|
|
||||||
categoryPush(categoryDiv: HTMLElement, categoryTitle: string = '', promise: Promise<MyDocument[]>, prepend?: boolean) {
|
categoryPush(categoryDiv: HTMLElement, categoryTitle: DocumentFragment | string = '', promise: Promise<MyDocument[]>, prepend?: boolean) {
|
||||||
//if((docs.length % 5) !== 0) categoryDiv.classList.add('not-full');
|
//if((docs.length % 5) !== 0) categoryDiv.classList.add('not-full');
|
||||||
|
|
||||||
const itemsDiv = document.createElement('div');
|
const itemsDiv = document.createElement('div');
|
||||||
@ -161,7 +161,8 @@ export default class StickersTab implements EmoticonsTab {
|
|||||||
titleDiv.classList.add('category-title');
|
titleDiv.classList.add('category-title');
|
||||||
|
|
||||||
if(categoryTitle) {
|
if(categoryTitle) {
|
||||||
titleDiv.innerHTML = categoryTitle;
|
if(typeof(categoryTitle) === 'string') titleDiv.innerHTML = categoryTitle;
|
||||||
|
else titleDiv.append(categoryTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
categoryDiv.append(titleDiv, itemsDiv);
|
categoryDiv.append(titleDiv, itemsDiv);
|
||||||
|
@ -5,10 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import simulateEvent from "../helpers/dom/dispatchEvent";
|
import simulateEvent from "../helpers/dom/dispatchEvent";
|
||||||
|
import documentFragmentToHTML from "../helpers/dom/documentFragmentToHTML";
|
||||||
import findUpAttribute from "../helpers/dom/findUpAttribute";
|
import findUpAttribute from "../helpers/dom/findUpAttribute";
|
||||||
import getRichValue from "../helpers/dom/getRichValue";
|
import getRichValue from "../helpers/dom/getRichValue";
|
||||||
import isInputEmpty from "../helpers/dom/isInputEmpty";
|
import isInputEmpty from "../helpers/dom/isInputEmpty";
|
||||||
import selectElementContents from "../helpers/dom/selectElementContents";
|
import selectElementContents from "../helpers/dom/selectElementContents";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
import { MessageEntity } from "../layer";
|
import { MessageEntity } from "../layer";
|
||||||
import { i18n, LangPackKey, _i18n } from "../lib/langPack";
|
import { i18n, LangPackKey, _i18n } from "../lib/langPack";
|
||||||
import RichTextProcessor from "../lib/richtextprocessor";
|
import RichTextProcessor from "../lib/richtextprocessor";
|
||||||
@ -71,7 +73,8 @@ let init = () => {
|
|||||||
entities = entities.filter(e => e._ === 'messageEntityEmoji' || e._ === 'messageEntityLinebreak');
|
entities = entities.filter(e => e._ === 'messageEntityEmoji' || e._ === 'messageEntityLinebreak');
|
||||||
}
|
}
|
||||||
|
|
||||||
text = RichTextProcessor.wrapDraftText(text, {entities});
|
const fragment = RichTextProcessor.wrapDraftText(text, {entities});
|
||||||
|
text = documentFragmentToHTML(fragment);
|
||||||
|
|
||||||
window.document.execCommand('insertHTML', false, text);
|
window.document.execCommand('insertHTML', false, text);
|
||||||
});
|
});
|
||||||
@ -106,7 +109,7 @@ export type InputFieldOptions = {
|
|||||||
placeholder?: LangPackKey,
|
placeholder?: LangPackKey,
|
||||||
label?: LangPackKey,
|
label?: LangPackKey,
|
||||||
labelOptions?: any[],
|
labelOptions?: any[],
|
||||||
labelText?: string,
|
labelText?: string | DocumentFragment,
|
||||||
name?: string,
|
name?: string,
|
||||||
maxLength?: number,
|
maxLength?: number,
|
||||||
showLengthOn?: number,
|
showLengthOn?: number,
|
||||||
@ -266,7 +269,7 @@ class InputField {
|
|||||||
public setLabel() {
|
public setLabel() {
|
||||||
this.label.textContent = '';
|
this.label.textContent = '';
|
||||||
if(this.options.labelText) {
|
if(this.options.labelText) {
|
||||||
this.label.innerHTML = this.options.labelText;
|
setInnerHTML(this.label, this.options.labelText);
|
||||||
} else {
|
} else {
|
||||||
this.label.append(i18n(this.options.label, this.options.labelOptions));
|
this.label.append(i18n(this.options.label, this.options.labelOptions));
|
||||||
}
|
}
|
||||||
@ -345,7 +348,7 @@ class InputField {
|
|||||||
|
|
||||||
public setDraftValue(value = '', silent = false) {
|
public setDraftValue(value = '', silent = false) {
|
||||||
if(!this.options.plainText) {
|
if(!this.options.plainText) {
|
||||||
value = RichTextProcessor.wrapDraftText(value);
|
value = documentFragmentToHTML(RichTextProcessor.wrapDraftText(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(silent) {
|
if(silent) {
|
||||||
|
@ -8,6 +8,7 @@ import IS_PARALLAX_SUPPORTED from "../environment/parallaxSupport";
|
|||||||
import callbackify from "../helpers/callbackify";
|
import callbackify from "../helpers/callbackify";
|
||||||
import { copyTextToClipboard } from "../helpers/clipboard";
|
import { copyTextToClipboard } from "../helpers/clipboard";
|
||||||
import replaceContent from "../helpers/dom/replaceContent";
|
import replaceContent from "../helpers/dom/replaceContent";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
import ListenerSetter from "../helpers/listenerSetter";
|
import ListenerSetter from "../helpers/listenerSetter";
|
||||||
import { fastRaf } from "../helpers/schedulers";
|
import { fastRaf } from "../helpers/schedulers";
|
||||||
import { Chat, ChatFull, User } from "../layer";
|
import { Chat, ChatFull, User } from "../layer";
|
||||||
@ -31,9 +32,9 @@ import Scrollable from "./scrollable";
|
|||||||
import { SettingSection, generateDelimiter } from "./sidebarLeft";
|
import { SettingSection, generateDelimiter } from "./sidebarLeft";
|
||||||
import { toast } from "./toast";
|
import { toast } from "./toast";
|
||||||
|
|
||||||
let setText = (text: string, row: Row) => {
|
let setText = (text: Parameters<typeof setInnerHTML>[1], row: Row) => {
|
||||||
//fastRaf(() => {
|
//fastRaf(() => {
|
||||||
row.title.innerHTML = text || '';
|
setInnerHTML(row.title, text || '');
|
||||||
row.container.style.display = text ? '' : 'none';
|
row.container.style.display = text ? '' : 'none';
|
||||||
//});
|
//});
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ import appUsersManager from "../lib/appManagers/appUsersManager";
|
|||||||
import RichTextProcessor from "../lib/richtextprocessor";
|
import RichTextProcessor from "../lib/richtextprocessor";
|
||||||
import { NULL_PEER_ID } from "../lib/mtproto/mtproto_config";
|
import { NULL_PEER_ID } from "../lib/mtproto/mtproto_config";
|
||||||
import limitSymbols from "../helpers/string/limitSymbols";
|
import limitSymbols from "../helpers/string/limitSymbols";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
export type PeerTitleOptions = {
|
export type PeerTitleOptions = {
|
||||||
peerId?: PeerId,
|
peerId?: PeerId,
|
||||||
@ -73,7 +74,7 @@ export default class PeerTitle {
|
|||||||
fromName = limitSymbols(fromName, this.limitSymbols, this.limitSymbols);
|
fromName = limitSymbols(fromName, this.limitSymbols, this.limitSymbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.element.innerHTML = RichTextProcessor.wrapEmojiText(fromName);
|
setInnerHTML(this.element, RichTextProcessor.wrapEmojiText(fromName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ export default class PeerTitle {
|
|||||||
if(this.peerId.isUser() && appUsersManager.getUser(this.peerId).pFlags.deleted) {
|
if(this.peerId.isUser() && appUsersManager.getUser(this.peerId).pFlags.deleted) {
|
||||||
replaceContent(this.element, i18n(this.onlyFirstName ? 'Deleted' : 'HiddenName'));
|
replaceContent(this.element, i18n(this.onlyFirstName ? 'Deleted' : 'HiddenName'));
|
||||||
} else {
|
} else {
|
||||||
this.element.innerHTML = appPeersManager.getPeerTitle(this.peerId, this.plainText, this.onlyFirstName, this.limitSymbols);
|
setInnerHTML(this.element, appPeersManager.getPeerTitle(this.peerId, this.plainText, this.onlyFirstName, this.limitSymbols));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
replaceContent(this.element, i18n(this.onlyFirstName ? 'Saved' : 'SavedMessages'));
|
replaceContent(this.element, i18n(this.onlyFirstName ? 'Saved' : 'SavedMessages'));
|
||||||
|
@ -25,6 +25,7 @@ import windowSize from "../helpers/windowSize";
|
|||||||
import { Poll, PollResults } from "../layer";
|
import { Poll, PollResults } from "../layer";
|
||||||
import toHHMMSS from "../helpers/string/toHHMMSS";
|
import toHHMMSS from "../helpers/string/toHHMMSS";
|
||||||
import StackedAvatars from "./stackedAvatars";
|
import StackedAvatars from "./stackedAvatars";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
let lineTotalLength = 0;
|
let lineTotalLength = 0;
|
||||||
const tailLength = 9;
|
const tailLength = 9;
|
||||||
@ -152,7 +153,7 @@ const setQuizHint = (solution: string, solution_entities: any[], onHide: () => v
|
|||||||
container.append(textEl);
|
container.append(textEl);
|
||||||
element.append(container);
|
element.append(container);
|
||||||
|
|
||||||
textEl.innerHTML = RichTextProcessor.wrapRichText(solution, {entities: solution_entities});
|
setInnerHTML(textEl, RichTextProcessor.wrapRichText(solution, {entities: solution_entities}));
|
||||||
appImManager.chat.bubbles.bubblesContainer.append(element);
|
appImManager.chat.bubbles.bubblesContainer.append(element);
|
||||||
|
|
||||||
void element.offsetLeft; // reflow
|
void element.offsetLeft; // reflow
|
||||||
@ -283,12 +284,14 @@ export default class PollElement extends HTMLElement {
|
|||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
this.innerHTML = `
|
this.innerHTML = `
|
||||||
<div class="poll-title">${poll.rQuestion}</div>
|
<div class="poll-title"></div>
|
||||||
<div class="poll-desc">
|
<div class="poll-desc">
|
||||||
<div class="poll-type"></div>
|
<div class="poll-type"></div>
|
||||||
<div class="poll-avatars"></div>
|
<div class="poll-avatars"></div>
|
||||||
</div>
|
</div>
|
||||||
${votes}`;
|
${votes}`;
|
||||||
|
|
||||||
|
setInnerHTML(this.firstElementChild, RichTextProcessor.wrapEmojiText(poll.question));
|
||||||
|
|
||||||
this.descDiv = this.firstElementChild.nextElementSibling as HTMLElement;
|
this.descDiv = this.firstElementChild.nextElementSibling as HTMLElement;
|
||||||
this.typeDiv = this.descDiv.firstElementChild as HTMLElement;
|
this.typeDiv = this.descDiv.firstElementChild as HTMLElement;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import PopupElement, { addCancelButton } from ".";
|
import PopupElement, { addCancelButton } from ".";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
import numberThousandSplitter from "../../helpers/number/numberThousandSplitter";
|
import numberThousandSplitter from "../../helpers/number/numberThousandSplitter";
|
||||||
import { ChatInvite, Updates } from "../../layer";
|
import { ChatInvite, Updates } from "../../layer";
|
||||||
import apiUpdatesManager from "../../lib/appManagers/apiUpdatesManager";
|
import apiUpdatesManager from "../../lib/appManagers/apiUpdatesManager";
|
||||||
@ -75,7 +76,7 @@ export default class PopupJoinChatInvite extends PopupElement {
|
|||||||
|
|
||||||
const title = document.createElement('div');
|
const title = document.createElement('div');
|
||||||
title.classList.add('chat-title');
|
title.classList.add('chat-title');
|
||||||
title.innerHTML = RichTextProcessor.wrapEmojiText(chatInvite.title);
|
setInnerHTML(title, RichTextProcessor.wrapEmojiText(chatInvite.title));
|
||||||
//avatarElem.setAttribute('peer', '' + -fakeChat.id);
|
//avatarElem.setAttribute('peer', '' + -fakeChat.id);
|
||||||
|
|
||||||
const isBroadcast = chatInvite.pFlags.broadcast;
|
const isBroadcast = chatInvite.pFlags.broadcast;
|
||||||
|
@ -19,7 +19,6 @@ import appDownloadManager from "../../lib/appManagers/appDownloadManager";
|
|||||||
import calcImageInBox from "../../helpers/calcImageInBox";
|
import calcImageInBox from "../../helpers/calcImageInBox";
|
||||||
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
|
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
|
||||||
import rootScope from "../../lib/rootScope";
|
import rootScope from "../../lib/rootScope";
|
||||||
import RichTextProcessor from "../../lib/richtextprocessor";
|
|
||||||
import { MediaSize } from "../../helpers/mediaSizes";
|
import { MediaSize } from "../../helpers/mediaSizes";
|
||||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
|
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
|
||||||
@ -358,7 +357,6 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
_: 'document',
|
_: 'document',
|
||||||
file: file,
|
file: file,
|
||||||
file_name: file.name || '',
|
file_name: file.name || '',
|
||||||
fileName: file.name ? RichTextProcessor.wrapEmojiText(file.name) : '',
|
|
||||||
size: file.size,
|
size: file.size,
|
||||||
type: isPhoto ? 'photo' : 'doc'
|
type: isPhoto ? 'photo' : 'doc'
|
||||||
} as MyDocument;
|
} as MyDocument;
|
||||||
|
@ -8,6 +8,7 @@ import AvatarElement from "../avatar";
|
|||||||
import PopupElement, { addCancelButton, PopupButton, PopupOptions } from ".";
|
import PopupElement, { addCancelButton, PopupButton, PopupOptions } from ".";
|
||||||
import { i18n, LangPackKey } from "../../lib/langPack";
|
import { i18n, LangPackKey } from "../../lib/langPack";
|
||||||
import CheckboxField, { CheckboxFieldOptions } from "../checkboxField";
|
import CheckboxField, { CheckboxFieldOptions } from "../checkboxField";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
export type PopupPeerButton = Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>;
|
export type PopupPeerButton = Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>;
|
||||||
export type PopupPeerButtonCallbackCheckboxes = Set<LangPackKey>;
|
export type PopupPeerButtonCallbackCheckboxes = Set<LangPackKey>;
|
||||||
@ -20,7 +21,7 @@ export type PopupPeerOptions = PopupOptions & Partial<{
|
|||||||
titleLangKey?: LangPackKey,
|
titleLangKey?: LangPackKey,
|
||||||
titleLangArgs?: any[],
|
titleLangArgs?: any[],
|
||||||
noTitle?: boolean,
|
noTitle?: boolean,
|
||||||
description: string,
|
description: string | DocumentFragment,
|
||||||
descriptionLangKey?: LangPackKey,
|
descriptionLangKey?: LangPackKey,
|
||||||
descriptionLangArgs?: any[],
|
descriptionLangArgs?: any[],
|
||||||
buttons?: Array<PopupPeerButton>,
|
buttons?: Array<PopupPeerButton>,
|
||||||
@ -55,7 +56,7 @@ export default class PopupPeer extends PopupElement {
|
|||||||
const p = this.description = document.createElement('p');
|
const p = this.description = document.createElement('p');
|
||||||
p.classList.add('popup-description');
|
p.classList.add('popup-description');
|
||||||
if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));
|
if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));
|
||||||
else if(options.description) p.innerHTML = options.description;
|
else if(options.description) setInnerHTML(p, options.description);
|
||||||
|
|
||||||
fragment.append(p);
|
fragment.append(p);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import findUpClassName from "../../helpers/dom/findUpClassName";
|
|||||||
import toggleDisability from "../../helpers/dom/toggleDisability";
|
import toggleDisability from "../../helpers/dom/toggleDisability";
|
||||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
import { toastNew } from "../toast";
|
import { toastNew } from "../toast";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
const ANIMATION_GROUP = 'STICKERS-POPUP';
|
const ANIMATION_GROUP = 'STICKERS-POPUP';
|
||||||
|
|
||||||
@ -98,7 +99,7 @@ export default class PopupStickers extends PopupElement {
|
|||||||
|
|
||||||
animationIntersector.setOnlyOnePlayableGroup(ANIMATION_GROUP);
|
animationIntersector.setOnlyOnePlayableGroup(ANIMATION_GROUP);
|
||||||
|
|
||||||
this.h6.innerHTML = RichTextProcessor.wrapEmojiText(set.set.title);
|
setInnerHTML(this.h6, RichTextProcessor.wrapEmojiText(set.set.title));
|
||||||
this.stickersFooter.classList.toggle('add', !set.set.installed_date);
|
this.stickersFooter.classList.toggle('add', !set.set.installed_date);
|
||||||
|
|
||||||
let button: HTMLElement;
|
let button: HTMLElement;
|
||||||
|
@ -33,7 +33,7 @@ export default class Row {
|
|||||||
radioField: Row['radioField'],
|
radioField: Row['radioField'],
|
||||||
checkboxField: Row['checkboxField'],
|
checkboxField: Row['checkboxField'],
|
||||||
noCheckboxSubtitle: boolean,
|
noCheckboxSubtitle: boolean,
|
||||||
title: string | HTMLElement,
|
title: string | HTMLElement | DocumentFragment,
|
||||||
titleLangKey: LangPackKey,
|
titleLangKey: LangPackKey,
|
||||||
titleRight: string | HTMLElement,
|
titleRight: string | HTMLElement,
|
||||||
titleRightSecondary: string | HTMLElement,
|
titleRightSecondary: string | HTMLElement,
|
||||||
|
@ -10,6 +10,7 @@ import cancelEvent from "../../../../helpers/dom/cancelEvent";
|
|||||||
import { canFocus } from "../../../../helpers/dom/canFocus";
|
import { canFocus } from "../../../../helpers/dom/canFocus";
|
||||||
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
|
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
|
||||||
import replaceContent from "../../../../helpers/dom/replaceContent";
|
import replaceContent from "../../../../helpers/dom/replaceContent";
|
||||||
|
import setInnerHTML from "../../../../helpers/dom/setInnerHTML";
|
||||||
import { AccountPassword } from "../../../../layer";
|
import { AccountPassword } from "../../../../layer";
|
||||||
import I18n, { i18n } from "../../../../lib/langPack";
|
import I18n, { i18n } from "../../../../lib/langPack";
|
||||||
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
||||||
@ -92,7 +93,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
this.state = _state;
|
this.state = _state;
|
||||||
|
|
||||||
if(this.state.hint) {
|
if(this.state.hint) {
|
||||||
passwordInputField.label.innerHTML = RichTextProcessor.wrapEmojiText(this.state.hint);
|
setInnerHTML(passwordInputField.label, RichTextProcessor.wrapEmojiText(this.state.hint));
|
||||||
} else {
|
} else {
|
||||||
replaceContent(passwordInputField.label, i18n('LoginPassword'));
|
replaceContent(passwordInputField.label, i18n('LoginPassword'));
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import copy from "../../../helpers/object/copy";
|
|||||||
import deepEqual from "../../../helpers/object/deepEqual";
|
import deepEqual from "../../../helpers/object/deepEqual";
|
||||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||||
import forEachReverse from "../../../helpers/array/forEachReverse";
|
import forEachReverse from "../../../helpers/array/forEachReverse";
|
||||||
|
import documentFragmentToHTML from "../../../helpers/dom/documentFragmentToHTML";
|
||||||
|
|
||||||
const MAX_FOLDER_NAME_LENGTH = 12;
|
const MAX_FOLDER_NAME_LENGTH = 12;
|
||||||
|
|
||||||
@ -283,7 +284,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filter = this.filter;
|
const filter = this.filter;
|
||||||
this.nameInputField.value = RichTextProcessor.wrapDraftText(filter.title);
|
this.nameInputField.value = documentFragmentToHTML(RichTextProcessor.wrapDraftText(filter.title));
|
||||||
|
|
||||||
for(const flag in this.flags) {
|
for(const flag in this.flags) {
|
||||||
this.flags[flag as keyof AppEditFolderTab['flags']].style.display = !!filter.pFlags[flag as keyof AppEditFolderTab['flags']] ? '' : 'none';
|
this.flags[flag as keyof AppEditFolderTab['flags']].style.display = !!filter.pFlags[flag as keyof AppEditFolderTab['flags']] ? '' : 'none';
|
||||||
|
@ -21,6 +21,7 @@ import { toast } from "../../toast";
|
|||||||
import appPeersManager from "../../../lib/appManagers/appPeersManager";
|
import appPeersManager from "../../../lib/appManagers/appPeersManager";
|
||||||
import copy from "../../../helpers/object/copy";
|
import copy from "../../../helpers/object/copy";
|
||||||
import forEachReverse from "../../../helpers/array/forEachReverse";
|
import forEachReverse from "../../../helpers/array/forEachReverse";
|
||||||
|
import setInnerHTML from "../../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
export default class AppIncludedChatsTab extends SliderSuperTab {
|
export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||||
private editFolderTab: AppEditFolderTab;
|
private editFolderTab: AppEditFolderTab;
|
||||||
@ -149,7 +150,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
|||||||
this.dialogsByFilters.forEach((dialogs, filter) => {
|
this.dialogsByFilters.forEach((dialogs, filter) => {
|
||||||
if(dialogs.has(peerId)) {
|
if(dialogs.has(peerId)) {
|
||||||
const span = document.createElement('span');
|
const span = document.createElement('span');
|
||||||
span.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);
|
setInnerHTML(span, RichTextProcessor.wrapEmojiText(filter.title));
|
||||||
foundInFilters.push(span);
|
foundInFilters.push(span);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,7 @@ import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
|||||||
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
||||||
import ripple from "../../ripple";
|
import ripple from "../../ripple";
|
||||||
import { i18n } from "../../../lib/langPack";
|
import { i18n } from "../../../lib/langPack";
|
||||||
|
import setInnerHTML from "../../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
export default class AppPollResultsTab extends SliderSuperTab {
|
export default class AppPollResultsTab extends SliderSuperTab {
|
||||||
private resultsDiv: HTMLElement;
|
private resultsDiv: HTMLElement;
|
||||||
@ -32,7 +33,7 @@ export default class AppPollResultsTab extends SliderSuperTab {
|
|||||||
this.setTitle(poll.poll.pFlags.quiz ? 'PollResults.Title.Quiz' : 'PollResults.Title.Poll');
|
this.setTitle(poll.poll.pFlags.quiz ? 'PollResults.Title.Quiz' : 'PollResults.Title.Poll');
|
||||||
|
|
||||||
const title = document.createElement('h3');
|
const title = document.createElement('h3');
|
||||||
title.innerHTML = poll.poll.rQuestion;
|
setInnerHTML(title, RichTextProcessor.wrapEmojiText(poll.poll.question));
|
||||||
|
|
||||||
const percents = poll.results.results.map(v => v.voters / poll.results.total_voters * 100);
|
const percents = poll.results.results.map(v => v.voters / poll.results.total_voters * 100);
|
||||||
roundPercents(percents);
|
roundPercents(percents);
|
||||||
@ -50,7 +51,7 @@ export default class AppPollResultsTab extends SliderSuperTab {
|
|||||||
answerEl.classList.add('poll-results-answer');
|
answerEl.classList.add('poll-results-answer');
|
||||||
|
|
||||||
const answerTitle = document.createElement('div');
|
const answerTitle = document.createElement('div');
|
||||||
answerTitle.innerHTML = RichTextProcessor.wrapEmojiText(answer.text);
|
setInnerHTML(answerTitle, RichTextProcessor.wrapEmojiText(answer.text));
|
||||||
|
|
||||||
const answerPercents = document.createElement('div');
|
const answerPercents = document.createElement('div');
|
||||||
answerPercents.innerText = Math.round(percents[idx]) + '%';
|
answerPercents.innerText = Math.round(percents[idx]) + '%';
|
||||||
|
@ -59,6 +59,7 @@ import { ChatAutoDownloadSettings } from '../helpers/autoDownload';
|
|||||||
import formatBytes from '../helpers/formatBytes';
|
import formatBytes from '../helpers/formatBytes';
|
||||||
import toHHMMSS from '../helpers/string/toHHMMSS';
|
import toHHMMSS from '../helpers/string/toHHMMSS';
|
||||||
import createVideo from '../helpers/dom/createVideo';
|
import createVideo from '../helpers/dom/createVideo';
|
||||||
|
import setInnerHTML from '../helpers/dom/setInnerHTML';
|
||||||
|
|
||||||
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
|
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
|
||||||
|
|
||||||
@ -652,7 +653,7 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
|||||||
}
|
}
|
||||||
|
|
||||||
//let fileName = stringMiddleOverflow(doc.file_name || 'Unknown.file', 26);
|
//let fileName = stringMiddleOverflow(doc.file_name || 'Unknown.file', 26);
|
||||||
let fileName = doc.fileName || 'Unknown.file';
|
let fileName = doc.file_name ? RichTextProcessor.wrapPlainText(doc.file_name) : 'Unknown.file';
|
||||||
const descriptionEl = document.createElement('div');
|
const descriptionEl = document.createElement('div');
|
||||||
descriptionEl.classList.add('document-description');
|
descriptionEl.classList.add('document-description');
|
||||||
const descriptionParts: (HTMLElement | string | DocumentFragment)[] = [formatBytes(doc.size)];
|
const descriptionParts: (HTMLElement | string | DocumentFragment)[] = [formatBytes(doc.size)];
|
||||||
@ -675,7 +676,8 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
|||||||
const middleEllipsisEl = new MiddleEllipsisElement();
|
const middleEllipsisEl = new MiddleEllipsisElement();
|
||||||
middleEllipsisEl.dataset.fontWeight = '' + fontWeight;
|
middleEllipsisEl.dataset.fontWeight = '' + fontWeight;
|
||||||
middleEllipsisEl.dataset.sizeType = sizeType;
|
middleEllipsisEl.dataset.sizeType = sizeType;
|
||||||
middleEllipsisEl.innerHTML = fileName;
|
middleEllipsisEl.textContent = fileName;
|
||||||
|
// setInnerHTML(middleEllipsisEl, fileName);
|
||||||
|
|
||||||
nameDiv.append(middleEllipsisEl);
|
nameDiv.append(middleEllipsisEl);
|
||||||
|
|
||||||
@ -2082,7 +2084,7 @@ export function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble,
|
|||||||
entities: message.totalEntities
|
entities: message.totalEntities
|
||||||
});
|
});
|
||||||
|
|
||||||
messageDiv.innerHTML = richText;
|
setInnerHTML(messageDiv, richText);
|
||||||
wrapper.append(messageDiv);
|
wrapper.append(messageDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
src/helpers/dom/documentFragmentToHTML.ts
Normal file
5
src/helpers/dom/documentFragmentToHTML.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export default function documentFragmentToHTML(fragment: DocumentFragment) {
|
||||||
|
return Array.from(fragment.childNodes).map((node) => {
|
||||||
|
return node.nodeType === 3 ? node.textContent : (node as Element).outerHTML + '\n';
|
||||||
|
}).join('');
|
||||||
|
}
|
@ -4,8 +4,9 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default function htmlToDocumentFragment(html: string) {
|
export default function htmlToDocumentFragment(html: string | DocumentFragment) {
|
||||||
var template = document.createElement('template');
|
if(html instanceof DocumentFragment) return html;
|
||||||
|
const template = document.createElement('template');
|
||||||
html = html.trim(); // Never return a text node of whitespace as the result
|
html = html.trim(); // Never return a text node of whitespace as the result
|
||||||
template.innerHTML = html;
|
template.innerHTML = html;
|
||||||
return template.content;
|
return template.content;
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default function htmlToSpan(html: string) {
|
export default function htmlToSpan(html: string | DocumentFragment) {
|
||||||
const span = document.createElement('span');
|
const span = document.createElement('span');
|
||||||
span.innerHTML = html;
|
if(typeof(html) === 'string') span.innerHTML = html;
|
||||||
|
else span.append(html);
|
||||||
return span;
|
return span;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,12 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default function setInnerHTML(elem: Element, html: string) {
|
export default function setInnerHTML(elem: Element, html: string | DocumentFragment) {
|
||||||
elem.setAttribute('dir', 'auto');
|
elem.setAttribute('dir', 'auto');
|
||||||
elem.innerHTML = html;
|
if(typeof(html) === 'string') {
|
||||||
|
elem.innerHTML = html;
|
||||||
|
} else {
|
||||||
|
elem.textContent = '';
|
||||||
|
elem.append(html);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
23
src/layer.d.ts
vendored
23
src/layer.d.ts
vendored
@ -511,7 +511,6 @@ export namespace User {
|
|||||||
restriction_reason?: Array<RestrictionReason>,
|
restriction_reason?: Array<RestrictionReason>,
|
||||||
bot_inline_placeholder?: string,
|
bot_inline_placeholder?: string,
|
||||||
lang_code?: string,
|
lang_code?: string,
|
||||||
initials?: string,
|
|
||||||
sortName?: string
|
sortName?: string
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -601,15 +600,13 @@ export namespace Chat {
|
|||||||
version: number,
|
version: number,
|
||||||
migrated_to?: InputChannel,
|
migrated_to?: InputChannel,
|
||||||
admin_rights?: ChatAdminRights,
|
admin_rights?: ChatAdminRights,
|
||||||
default_banned_rights?: ChatBannedRights,
|
default_banned_rights?: ChatBannedRights
|
||||||
initials?: string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type chatForbidden = {
|
export type chatForbidden = {
|
||||||
_: 'chatForbidden',
|
_: 'chatForbidden',
|
||||||
id: string | number,
|
id: string | number,
|
||||||
title: string,
|
title: string
|
||||||
initials?: string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type channel = {
|
export type channel = {
|
||||||
@ -646,8 +643,7 @@ export namespace Chat {
|
|||||||
admin_rights?: ChatAdminRights,
|
admin_rights?: ChatAdminRights,
|
||||||
banned_rights?: ChatBannedRights,
|
banned_rights?: ChatBannedRights,
|
||||||
default_banned_rights?: ChatBannedRights,
|
default_banned_rights?: ChatBannedRights,
|
||||||
participants_count?: number,
|
participants_count?: number
|
||||||
initials?: string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type channelForbidden = {
|
export type channelForbidden = {
|
||||||
@ -660,8 +656,7 @@ export namespace Chat {
|
|||||||
id: string | number,
|
id: string | number,
|
||||||
access_hash: string | number,
|
access_hash: string | number,
|
||||||
title: string,
|
title: string,
|
||||||
until_date?: number,
|
until_date?: number
|
||||||
initials?: string
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3281,13 +3276,9 @@ export namespace Document {
|
|||||||
h?: number,
|
h?: number,
|
||||||
w?: number,
|
w?: number,
|
||||||
file_name?: string,
|
file_name?: string,
|
||||||
fileName?: string,
|
|
||||||
file?: File,
|
file?: File,
|
||||||
duration?: number,
|
duration?: number,
|
||||||
audioTitle?: string,
|
|
||||||
audioPerformer?: string,
|
|
||||||
sticker?: 1 | 2 | 3,
|
sticker?: 1 | 2 | 3,
|
||||||
stickerEmoji?: string,
|
|
||||||
stickerEmojiRaw?: string,
|
stickerEmojiRaw?: string,
|
||||||
stickerSetInput?: InputStickerSet.inputStickerSetID,
|
stickerSetInput?: InputStickerSet.inputStickerSetID,
|
||||||
pFlags?: Partial<{
|
pFlags?: Partial<{
|
||||||
@ -3788,9 +3779,7 @@ export namespace WebPage {
|
|||||||
author?: string,
|
author?: string,
|
||||||
document?: Document,
|
document?: Document,
|
||||||
cached_page?: Page,
|
cached_page?: Page,
|
||||||
attributes?: Array<WebPageAttribute>,
|
attributes?: Array<WebPageAttribute>
|
||||||
rTitle?: string,
|
|
||||||
rDescription?: string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type webPageNotModified = {
|
export type webPageNotModified = {
|
||||||
@ -7632,8 +7621,6 @@ export namespace Poll {
|
|||||||
answers: Array<PollAnswer>,
|
answers: Array<PollAnswer>,
|
||||||
close_period?: number,
|
close_period?: number,
|
||||||
close_date?: number,
|
close_date?: number,
|
||||||
rQuestion?: string,
|
|
||||||
rReply?: string,
|
|
||||||
chosenIndexes?: number[]
|
chosenIndexes?: number[]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||||
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
||||||
import replaceContent from "../../helpers/dom/replaceContent";
|
import replaceContent from "../../helpers/dom/replaceContent";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
import sequentialDom from "../../helpers/sequentialDom";
|
import sequentialDom from "../../helpers/sequentialDom";
|
||||||
import { UserProfilePhoto, ChatPhoto, InputFileLocation } from "../../layer";
|
import { UserProfilePhoto, ChatPhoto, InputFileLocation } from "../../layer";
|
||||||
import { DownloadOptions } from "../mtproto/apiFileManager";
|
import { DownloadOptions } from "../mtproto/apiFileManager";
|
||||||
@ -163,8 +164,8 @@ export class AppAvatarsManager {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public s(div: HTMLElement, innerHTML: string, color: string, icon: string) {
|
public s(div: HTMLElement, innerHTML: Parameters<typeof setInnerHTML>[1], color: string, icon: string) {
|
||||||
div.innerHTML = innerHTML;
|
setInnerHTML(div, innerHTML);
|
||||||
div.dataset.color = color;
|
div.dataset.color = color;
|
||||||
div.classList.remove('tgico-saved', 'tgico-deletedaccount', 'tgico-reply_filled');
|
div.classList.remove('tgico-saved', 'tgico-deletedaccount', 'tgico-reply_filled');
|
||||||
icon && div.classList.add(icon);
|
icon && div.classList.add(icon);
|
||||||
@ -202,14 +203,7 @@ export class AppAvatarsManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let abbr: string;
|
const abbr = title ? RichTextProcessor.getAbbreviation(title) : appPeersManager.getPeerInitials(peerId);
|
||||||
if(!title) {
|
|
||||||
const peer = appPeersManager.getPeer(peerId);
|
|
||||||
abbr = peer.initials ?? '';
|
|
||||||
} else {
|
|
||||||
abbr = RichTextProcessor.getAbbreviation(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.s(div, abbr, color, '');
|
this.s(div, abbr, color, '');
|
||||||
//return Promise.resolve(true);
|
//return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
@ -144,8 +144,6 @@ export class AppChatsManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chat.initials = RichTextProcessor.getAbbreviation(chat.title);
|
|
||||||
|
|
||||||
if(chat._ === 'channel' &&
|
if(chat._ === 'channel' &&
|
||||||
chat.participants_count === undefined &&
|
chat.participants_count === undefined &&
|
||||||
oldChat !== undefined &&
|
oldChat !== undefined &&
|
||||||
|
@ -62,6 +62,7 @@ import appNavigationController, { NavigationItem } from "../../components/appNav
|
|||||||
import assumeType from "../../helpers/assumeType";
|
import assumeType from "../../helpers/assumeType";
|
||||||
import generateTitleIcons from "../../components/generateTitleIcons";
|
import generateTitleIcons from "../../components/generateTitleIcons";
|
||||||
import appMediaPlaybackController from "../../components/appMediaPlaybackController";
|
import appMediaPlaybackController from "../../components/appMediaPlaybackController";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
export type DialogDom = {
|
export type DialogDom = {
|
||||||
avatarEl: AvatarElement,
|
avatarEl: AvatarElement,
|
||||||
@ -517,7 +518,7 @@ export class AppDialogsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const elements = this.filtersRendered[filter.id];
|
const elements = this.filtersRendered[filter.id];
|
||||||
elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);
|
setInnerHTML(elements.title, RichTextProcessor.wrapEmojiText(filter.title));
|
||||||
});
|
});
|
||||||
|
|
||||||
rootScope.addEventListener('filter_delete', (filter) => {
|
rootScope.addEventListener('filter_delete', (filter) => {
|
||||||
@ -779,7 +780,7 @@ export class AppDialogsManager {
|
|||||||
const titleSpan = document.createElement('span');
|
const titleSpan = document.createElement('span');
|
||||||
titleSpan.classList.add('text-super');
|
titleSpan.classList.add('text-super');
|
||||||
if(filter.titleEl) titleSpan.append(filter.titleEl);
|
if(filter.titleEl) titleSpan.append(filter.titleEl);
|
||||||
else titleSpan.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);
|
else setInnerHTML(titleSpan, RichTextProcessor.wrapEmojiText(filter.title));
|
||||||
const unreadSpan = document.createElement('div');
|
const unreadSpan = document.createElement('div');
|
||||||
unreadSpan.classList.add('badge', 'badge-20', 'badge-primary');
|
unreadSpan.classList.add('badge', 'badge-20', 'badge-primary');
|
||||||
const i = document.createElement('i');
|
const i = document.createElement('i');
|
||||||
|
@ -105,13 +105,10 @@ export class AppDocsManager {
|
|||||||
switch(attribute._) {
|
switch(attribute._) {
|
||||||
case 'documentAttributeFilename':
|
case 'documentAttributeFilename':
|
||||||
doc.file_name = RichTextProcessor.wrapPlainText(attribute.file_name);
|
doc.file_name = RichTextProcessor.wrapPlainText(attribute.file_name);
|
||||||
doc.fileName = RichTextProcessor.wrapEmojiText(attribute.file_name);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'documentAttributeAudio':
|
case 'documentAttributeAudio':
|
||||||
doc.duration = attribute.duration;
|
doc.duration = attribute.duration;
|
||||||
doc.audioTitle = RichTextProcessor.wrapEmojiText(attribute.title);
|
|
||||||
doc.audioPerformer = RichTextProcessor.wrapEmojiText(attribute.performer);
|
|
||||||
doc.type = attribute.pFlags.voice && doc.mime_type === 'audio/ogg' ? 'voice' : 'audio';
|
doc.type = attribute.pFlags.voice && doc.mime_type === 'audio/ogg' ? 'voice' : 'audio';
|
||||||
/* if(apiDoc.type === 'audio') {
|
/* if(apiDoc.type === 'audio') {
|
||||||
apiDoc.supportsStreaming = true;
|
apiDoc.supportsStreaming = true;
|
||||||
@ -133,7 +130,6 @@ export class AppDocsManager {
|
|||||||
case 'documentAttributeSticker':
|
case 'documentAttributeSticker':
|
||||||
if(attribute.alt !== undefined) {
|
if(attribute.alt !== undefined) {
|
||||||
doc.stickerEmojiRaw = attribute.alt;
|
doc.stickerEmojiRaw = attribute.alt;
|
||||||
doc.stickerEmoji = RichTextProcessor.wrapRichText(doc.stickerEmojiRaw, {noLinks: true, noLinebreaks: true});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attribute.stickerset) {
|
if(attribute.stickerset) {
|
||||||
@ -210,7 +206,7 @@ export class AppDocsManager {
|
|||||||
|
|
||||||
if(doc.type === 'voice' || doc.type === 'round') {
|
if(doc.type === 'voice' || doc.type === 'round') {
|
||||||
// browser will identify extension
|
// browser will identify extension
|
||||||
doc.file_name = doc.fileName = doc.type + '_' + getFullDate(new Date(doc.date * 1000), {monthAsNumber: true, leadingZero: true}).replace(/[:\.]/g, '-').replace(', ', '_');
|
doc.file_name = doc.type + '_' + getFullDate(new Date(doc.date * 1000), {monthAsNumber: true, leadingZero: true}).replace(/[:\.]/g, '-').replace(', ', '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(apiManager.isServiceWorkerOnline()) {
|
if(apiManager.isServiceWorkerOnline()) {
|
||||||
@ -229,7 +225,7 @@ export class AppDocsManager {
|
|||||||
// doc.url = ''; // * this will break upload urls
|
// doc.url = ''; // * this will break upload urls
|
||||||
|
|
||||||
if(!doc.file_name) {
|
if(!doc.file_name) {
|
||||||
doc.file_name = doc.fileName = '';
|
doc.file_name = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(doc.mime_type === 'application/x-tgsticker' && doc.file_name === 'AnimatedSticker.tgs') {
|
if(doc.mime_type === 'application/x-tgsticker' && doc.file_name === 'AnimatedSticker.tgs') {
|
||||||
|
@ -24,6 +24,7 @@ import appMessagesIdsManager from "./appMessagesIdsManager";
|
|||||||
import assumeType from "../../helpers/assumeType";
|
import assumeType from "../../helpers/assumeType";
|
||||||
import isObject from "../../helpers/object/isObject";
|
import isObject from "../../helpers/object/isObject";
|
||||||
import deepEqual from "../../helpers/object/deepEqual";
|
import deepEqual from "../../helpers/object/deepEqual";
|
||||||
|
import documentFragmentToHTML from "../../helpers/dom/documentFragmentToHTML";
|
||||||
|
|
||||||
export type MyDraftMessage = DraftMessage.draftMessage;
|
export type MyDraftMessage = DraftMessage.draftMessage;
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ export class AppDraftsManager {
|
|||||||
const apiEntities = draft.entities || [];
|
const apiEntities = draft.entities || [];
|
||||||
const totalEntities = RichTextProcessor.mergeEntities(apiEntities.slice(), myEntities); // ! only in this order, otherwise bold and emoji formatting won't work
|
const totalEntities = RichTextProcessor.mergeEntities(apiEntities.slice(), myEntities); // ! only in this order, otherwise bold and emoji formatting won't work
|
||||||
|
|
||||||
draft.rMessage = RichTextProcessor.wrapDraftText(draft.message, {entities: totalEntities});
|
draft.rMessage = documentFragmentToHTML(RichTextProcessor.wrapDraftText(draft.message, {entities: totalEntities}));
|
||||||
//draft.rReply = appMessagesManager.getRichReplyText(draft);
|
//draft.rReply = appMessagesManager.getRichReplyText(draft);
|
||||||
if(draft.reply_to_msg_id) {
|
if(draft.reply_to_msg_id) {
|
||||||
draft.reply_to_msg_id = appMessagesIdsManager.generateMessageId(draft.reply_to_msg_id);
|
draft.reply_to_msg_id = appMessagesIdsManager.generateMessageId(draft.reply_to_msg_id);
|
||||||
|
@ -71,6 +71,7 @@ import escapeRegExp from "../../helpers/string/escapeRegExp";
|
|||||||
import limitSymbols from "../../helpers/string/limitSymbols";
|
import limitSymbols from "../../helpers/string/limitSymbols";
|
||||||
import splitStringByLength from "../../helpers/string/splitStringByLength";
|
import splitStringByLength from "../../helpers/string/splitStringByLength";
|
||||||
import debounce from "../../helpers/schedulers/debounce";
|
import debounce from "../../helpers/schedulers/debounce";
|
||||||
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
//console.trace('include');
|
//console.trace('include');
|
||||||
// TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках
|
// TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках
|
||||||
@ -2905,7 +2906,7 @@ export class AppMessagesManager {
|
|||||||
const parts: (Node | string)[] = [];
|
const parts: (Node | string)[] = [];
|
||||||
|
|
||||||
let hasAlbumKey = false;
|
let hasAlbumKey = false;
|
||||||
const addPart = (langKey: LangPackKey, part?: string | HTMLElement) => {
|
const addPart = (langKey: LangPackKey, part?: string | HTMLElement | DocumentFragment) => {
|
||||||
if(langKey) {
|
if(langKey) {
|
||||||
if(part === undefined && hasAlbumKey) {
|
if(part === undefined && hasAlbumKey) {
|
||||||
return;
|
return;
|
||||||
@ -2980,7 +2981,8 @@ export class AppMessagesManager {
|
|||||||
addPart('AttachLiveLocation');
|
addPart('AttachLiveLocation');
|
||||||
break;
|
break;
|
||||||
case 'messageMediaPoll':
|
case 'messageMediaPoll':
|
||||||
addPart(undefined, plain ? '📊' + ' ' + (media.poll.question || 'poll') : media.poll.rReply);
|
const f = '📊' + ' ' + (media.poll.question || 'poll');
|
||||||
|
addPart(undefined, plain ? f : RichTextProcessor.wrapEmojiText(f));
|
||||||
break;
|
break;
|
||||||
case 'messageMediaContact':
|
case 'messageMediaContact':
|
||||||
addPart('AttachContact');
|
addPart('AttachContact');
|
||||||
@ -3004,7 +3006,8 @@ export class AppMessagesManager {
|
|||||||
} else if(document.type === 'sticker') {
|
} else if(document.type === 'sticker') {
|
||||||
const i = parts.length;
|
const i = parts.length;
|
||||||
if(document.stickerEmojiRaw) {
|
if(document.stickerEmojiRaw) {
|
||||||
addPart(undefined, (plain ? document.stickerEmojiRaw : document.stickerEmoji) + ' ');
|
const f = document.stickerEmojiRaw + ' ';
|
||||||
|
addPart(undefined, plain ? f : RichTextProcessor.wrapEmojiText(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
addPart('AttachSticker');
|
addPart('AttachSticker');
|
||||||
@ -3099,7 +3102,7 @@ export class AppMessagesManager {
|
|||||||
noTextFormat: true
|
noTextFormat: true
|
||||||
});
|
});
|
||||||
|
|
||||||
parts.push(htmlToDocumentFragment(messageWrapped) as any);
|
parts.push(htmlToDocumentFragment(messageWrapped));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3179,7 +3182,7 @@ export class AppMessagesManager {
|
|||||||
if(plain) {
|
if(plain) {
|
||||||
return RichTextProcessor.wrapPlainText(unsafeMessage);
|
return RichTextProcessor.wrapPlainText(unsafeMessage);
|
||||||
} else {
|
} else {
|
||||||
element.innerHTML = RichTextProcessor.wrapRichText(unsafeMessage, {noLinebreaks: true});
|
setInnerHTML(element, RichTextProcessor.wrapRichText(unsafeMessage, {noLinebreaks: true}));
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -74,7 +74,10 @@ export class AppPeersManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPeerTitle(peerId: PeerId, plainText = false, onlyFirstName = false, _limitSymbols?: number) {
|
public getPeerTitle(peerId: PeerId, plainText: true, onlyFirstName?: boolean, _limitSymbols?: number): string;
|
||||||
|
public getPeerTitle(peerId: PeerId, plainText?: false, onlyFirstName?: boolean, _limitSymbols?: number): DocumentFragment;
|
||||||
|
public getPeerTitle(peerId: PeerId, plainText: boolean, onlyFirstName?: boolean, _limitSymbols?: number): DocumentFragment | string;
|
||||||
|
public getPeerTitle(peerId: PeerId, plainText = false, onlyFirstName = false, _limitSymbols?: number): DocumentFragment | string {
|
||||||
if(!peerId) {
|
if(!peerId) {
|
||||||
peerId = rootScope.myId;
|
peerId = rootScope.myId;
|
||||||
}
|
}
|
||||||
@ -133,6 +136,13 @@ export class AppPeersManager {
|
|||||||
: appChatsManager.getChat(peerId.toChatId());
|
: appChatsManager.getChat(peerId.toChatId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getPeerInitials(peerId: PeerId) {
|
||||||
|
const peer: Chat | User = this.getPeer(peerId);
|
||||||
|
return RichTextProcessor.getAbbreviation(
|
||||||
|
(peer as Chat.chat).title ?? [(peer as User.user).first_name, (peer as User.user).last_name].filter(Boolean).join(' ')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public getPeerId(peerId: {user_id: UserId} | {channel_id: ChatId} | {chat_id: ChatId} | InputPeer | PeerId | string): PeerId {
|
public getPeerId(peerId: {user_id: UserId} | {channel_id: ChatId} | {chat_id: ChatId} | InputPeer | PeerId | string): PeerId {
|
||||||
if(peerId !== undefined && ((peerId as string).isPeerId ? (peerId as string).isPeerId() : false)) return peerId as PeerId;
|
if(peerId !== undefined && ((peerId as string).isPeerId ? (peerId as string).isPeerId() : false)) return peerId as PeerId;
|
||||||
// if(typeof(peerId) === 'string' && /^[uc]/.test(peerId)) return peerId as PeerId;
|
// if(typeof(peerId) === 'string' && /^[uc]/.test(peerId)) return peerId as PeerId;
|
||||||
|
@ -56,8 +56,6 @@ export class AppPollsManager {
|
|||||||
} else {
|
} else {
|
||||||
this.polls[id] = poll;
|
this.polls[id] = poll;
|
||||||
|
|
||||||
poll.rQuestion = RichTextProcessor.wrapEmojiText(poll.question);
|
|
||||||
poll.rReply = RichTextProcessor.wrapEmojiText('📊') + ' ' + (poll.rQuestion || 'poll');
|
|
||||||
poll.chosenIndexes = [];
|
poll.chosenIndexes = [];
|
||||||
results = this.saveResults(poll, results);
|
results = this.saveResults(poll, results);
|
||||||
}
|
}
|
||||||
|
@ -431,17 +431,14 @@ export class AppUsersManager {
|
|||||||
this.setUserNameToCache(user, oldUser);
|
this.setUserNameToCache(user, oldUser);
|
||||||
|
|
||||||
if(!oldUser
|
if(!oldUser
|
||||||
|| oldUser.initials === undefined
|
|
||||||
|| oldUser.sortName === undefined
|
|| oldUser.sortName === undefined
|
||||||
|| oldUser.first_name !== user.first_name
|
|| oldUser.first_name !== user.first_name
|
||||||
|| oldUser.last_name !== user.last_name) {
|
|| oldUser.last_name !== user.last_name) {
|
||||||
const fullName = user.first_name + (user.last_name ? ' ' + user.last_name : '');
|
const fullName = user.first_name + (user.last_name ? ' ' + user.last_name : '');
|
||||||
|
|
||||||
user.sortName = user.pFlags.deleted ? '' : cleanSearchText(fullName, false);
|
user.sortName = user.pFlags.deleted ? '' : cleanSearchText(fullName, false);
|
||||||
user.initials = RichTextProcessor.getAbbreviation(fullName);
|
|
||||||
} else {
|
} else {
|
||||||
user.sortName = oldUser.sortName;
|
user.sortName = oldUser.sortName;
|
||||||
user.initials = oldUser.initials;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(user.status) {
|
if(user.status) {
|
||||||
|
@ -71,23 +71,7 @@ export class AppWebPagesManager {
|
|||||||
delete apiWebPage.site_name;
|
delete apiWebPage.site_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
shortTitle = limitSymbols(shortTitle, 80, 100);
|
|
||||||
|
|
||||||
apiWebPage.rTitle = RichTextProcessor.wrapRichText(shortTitle, {noLinks: true, noLinebreaks: true});
|
|
||||||
let contextHashtag = '';
|
|
||||||
if(siteName === 'GitHub') {
|
|
||||||
const matches = apiWebPage.url.match(/(https?:\/\/github\.com\/[^\/]+\/[^\/]+)/);
|
|
||||||
if(matches) {
|
|
||||||
contextHashtag = matches[0] + '/issues/{1}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete apiWebPage.description
|
// delete apiWebPage.description
|
||||||
const shortDescriptionText = limitSymbols(apiWebPage.description || '', 150, 180);
|
|
||||||
apiWebPage.rDescription = RichTextProcessor.wrapRichText(shortDescriptionText, {
|
|
||||||
contextSite: siteName || 'external',
|
|
||||||
contextHashtag: contextHashtag
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!photoTypeSet.has(apiWebPage.type) &&
|
if(!photoTypeSet.has(apiWebPage.type) &&
|
||||||
!apiWebPage.description &&
|
!apiWebPage.description &&
|
||||||
@ -128,6 +112,28 @@ export class AppWebPagesManager {
|
|||||||
return apiWebPage;
|
return apiWebPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public wrapTitle(webPage: WebPage.webPage) {
|
||||||
|
let shortTitle = webPage.title || webPage.author || webPage.site_name || '';
|
||||||
|
shortTitle = limitSymbols(shortTitle, 80, 100);
|
||||||
|
return RichTextProcessor.wrapRichText(shortTitle, {noLinks: true, noLinebreaks: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
public wrapDescription(webPage: WebPage.webPage) {
|
||||||
|
const shortDescriptionText = limitSymbols(webPage.description || '', 150, 180);
|
||||||
|
// const siteName = webPage.site_name;
|
||||||
|
// let contextHashtag = '';
|
||||||
|
// if(siteName === 'GitHub') {
|
||||||
|
// const matches = apiWebPage.url.match(/(https?:\/\/github\.com\/[^\/]+\/[^\/]+)/);
|
||||||
|
// if(matches) {
|
||||||
|
// contextHashtag = matches[0] + '/issues/{1}';
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return RichTextProcessor.wrapRichText(shortDescriptionText/* , {
|
||||||
|
contextSite: siteName || 'external',
|
||||||
|
contextHashtag: contextHashtag
|
||||||
|
} */);
|
||||||
|
}
|
||||||
|
|
||||||
public getMessageKeyForPendingWebPage(peerId: PeerId, mid: number, isScheduled?: boolean): WebPageMessageKey {
|
public getMessageKeyForPendingWebPage(peerId: PeerId, mid: number, isScheduled?: boolean): WebPageMessageKey {
|
||||||
return peerId + '_' + mid + (isScheduled ? '_s' : '') as any;
|
return peerId + '_' + mid + (isScheduled ? '_s' : '') as any;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import emojiRegExp from '../vendor/emoji/regex';
|
import emojiRegExp from '../vendor/emoji/regex';
|
||||||
import { encodeEmoji, toCodePoints } from '../vendor/emoji';
|
import { encodeEmoji, toCodePoints } from '../vendor/emoji';
|
||||||
import { MessageEntity } from '../layer';
|
import { Message, MessageEntity } from '../layer';
|
||||||
import { IS_SAFARI } from '../environment/userAgent';
|
import { IS_SAFARI } from '../environment/userAgent';
|
||||||
import { MOUNT_CLASS_TO } from '../config/debug';
|
import { MOUNT_CLASS_TO } from '../config/debug';
|
||||||
import IS_EMOJI_SUPPORTED from '../environment/emojiSupport';
|
import IS_EMOJI_SUPPORTED from '../environment/emojiSupport';
|
||||||
@ -463,10 +463,16 @@ namespace RichTextProcessor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setBlankToAnchor(anchor: HTMLAnchorElement) {
|
||||||
|
anchor.target = '_blank';
|
||||||
|
anchor.rel = 'noopener noreferrer';
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * Expecting correctly sorted nested entities (RichTextProcessor.sortEntities)
|
* * Expecting correctly sorted nested entities (RichTextProcessor.sortEntities)
|
||||||
*/
|
*/
|
||||||
export function wrapRichText(text: string, options: Partial<{
|
export function wrapRichText(text: string, options: Partial<{
|
||||||
entities: MessageEntity[],
|
entities: MessageEntity[],
|
||||||
contextSite: string,
|
contextSite: string,
|
||||||
highlightUsername: string,
|
highlightUsername: string,
|
||||||
@ -483,57 +489,33 @@ namespace RichTextProcessor {
|
|||||||
noEncoding: boolean,
|
noEncoding: boolean,
|
||||||
|
|
||||||
contextHashtag?: string,
|
contextHashtag?: string,
|
||||||
|
nasty?: {
|
||||||
|
i: number,
|
||||||
|
usedLength: number,
|
||||||
|
lastEntity?: MessageEntity
|
||||||
|
},
|
||||||
|
voodoo?: boolean
|
||||||
}> = {}) {
|
}> = {}) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
if(!text) {
|
if(!text) {
|
||||||
return '';
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lol: {
|
const entities = options.entities ??= parseEntities(text);
|
||||||
part: string,
|
|
||||||
offset: number,
|
|
||||||
// priority: number
|
|
||||||
}[] = [];
|
|
||||||
const entities = options.entities || parseEntities(text);
|
|
||||||
|
|
||||||
const passEntities: typeof options.passEntities = options.passEntities || {};
|
const passEntities = options.passEntities ??= {};
|
||||||
const contextSite = options.contextSite || 'Telegram';
|
const contextSite = options.contextSite ??= 'Telegram';
|
||||||
const contextExternal = contextSite !== 'Telegram';
|
const contextExternal = contextSite !== 'Telegram';
|
||||||
|
const nasty = options.nasty ??= {
|
||||||
const insertPart = (entity: MessageEntity, startPart: string, endPart?: string/* , priority = 0 */) => {
|
i: 0,
|
||||||
const startOffset = entity.offset, endOffset = endPart ? entity.offset + entity.length : undefined;
|
usedLength: 0
|
||||||
let startIndex: number, endIndex: number, length = lol.length;
|
|
||||||
for(let i = length - 1; i >= 0; --i) {
|
|
||||||
const offset = lol[i].offset;
|
|
||||||
|
|
||||||
if(startIndex === undefined && startOffset >= offset) {
|
|
||||||
startIndex = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(endOffset !== undefined) {
|
|
||||||
if(endOffset <= offset) {
|
|
||||||
endIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(startOffset > offset && (endOffset === undefined || endOffset < offset)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startIndex ??= 0;
|
|
||||||
lol.splice(startIndex, 0, {part: startPart, offset: entity.offset/* , priority */});
|
|
||||||
|
|
||||||
if(endOffset !== undefined) {
|
|
||||||
endIndex ??= startIndex;
|
|
||||||
++endIndex;
|
|
||||||
lol.splice(endIndex, 0, {part: endPart, offset: entity.offset + entity.length/* , priority */});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const pushPartsAfterSort: typeof lol = [];
|
|
||||||
const textLength = text.length;
|
const textLength = text.length;
|
||||||
for(let i = 0, length = entities.length; i < length; ++i) {
|
const length = entities.length;
|
||||||
let entity = entities[i];
|
let lastElement: HTMLElement | DocumentFragment;
|
||||||
|
for(; nasty.i < length; ++nasty.i) {
|
||||||
|
let entity = entities[nasty.i];
|
||||||
|
|
||||||
// * check whether text was sliced
|
// * check whether text was sliced
|
||||||
// TODO: consider about moving it to other function
|
// TODO: consider about moving it to other function
|
||||||
@ -546,13 +528,40 @@ namespace RichTextProcessor {
|
|||||||
entity.length = entity.offset + entity.length - textLength;
|
entity.length = entity.offset + entity.length - textLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(entity.length) {
|
||||||
|
nasty.lastEntity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nextEntity = entities[nasty.i + 1];
|
||||||
|
|
||||||
|
const startOffset = entity.offset;
|
||||||
|
const endOffset = startOffset + entity.length;
|
||||||
|
const endPartOffset = Math.min(endOffset, nextEntity?.offset ?? 0xFFFF);
|
||||||
|
const fullEntityText = text.slice(startOffset, endOffset);
|
||||||
|
const sliced = text.slice(startOffset, endPartOffset);
|
||||||
|
const partText = sliced;
|
||||||
|
|
||||||
|
if(nasty.usedLength < startOffset) {
|
||||||
|
(lastElement || fragment).append(text.slice(nasty.usedLength, startOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lastElement) {
|
||||||
|
lastElement = fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
nasty.usedLength = endPartOffset;
|
||||||
|
|
||||||
|
let element: HTMLElement,
|
||||||
|
property: 'textContent' | 'alt' = 'textContent',
|
||||||
|
usedText = false;
|
||||||
switch(entity._) {
|
switch(entity._) {
|
||||||
case 'messageEntityBold': {
|
case 'messageEntityBold': {
|
||||||
if(!options.noTextFormat) {
|
if(!options.noTextFormat) {
|
||||||
if(options.wrappingDraft) {
|
if(options.wrappingDraft) {
|
||||||
insertPart(entity, '<span style="font-weight: bold;">', '</span>');
|
element = document.createElement('span');
|
||||||
|
element.style.fontWeight = 'bold';
|
||||||
} else {
|
} else {
|
||||||
insertPart(entity, '<strong>', '</strong>');
|
element = document.createElement('strong');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,9 +571,10 @@ namespace RichTextProcessor {
|
|||||||
case 'messageEntityItalic': {
|
case 'messageEntityItalic': {
|
||||||
if(!options.noTextFormat) {
|
if(!options.noTextFormat) {
|
||||||
if(options.wrappingDraft) {
|
if(options.wrappingDraft) {
|
||||||
insertPart(entity, '<span style="font-style: italic;">', '</span>');
|
element = document.createElement('span');
|
||||||
|
element.style.fontStyle = 'italic';
|
||||||
} else {
|
} else {
|
||||||
insertPart(entity, '<em>', '</em>');
|
element = document.createElement('em');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,9 +584,10 @@ namespace RichTextProcessor {
|
|||||||
case 'messageEntityStrike': {
|
case 'messageEntityStrike': {
|
||||||
if(options.wrappingDraft) {
|
if(options.wrappingDraft) {
|
||||||
const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line';
|
const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line';
|
||||||
insertPart(entity, `<span style="${styleName}: line-through;">`, '</span>');
|
element = document.createElement('span');
|
||||||
|
element.style.cssText = `${styleName}: line-through;`;
|
||||||
} else if(!options.noTextFormat) {
|
} else if(!options.noTextFormat) {
|
||||||
insertPart(entity, '<del>', '</del>');
|
element = document.createElement('del');
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -585,54 +596,68 @@ namespace RichTextProcessor {
|
|||||||
case 'messageEntityUnderline': {
|
case 'messageEntityUnderline': {
|
||||||
if(options.wrappingDraft) {
|
if(options.wrappingDraft) {
|
||||||
const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line';
|
const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line';
|
||||||
insertPart(entity, `<span style="${styleName}: underline;">`, '</span>');
|
element = document.createElement('span');
|
||||||
|
element.style.cssText = `${styleName}: underline;`;
|
||||||
} else if(!options.noTextFormat) {
|
} else if(!options.noTextFormat) {
|
||||||
insertPart(entity, '<u>', '</u>');
|
element = document.createElement('u');
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'messageEntityPre':
|
||||||
case 'messageEntityCode': {
|
case 'messageEntityCode': {
|
||||||
if(options.wrappingDraft) {
|
if(options.wrappingDraft) {
|
||||||
insertPart(entity, '<span style="font-family: var(--font-monospace);">', '</span>');
|
element = document.createElement('span');
|
||||||
|
element.style.fontFamily = 'var(--font-monospace)';
|
||||||
} else if(!options.noTextFormat) {
|
} else if(!options.noTextFormat) {
|
||||||
insertPart(entity, '<code>', '</code>');
|
element = document.createElement('code');
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'messageEntityPre': {
|
// case 'messageEntityPre': {
|
||||||
if(options.wrappingDraft) {
|
// if(options.wrappingDraft) {
|
||||||
insertPart(entity, '<span style="font-family: var(--font-monospace);">', '</span>');
|
// element = document.createElement('span');
|
||||||
} else if(!options.noTextFormat) {
|
// element.style.fontFamily = 'var(--font-monospace)';
|
||||||
insertPart(entity, `<pre><code${entity.language ? ' class="language-' + encodeEntities(entity.language) + '"' : ''}>`, '</code></pre>');
|
// } else if(!options.noTextFormat) {
|
||||||
}
|
// element = document.createElement('pre');
|
||||||
|
// const inner = document.createElement('code');
|
||||||
|
// if(entity.language) {
|
||||||
|
// inner.className = 'language-' + entity.language;
|
||||||
|
// inner.textContent = entityText;
|
||||||
|
// usedText = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
case 'messageEntityHighlight': {
|
case 'messageEntityHighlight': {
|
||||||
insertPart(entity, '<i class="text-highlight">', '</i>');
|
element = document.createElement('i');
|
||||||
|
element.className = 'text-highlight';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'messageEntityBotCommand': {
|
case 'messageEntityBotCommand': {
|
||||||
// if(!(options.noLinks || options.noCommands || contextExternal)/* && !entity.unsafe */) {
|
// if(!(options.noLinks || options.noCommands || contextExternal)/* && !entity.unsafe */) {
|
||||||
if(!options.noLinks && passEntities[entity._]) {
|
if(!options.noLinks && passEntities[entity._]) {
|
||||||
const entityText = text.substr(entity.offset, entity.length);
|
let command = fullEntityText.slice(1);
|
||||||
let command = entityText.substr(1);
|
|
||||||
let bot: string | boolean;
|
let bot: string | boolean;
|
||||||
let atPos: number;
|
let atPos: number;
|
||||||
if((atPos = command.indexOf('@')) !== -1) {
|
if((atPos = command.indexOf('@')) !== -1) {
|
||||||
bot = command.substr(atPos + 1);
|
bot = command.slice(atPos + 1);
|
||||||
command = command.substr(0, atPos);
|
command = command.slice(0, atPos);
|
||||||
} else {
|
} else {
|
||||||
bot = options.fromBot;
|
bot = options.fromBot;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertPart(entity, `<a href="${encodeEntities('tg://bot_command?command=' + encodeURIComponent(command) + (bot ? '&bot=' + encodeURIComponent(bot) : ''))}" ${contextExternal ? '' : 'onclick="execBotCommand(this)"'}>`, `</a>`);
|
element = document.createElement('a');
|
||||||
|
(element as HTMLAnchorElement).href = encodeEntities('tg://bot_command?command=' + encodeURIComponent(command) + (bot ? '&bot=' + encodeURIComponent(bot) : ''));
|
||||||
|
if(!contextExternal) {
|
||||||
|
element.setAttribute('onclick', 'execBotCommand(this)');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -657,11 +682,15 @@ namespace RichTextProcessor {
|
|||||||
// if(isSupported) { // ! contenteditable="false" нужен для поля ввода, иначе там будет меняться шрифт в Safari, или же рендерить смайлик напрямую, без контейнера
|
// if(isSupported) { // ! contenteditable="false" нужен для поля ввода, иначе там будет меняться шрифт в Safari, или же рендерить смайлик напрямую, без контейнера
|
||||||
// insertPart(entity, '<span class="emoji">', '</span>');
|
// insertPart(entity, '<span class="emoji">', '</span>');
|
||||||
// } else {
|
// } else {
|
||||||
insertPart(entity, `<img src="assets/img/emoji/${entity.unicode}.png" alt="`, `" class="emoji">`);
|
element = document.createElement('img');
|
||||||
|
(element as HTMLImageElement).src = `assets/img/emoji/${entity.unicode}.png`;
|
||||||
|
property = 'alt';
|
||||||
|
element.className = 'emoji';
|
||||||
// }
|
// }
|
||||||
//} else if(options.mustWrapEmoji) {
|
//} else if(options.mustWrapEmoji) {
|
||||||
} else if(!options.wrappingDraft) {
|
} else if(!options.wrappingDraft) {
|
||||||
insertPart(entity, '<span class="emoji">', '</span>');
|
element = document.createElement('span');
|
||||||
|
element.className = 'emoji';
|
||||||
}/* else if(!IS_SAFARI) {
|
}/* else if(!IS_SAFARI) {
|
||||||
insertPart(entity, '<span class="emoji" contenteditable="false">', '</span>');
|
insertPart(entity, '<span class="emoji" contenteditable="false">', '</span>');
|
||||||
} */
|
} */
|
||||||
@ -673,32 +702,28 @@ namespace RichTextProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'messageEntityCaret': {
|
case 'messageEntityCaret': {
|
||||||
const html = '<span class="composer-sel"></span>';
|
element = document.createElement('span');
|
||||||
// const html = '<span class="composer-sel" contenteditable="false"></span>';
|
element.className = 'composer-sel';
|
||||||
// insertPart(entity, '<span class="composer-sel" contenteditable="true"></span>');
|
// const html = '<span class="composer-sel"></span>';
|
||||||
// insertPart(entity, '<span class="composer-sel"></span>');
|
// pushPartsAfterSort.push({part: html, offset: entity.offset});
|
||||||
pushPartsAfterSort.push({part: html, offset: entity.offset});
|
|
||||||
// insertPart(entity, html/* , undefined, 1 */);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* case 'messageEntityLinebreak': {
|
// /* case 'messageEntityLinebreak': {
|
||||||
if(options.noLinebreaks) {
|
// if(options.noLinebreaks) {
|
||||||
insertPart(entity, ' ');
|
// insertPart(entity, ' ');
|
||||||
} else {
|
// } else {
|
||||||
insertPart(entity, '<br/>');
|
// insertPart(entity, '<br/>');
|
||||||
}
|
// }
|
||||||
|
|
||||||
break;
|
// break;
|
||||||
} */
|
// } */
|
||||||
|
|
||||||
case 'messageEntityUrl':
|
case 'messageEntityUrl':
|
||||||
case 'messageEntityTextUrl': {
|
case 'messageEntityTextUrl': {
|
||||||
if(!(options.noLinks && !passEntities[entity._])) {
|
if(!(options.noLinks && !passEntities[entity._])) {
|
||||||
const entityText = text.substr(entity.offset, entity.length);
|
|
||||||
|
|
||||||
// let inner: string;
|
// let inner: string;
|
||||||
let url: string = (entity as MessageEntity.messageEntityTextUrl).url || entityText;
|
let url: string = (entity as MessageEntity.messageEntityTextUrl).url || fullEntityText;
|
||||||
let masked = false;
|
let masked = false;
|
||||||
let onclick: string;
|
let onclick: string;
|
||||||
|
|
||||||
@ -707,14 +732,13 @@ namespace RichTextProcessor {
|
|||||||
onclick = wrapped.onclick;
|
onclick = wrapped.onclick;
|
||||||
|
|
||||||
if(entity._ === 'messageEntityTextUrl') {
|
if(entity._ === 'messageEntityTextUrl') {
|
||||||
const nextEntity = entities[i + 1];
|
|
||||||
if(nextEntity?._ === 'messageEntityUrl' &&
|
if(nextEntity?._ === 'messageEntityUrl' &&
|
||||||
nextEntity.length === entity.length &&
|
nextEntity.length === entity.length &&
|
||||||
nextEntity.offset === entity.offset) {
|
nextEntity.offset === entity.offset) {
|
||||||
i++;
|
nasty.i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(url !== entityText) {
|
if(url !== fullEntityText) {
|
||||||
masked = true;
|
masked = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -734,10 +758,17 @@ namespace RichTextProcessor {
|
|||||||
? encodeEntities(url)
|
? encodeEntities(url)
|
||||||
: `javascript:electronHelpers.openExternal('${encodeEntities(url)}');`;
|
: `javascript:electronHelpers.openExternal('${encodeEntities(url)}');`;
|
||||||
|
|
||||||
const target = (currentContext || typeof electronHelpers !== 'undefined')
|
element = document.createElement('a');
|
||||||
? '' : ' target="_blank" rel="noopener noreferrer"';
|
element.className = 'anchor-url';
|
||||||
|
(element as HTMLAnchorElement).href = href;
|
||||||
|
|
||||||
insertPart(entity, `<a class="anchor-url" href="${href}"${target}${onclick ? `onclick="${onclick}(this)"` : ''}>`, '</a>');
|
if(!(currentContext || typeof electronHelpers !== 'undefined')) {
|
||||||
|
setBlankToAnchor(element as HTMLAnchorElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(onclick) {
|
||||||
|
element.setAttribute('onclick', onclick + '(this)');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -745,8 +776,9 @@ namespace RichTextProcessor {
|
|||||||
|
|
||||||
case 'messageEntityEmail': {
|
case 'messageEntityEmail': {
|
||||||
if(!options.noLinks) {
|
if(!options.noLinks) {
|
||||||
const entityText = text.substr(entity.offset, entity.length);
|
element = document.createElement('a');
|
||||||
insertPart(entity, `<a href="${encodeEntities('mailto:' + entityText)}" target="_blank" rel="noopener noreferrer">`, '</a>');
|
(element as HTMLAnchorElement).href = encodeEntities('mailto:' + fullEntityText);
|
||||||
|
setBlankToAnchor(element as HTMLAnchorElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -755,9 +787,15 @@ namespace RichTextProcessor {
|
|||||||
case 'messageEntityHashtag': {
|
case 'messageEntityHashtag': {
|
||||||
const contextUrl = !options.noLinks && siteHashtags[contextSite];
|
const contextUrl = !options.noLinks && siteHashtags[contextSite];
|
||||||
if(contextUrl) {
|
if(contextUrl) {
|
||||||
const entityText = text.substr(entity.offset, entity.length);
|
const hashtag = fullEntityText.slice(1);
|
||||||
const hashtag = entityText.substr(1);
|
element = document.createElement('a');
|
||||||
insertPart(entity, `<a class="anchor-hashtag" href="${contextUrl.replace('{1}', encodeURIComponent(hashtag))}"${contextExternal ? ' target="_blank" rel="noopener noreferrer"' : ' onclick="searchByHashtag(this)"'}>`, '</a>');
|
element.className = 'anchor-hashtag';
|
||||||
|
(element as HTMLAnchorElement).href = contextUrl.replace('{1}', encodeURIComponent(hashtag));
|
||||||
|
if(contextExternal) {
|
||||||
|
setBlankToAnchor(element as HTMLAnchorElement);
|
||||||
|
} else {
|
||||||
|
element.setAttribute('onclick', 'searchByHashtag(this)');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -765,7 +803,10 @@ namespace RichTextProcessor {
|
|||||||
|
|
||||||
case 'messageEntityMentionName': {
|
case 'messageEntityMentionName': {
|
||||||
if(!(options.noLinks && !passEntities[entity._])) {
|
if(!(options.noLinks && !passEntities[entity._])) {
|
||||||
insertPart(entity, `<a href="#/im?p=${encodeURIComponent(entity.user_id)}" class="follow" data-follow="${entity.user_id}">`, '</a>');
|
element = document.createElement('a');
|
||||||
|
(element as HTMLAnchorElement).href = `#/im?p=${encodeURIComponent(entity.user_id)}`;
|
||||||
|
element.className = 'follow';
|
||||||
|
element.dataset.follow = '' + entity.user_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -774,13 +815,18 @@ namespace RichTextProcessor {
|
|||||||
case 'messageEntityMention': {
|
case 'messageEntityMention': {
|
||||||
// const contextUrl = !options.noLinks && siteMentions[contextSite];
|
// const contextUrl = !options.noLinks && siteMentions[contextSite];
|
||||||
if(!options.noLinks) {
|
if(!options.noLinks) {
|
||||||
const entityText = text.substr(entity.offset, entity.length);
|
const username = fullEntityText.slice(1);
|
||||||
const username = entityText.substr(1);
|
|
||||||
|
|
||||||
const {url, onclick} = wrapUrl('t.me/' + username);
|
const {url, onclick} = wrapUrl('t.me/' + username);
|
||||||
|
|
||||||
|
element = document.createElement('a');
|
||||||
|
element.className = 'mention';
|
||||||
|
(element as HTMLAnchorElement).href = url;
|
||||||
|
if(onclick) {
|
||||||
|
element.setAttribute('onclick', `${onclick}(this)`);
|
||||||
|
}
|
||||||
|
|
||||||
// insertPart(entity, `<a class="mention" href="${contextUrl.replace('{1}', encodeURIComponent(username))}"${contextExternal ? ' target="_blank" rel="noopener noreferrer"' : ''}>`, '</a>');
|
// 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;
|
break;
|
||||||
@ -793,53 +839,63 @@ namespace RichTextProcessor {
|
|||||||
const after = text.slice(entity.offset + entity.length);
|
const after = text.slice(entity.offset + entity.length);
|
||||||
text = before + spoiler(spoilerBefore)/* '▚'.repeat(entity.length) */ + after;
|
text = before + spoiler(spoilerBefore)/* '▚'.repeat(entity.length) */ + after;
|
||||||
} else if(options.wrappingDraft) {
|
} else if(options.wrappingDraft) {
|
||||||
insertPart(entity, '<span style="font-family: spoiler;">', '</span>');
|
element = document.createElement('span');
|
||||||
|
element.style.fontFamily = 'spoiler';
|
||||||
} else {
|
} else {
|
||||||
insertPart(entity, '<span class="spoiler"><span class="spoiler-text">', '</span></span>');
|
const container = document.createElement('span');
|
||||||
|
container.className = 'spoiler';
|
||||||
|
element = document.createElement('span');
|
||||||
|
element.className = 'spoiler-text';
|
||||||
|
element.textContent = partText;
|
||||||
|
usedText = true;
|
||||||
|
container.append(element);
|
||||||
|
fragment.append(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// lol.sort((a, b) => (a.offset - b.offset) || (a.priority - b.priority));
|
if(element && !usedText) {
|
||||||
// lol.sort((a, b) => a.offset - b.offset); // have to sort because of nested entities
|
// @ts-ignore
|
||||||
|
element[property] = partText;
|
||||||
let partsLength = lol.length, pushPartsAfterSortLength = pushPartsAfterSort.length;
|
|
||||||
for(let i = 0; i < pushPartsAfterSortLength; ++i) {
|
|
||||||
const part = pushPartsAfterSort[i];
|
|
||||||
let insertAt = 0;
|
|
||||||
while(insertAt < partsLength) {
|
|
||||||
if(lol[insertAt++].offset >= part.offset) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lol.splice(insertAt, 0, part);
|
while(nextEntity && nextEntity.offset < (endOffset - 1)) {
|
||||||
}
|
++nasty.i;
|
||||||
|
|
||||||
partsLength += pushPartsAfterSortLength;
|
(element || fragment).append(wrapRichText(text, {
|
||||||
|
...options,
|
||||||
|
voodoo: true
|
||||||
|
}));
|
||||||
|
|
||||||
const arr: string[] = [];
|
nextEntity = entities[nasty.i + 1];
|
||||||
let usedLength = 0;
|
|
||||||
for(let i = 0; i < partsLength; ++i) {
|
|
||||||
const {part, offset} = lol[i];
|
|
||||||
if(offset > usedLength) {
|
|
||||||
const sliced = text.slice(usedLength, offset);
|
|
||||||
arr.push(options.noEncoding ? sliced : encodeEntities(sliced));
|
|
||||||
usedLength = offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arr.push(part);
|
if(!element?.parentElement) {
|
||||||
|
(lastElement || fragment).append(element ?? partText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(entity.length > partText.length && element) {
|
||||||
|
lastElement = element;
|
||||||
|
} else {
|
||||||
|
lastElement = fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(options.voodoo) {
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(usedLength < text.length) {
|
if(nasty.lastEntity) {
|
||||||
const sliced = text.slice(usedLength);
|
nasty.usedLength = nasty.lastEntity.offset + nasty.lastEntity.length;
|
||||||
arr.push(options.noEncoding ? sliced : encodeEntities(sliced));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return arr.join('');
|
if(nasty.usedLength < textLength) {
|
||||||
|
(lastElement || fragment).append(text.slice(nasty.usedLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fixEmoji(text: string, entities?: MessageEntity[]) {
|
export function fixEmoji(text: string, entities?: MessageEntity[]) {
|
||||||
@ -874,7 +930,7 @@ namespace RichTextProcessor {
|
|||||||
entities: MessageEntity[]
|
entities: MessageEntity[]
|
||||||
}> = {}) {
|
}> = {}) {
|
||||||
if(!text) {
|
if(!text) {
|
||||||
return '';
|
return wrapRichText('');
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapRichText(text, {
|
return wrapRichText(text, {
|
||||||
@ -941,11 +997,11 @@ namespace RichTextProcessor {
|
|||||||
noTextFormat: true,
|
noTextFormat: true,
|
||||||
noLinebreaks: true,
|
noLinebreaks: true,
|
||||||
noLinks: true
|
noLinks: true
|
||||||
});
|
}).textContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapEmojiText(text: string, isDraft = false) {
|
export function wrapEmojiText(text: string, isDraft = false) {
|
||||||
if(!text) return '';
|
if(!text) return wrapRichText('');
|
||||||
|
|
||||||
let entities = parseEntities(text).filter(e => e._ === 'messageEntityEmoji');
|
let entities = parseEntities(text).filter(e => e._ === 'messageEntityEmoji');
|
||||||
return wrapRichText(text, {entities, wrappingDraft: isDraft});
|
return wrapRichText(text, {entities, wrappingDraft: isDraft});
|
||||||
|
@ -40,6 +40,7 @@ import stateStorage from "../lib/stateStorage";
|
|||||||
import rootScope from "../lib/rootScope";
|
import rootScope from "../lib/rootScope";
|
||||||
import TelInputField from "../components/telInputField";
|
import TelInputField from "../components/telInputField";
|
||||||
import IS_EMOJI_SUPPORTED from "../environment/emojiSupport";
|
import IS_EMOJI_SUPPORTED from "../environment/emojiSupport";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
//import _countries from '../countries_pretty.json';
|
//import _countries from '../countries_pretty.json';
|
||||||
let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement;
|
let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement;
|
||||||
@ -118,10 +119,10 @@ let onFirstMount = () => {
|
|||||||
let wrapped = RichTextProcessor.wrapEmojiText(emoji);
|
let wrapped = RichTextProcessor.wrapEmojiText(emoji);
|
||||||
if(IS_EMOJI_SUPPORTED) {
|
if(IS_EMOJI_SUPPORTED) {
|
||||||
const spanEmoji = document.createElement('span');
|
const spanEmoji = document.createElement('span');
|
||||||
spanEmoji.innerHTML = wrapped;
|
setInnerHTML(spanEmoji, wrapped);
|
||||||
li.append(spanEmoji);
|
li.append(spanEmoji);
|
||||||
} else {
|
} else {
|
||||||
li.innerHTML = wrapped;
|
setInnerHTML(li, wrapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
const el = i18n(c.default_name as any);
|
const el = i18n(c.default_name as any);
|
||||||
|
@ -6,13 +6,9 @@
|
|||||||
{"name": "h", "type": "number"},
|
{"name": "h", "type": "number"},
|
||||||
{"name": "w", "type": "number"},
|
{"name": "w", "type": "number"},
|
||||||
{"name": "file_name", "type": "string"},
|
{"name": "file_name", "type": "string"},
|
||||||
{"name": "fileName", "type": "string"},
|
|
||||||
{"name": "file", "type": "File"},
|
{"name": "file", "type": "File"},
|
||||||
{"name": "duration", "type": "number"},
|
{"name": "duration", "type": "number"},
|
||||||
{"name": "audioTitle", "type": "string"},
|
|
||||||
{"name": "audioPerformer", "type": "string"},
|
|
||||||
{"name": "sticker", "type": "1 | 2 | 3"},
|
{"name": "sticker", "type": "1 | 2 | 3"},
|
||||||
{"name": "stickerEmoji", "type": "string"},
|
|
||||||
{"name": "stickerEmojiRaw", "type": "string"},
|
{"name": "stickerEmojiRaw", "type": "string"},
|
||||||
{"name": "stickerSetInput", "type": "InputStickerSet.inputStickerSetID"},
|
{"name": "stickerSetInput", "type": "InputStickerSet.inputStickerSetID"},
|
||||||
{"name": "stickerThumbConverted", "type": "true"},
|
{"name": "stickerThumbConverted", "type": "true"},
|
||||||
@ -149,7 +145,6 @@
|
|||||||
}, {
|
}, {
|
||||||
"predicate": "user",
|
"predicate": "user",
|
||||||
"params": [
|
"params": [
|
||||||
{"name": "initials", "type": "string"},
|
|
||||||
{"name": "sortName", "type": "string"}
|
{"name": "sortName", "type": "string"}
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
@ -163,26 +158,6 @@
|
|||||||
{"name": "rReply", "type": "string"},
|
{"name": "rReply", "type": "string"},
|
||||||
{"name": "rMessage", "type": "string"}
|
{"name": "rMessage", "type": "string"}
|
||||||
]
|
]
|
||||||
}, {
|
|
||||||
"predicate": "chat",
|
|
||||||
"params": [
|
|
||||||
{"name": "initials", "type": "string"}
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
"predicate": "chatForbidden",
|
|
||||||
"params": [
|
|
||||||
{"name": "initials", "type": "string"}
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
"predicate": "channel",
|
|
||||||
"params": [
|
|
||||||
{"name": "initials", "type": "string"}
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
"predicate": "channelForbidden",
|
|
||||||
"params": [
|
|
||||||
{"name": "initials", "type": "string"}
|
|
||||||
]
|
|
||||||
}, {
|
}, {
|
||||||
"predicate": "messageActionDiscussionStarted",
|
"predicate": "messageActionDiscussionStarted",
|
||||||
"params": [],
|
"params": [],
|
||||||
@ -317,12 +292,6 @@
|
|||||||
"params": [
|
"params": [
|
||||||
{"name": "checkedReference", "type": "boolean"}
|
{"name": "checkedReference", "type": "boolean"}
|
||||||
]
|
]
|
||||||
}, {
|
|
||||||
"predicate": "webPage",
|
|
||||||
"params": [
|
|
||||||
{"name": "rTitle", "type": "string"},
|
|
||||||
{"name": "rDescription", "type": "string"}
|
|
||||||
]
|
|
||||||
}, {
|
}, {
|
||||||
"predicate": "inputMediaContact",
|
"predicate": "inputMediaContact",
|
||||||
"params": [
|
"params": [
|
||||||
@ -331,8 +300,6 @@
|
|||||||
}, {
|
}, {
|
||||||
"predicate": "poll",
|
"predicate": "poll",
|
||||||
"params": [
|
"params": [
|
||||||
{"name": "rQuestion", "type": "string"},
|
|
||||||
{"name": "rReply", "type": "string"},
|
|
||||||
{"name": "chosenIndexes", "type": "number[]"}
|
{"name": "chosenIndexes", "type": "number[]"}
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
|
Loading…
Reference in New Issue
Block a user