Browse Source

Media aspecter container

Fix urls
Fix merging message entities
Decrease sticker size
master
morethanwords 3 years ago
parent
commit
1bb0f31026
  1. 2
      src/components/appMediaViewer.ts
  2. 12
      src/components/chat/bubbles.ts
  3. 6
      src/components/chat/markupTooltip.ts
  4. 44
      src/components/wrappers.ts
  5. 15
      src/helpers/mediaSizes.ts
  6. 38
      src/lib/appManagers/appPhotosManager.ts
  7. 80
      src/lib/richtextprocessor.ts
  8. 19
      src/scss/partials/_chatBubble.scss

2
src/components/appMediaViewer.ts

@ -956,7 +956,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -956,7 +956,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
// TODO: const maxHeight = mediaSizes.isMobile ? appPhotosManager.windowH : appPhotosManager.windowH - 100;
const maxHeight = appPhotosManager.windowH - 100;
let thumbPromise: Promise<any> = Promise.resolve();
const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true);
const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true).photoSize;
if(useContainerAsTarget) {
const cacheContext = appDownloadManager.getCacheContext(media, size.type);
let img: HTMLImageElement;

12
src/components/chat/bubbles.ts

@ -859,9 +859,11 @@ export default class ChatBubbles { @@ -859,9 +859,11 @@ export default class ChatBubbles {
str += '.attachment video, .attachment img';
}
const hasAspecter = !!this.bubbles[id].querySelector('.media-container-aspecter');
let elements = this.bubbles[id].querySelectorAll(str) as NodeListOf<HTMLElement>;
const parents: Set<HTMLElement> = new Set();
Array.from(elements).forEach((element: HTMLElement) => {
if(hasAspecter && !findUpClassName(element, 'media-container-aspecter')) return;
let albumItem = findUpClassName(element, 'album-item');
const parent = albumItem || element.parentElement;
if(parents.has(parent)) return;
@ -2330,6 +2332,7 @@ export default class ChatBubbles { @@ -2330,6 +2332,7 @@ export default class ChatBubbles {
if(size.w === size.h && quoteTextDiv.childElementCount) {
bubble.classList.add('is-square-photo');
isSquare = true;
this.appPhotosManager.setAttachmentSize(webpage.photo, preview, 80, 80, false);
} else if(size.h > size.w) {
bubble.classList.add('is-vertical-photo');
}
@ -2338,8 +2341,8 @@ export default class ChatBubbles { @@ -2338,8 +2341,8 @@ export default class ChatBubbles {
photo: webpage.photo,
message,
container: preview,
boxWidth: mediaSizes.active.webpage.width,
boxHeight: mediaSizes.active.webpage.height,
boxWidth: isSquare ? 0 : mediaSizes.active.webpage.width,
boxHeight: isSquare ? 0 : mediaSizes.active.webpage.height,
isOut,
lazyLoadQueue: this.lazyLoadQueue,
middleware: this.getMiddleware(),
@ -2372,8 +2375,9 @@ export default class ChatBubbles { @@ -2372,8 +2375,9 @@ export default class ChatBubbles {
bubble.classList.add('sticker-animated');
}
let size = bubble.classList.contains('emoji-big') ? 140 : 200;
this.appPhotosManager.setAttachmentSize(doc, attachmentDiv, size, size);
const sizes = mediaSizes.active;
const size = bubble.classList.contains('emoji-big') ? sizes.emojiSticker : (doc.animated ? sizes.animatedSticker : sizes.staticSticker);
this.appPhotosManager.setAttachmentSize(doc, attachmentDiv, size.width, size.height);
//let preloader = new ProgressivePreloader(attachmentDiv, false);
bubbleContainer.style.height = attachmentDiv.style.height;
bubbleContainer.style.width = attachmentDiv.style.width;

6
src/components/chat/markupTooltip.ts

@ -170,7 +170,11 @@ export default class MarkupTooltip { @@ -170,7 +170,11 @@ export default class MarkupTooltip {
private applyLink(e: Event) {
cancelEvent(e);
this.resetSelection();
this.appImManager.chat.input.applyMarkdown('link', this.linkInput.value);
let url = this.linkInput.value;
if(url && !RichTextProcessor.matchUrlProtocol(url)) {
url = 'https://' + url;
}
this.appImManager.chat.input.applyMarkdown('link', url);
setTimeout(() => {
this.hide();
}, 0);

44
src/components/wrappers.ts

@ -283,7 +283,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai @@ -283,7 +283,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
}
if(!video.parentElement && container) {
container.append(video);
(photoRes?.aspecter || container).append(video);
}
const cacheContext = appDownloadManager.getCacheContext(doc);
@ -669,7 +669,7 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT @@ -669,7 +669,7 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
}) {
if(!((photo as MyPhoto).sizes || (photo as MyDocument).thumbs)) {
if(boxWidth && boxHeight && !size && photo._ === 'document') {
size = appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message && message.message);
appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message);
}
return {
@ -681,7 +681,8 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT @@ -681,7 +681,8 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
thumb: null,
full: null
},
preloader: null
preloader: null,
aspecter: null
};
}
@ -690,7 +691,11 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT @@ -690,7 +691,11 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
if(boxHeight === undefined) boxHeight = mediaSizes.active.regular.height;
}
let loadThumbPromise: Promise<any>;
container.classList.add('media-container');
let aspecter = container;
let isFit = true;
let loadThumbPromise: Promise<any> = Promise.resolve();
let thumbImage: HTMLImageElement;
let image: HTMLImageElement;
// if(withTail) {
@ -699,15 +704,35 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT @@ -699,15 +704,35 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
image = new Image();
if(boxWidth && boxHeight && !size) { // !album
size = appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message && message.message);
const set = appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message);
size = set.photoSize;
isFit = set.isFit;
if(!isFit) {
aspecter = document.createElement('div');
aspecter.classList.add('media-container-aspecter');
aspecter.style.width = set.size.width + 'px';
aspecter.style.height = set.size.height + 'px';
const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, !noBlur, true);
if(gotThumb) {
loadThumbPromise = gotThumb.loadPromise;
const thumbImage = gotThumb.image; // local scope
thumbImage.classList.add('media-photo');
container.append(thumbImage);
}
container.classList.add('media-container-fitted');
container.append(aspecter);
}
}
const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, !noBlur);
if(gotThumb) {
loadThumbPromise = gotThumb.loadPromise;
loadThumbPromise = Promise.all([loadThumbPromise, gotThumb.loadPromise]);
thumbImage = gotThumb.image;
thumbImage.classList.add('media-photo');
container.append(thumbImage);
aspecter.append(thumbImage);
}
// }
@ -754,7 +779,7 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT @@ -754,7 +779,7 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
renderImageFromUrl(image, cacheContext.url, () => {
sequentialDom.mutateElement(container, () => {
container.append(image);
aspecter.append(image);
fastRaf(() => {
resolve();
@ -820,7 +845,8 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT @@ -820,7 +845,8 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
thumb: thumbImage,
full: image
},
preloader
preloader,
aspecter
};
}

15
src/helpers/mediaSizes.ts

@ -34,7 +34,10 @@ type MediaTypeSizes = { @@ -34,7 +34,10 @@ type MediaTypeSizes = {
regular: MediaSize,
webpage: MediaSize,
album: MediaSize,
esgSticker: MediaSize
esgSticker: MediaSize,
animatedSticker: MediaSize,
staticSticker: MediaSize,
emojiSticker: MediaSize
};
export enum ScreenSize {
@ -61,13 +64,19 @@ class MediaSizes extends EventListenerBase<{ @@ -61,13 +64,19 @@ class MediaSizes extends EventListenerBase<{
regular: makeMediaSize(270, 270),
webpage: makeMediaSize(270, 200),
album: makeMediaSize(270, 0),
esgSticker: makeMediaSize(68, 68)
esgSticker: makeMediaSize(68, 68),
animatedSticker: makeMediaSize(160, 160),
staticSticker: makeMediaSize(160, 160),
emojiSticker: makeMediaSize(112, 112)
},
desktop: {
regular: makeMediaSize(400, 320),
webpage: makeMediaSize(400, 320),
album: makeMediaSize(420, 0),
esgSticker: makeMediaSize(80, 80)
esgSticker: makeMediaSize(80, 80),
animatedSticker: makeMediaSize(200, 200),
staticSticker: makeMediaSize(200, 200),
emojiSticker: makeMediaSize(112, 112)
}
};

38
src/lib/appManagers/appPhotosManager.ts

@ -216,7 +216,7 @@ export class AppPhotosManager { @@ -216,7 +216,7 @@ export class AppPhotosManager {
return {image, loadPromise};
}
public setAttachmentSize(photo: MyPhoto | MyDocument, element: HTMLElement | SVGForeignObjectElement, boxWidth: number, boxHeight: number, noZoom = true, hasText?: boolean) {
public setAttachmentSize(photo: MyPhoto | MyDocument, element: HTMLElement | SVGForeignObjectElement, boxWidth: number, boxHeight: number, noZoom = true, message?: any) {
const photoSize = this.choosePhotoSize(photo, boxWidth, boxHeight);
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
@ -227,13 +227,29 @@ export class AppPhotosManager { @@ -227,13 +227,29 @@ export class AppPhotosManager {
size = makeMediaSize('w' in photoSize ? photoSize.w : 100, 'h' in photoSize ? photoSize.h : 100);
}
const boxSize = makeMediaSize(boxWidth, boxHeight);
let boxSize = makeMediaSize(boxWidth, boxHeight);
size = size.aspect(boxSize, noZoom);
boxSize = size = size.aspect(boxSize, noZoom);
// /* if(hasText) {
// w = Math.max(boxWidth, w);
// } */
let isFit = true;
if(photo._ === 'photo' || ['video', 'gif'].includes(photo.type)) {
if(boxSize.width < 200 && boxSize.height < 200) { // make at least one side this big
boxSize = size = size.aspectCovered(makeMediaSize(200, 200));
}
if(message && (message.message || message.media.webpage || message.replies)) { // make sure that bubble block is human-readable
if(boxSize.width < 320) {
boxSize = makeMediaSize(320, boxSize.height);
isFit = false;
}
}
if(isFit && boxSize.width < 120) { // if image is too narrow
boxSize = makeMediaSize(120, boxSize.height);
isFit = false;
}
}
// if(element instanceof SVGForeignObjectElement) {
// element.setAttributeNS(null, 'width', '' + w);
@ -241,16 +257,16 @@ export class AppPhotosManager { @@ -241,16 +257,16 @@ export class AppPhotosManager {
// //console.log('set dimensions to svg element:', element, w, h);
// } else {
element.style.width = size.width + 'px';
element.style.height = size.height + 'px';
element.style.width = boxSize.width + 'px';
element.style.height = boxSize.height + 'px';
// }
return photoSize;
return {photoSize, size, isFit};
}
public getStrippedThumbIfNeeded(photo: MyPhoto | MyDocument, useBlur: boolean): ReturnType<AppPhotosManager['getImageFromStrippedThumb']> {
public getStrippedThumbIfNeeded(photo: MyPhoto | MyDocument, useBlur: boolean, ignoreCache = false): ReturnType<AppPhotosManager['getImageFromStrippedThumb']> {
const cacheContext = appDownloadManager.getCacheContext(photo);
if(!cacheContext.downloaded || (photo as MyDocument).type === 'video' || (photo as MyDocument).type === 'gif') {
if(!cacheContext.downloaded || (['video', 'gif'] as MyDocument['type'][]).includes((photo as MyDocument).type) || ignoreCache) {
if(photo._ === 'document' && cacheContext.downloaded) {
return null;
}

80
src/lib/richtextprocessor.ts

@ -54,17 +54,19 @@ const alphaCharsRegExp = 'a-z' + @@ -54,17 +54,19 @@ const alphaCharsRegExp = 'a-z' +
const alphaNumericRegExp = '0-9\_' + alphaCharsRegExp;
const domainAddChars = '\u00b7';
// Based on Regular Expression for URL validation by Diego Perini
const urlRegExp = '((?:https?|ftp)://|mailto:)?' +
const urlAlphanumericRegExpPart = '[' + alphaCharsRegExp + '0-9]';
const urlProtocolRegExpPart = '((?:https?|ftp)://|mailto:)?';
const urlRegExp = urlProtocolRegExpPart +
// user:pass authentication
'(?:\\S{1,64}(?::\\S{0,64})?@)?' +
'(?:' + urlAlphanumericRegExpPart + '{1,64}(?::' + urlAlphanumericRegExpPart + '{0,64})?@)?' +
'(?:' +
// sindresorhus/ip-regexp
'(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){3}' +
'|' +
// host name
'[' + alphaCharsRegExp + '0-9][' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}' +
urlAlphanumericRegExpPart + '[' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}' +
// domain name
'(?:\\.[' + alphaCharsRegExp + '0-9][' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}){0,10}' +
'(?:\\.' + urlAlphanumericRegExpPart + '[' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}){0,10}' +
// TLD identifier
'(?:\\.(xn--[0-9a-z]{2,16}|[' + alphaCharsRegExp + ']{2,24}))' +
')' +
@ -72,9 +74,11 @@ const urlRegExp = '((?:https?|ftp)://|mailto:)?' + @@ -72,9 +74,11 @@ const urlRegExp = '((?:https?|ftp)://|mailto:)?' +
'(?::\\d{2,5})?' +
// resource path
'(?:/(?:\\S{0,255}[^\\s.;,(\\[\\]{}<>"\'])?)?';
const urlProtocolRegExp = new RegExp('^' + urlProtocolRegExpPart.slice(0, -1), 'i');
const urlAnyProtocolRegExp = /^((?:.+?):\/\/|mailto:)/;
const usernameRegExp = '[a-zA-Z\\d_]{5,32}';
const botCommandRegExp = '\\/([a-zA-Z\\d_]{1,32})(?:@(' + usernameRegExp + '))?(\\b|$)';
const fullRegExp = new RegExp('(^| )(@)(' + usernameRegExp + ')|(' + urlRegExp + ')|(\\n)|(' + emojiRegExp + ')|(^|[\\s\\(\\]])(#[' + alphaNumericRegExp + ']{2,64})|(^|\\s)' + botCommandRegExp, 'i')
const fullRegExp = new RegExp('(^| )(@)(' + usernameRegExp + ')|(' + urlRegExp + ')|(\\n)|(' + emojiRegExp + ')|(^|[\\s\\(\\]])(#[' + alphaNumericRegExp + ']{2,64})|(^|\\s)' + botCommandRegExp, 'i');
const emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
//const markdownTestRegExp = /[`_*@~]/;
const markdownRegExp = /(^|\s|\n)(````?)([\s\S]+?)(````?)([\s\n\.,:?!;]|$)|(^|\s|\x01)(`|~~|\*\*|__|_-_)([^\n]+?)\7([\x01\s\.,:?!;]|$)|@(\d+)\s*\((.+?)\)|(\[(.+?)\]\((.+?)\))/m;
@ -91,7 +95,7 @@ const siteMentions: {[siteName: string]: string} = { @@ -91,7 +95,7 @@ const siteMentions: {[siteName: string]: string} = {
Instagram: 'https://instagram.com/{1}/',
GitHub: 'https://github.com/{1}'
};
const markdownEntities: {[markdown: string]: any} = {
const markdownEntities: {[markdown: string]: MessageEntity['_']} = {
'`': 'messageEntityCode',
'``': 'messageEntityPre',
'**': 'messageEntityBold',
@ -100,6 +104,11 @@ const markdownEntities: {[markdown: string]: any} = { @@ -100,6 +104,11 @@ const markdownEntities: {[markdown: string]: any} = {
'_-_': 'messageEntityUnderline'
};
const passConflictingEntities: Set<MessageEntity['_']> = new Set();
for(let i in markdownEntities) {
passConflictingEntities.add(markdownEntities[i]);
}
namespace RichTextProcessor {
export const emojiSupported = navigator.userAgent.search(/OS X|iPhone|iPad|iOS/i) !== -1/* && false *//* || true */;
@ -120,11 +129,11 @@ namespace RichTextProcessor { @@ -120,11 +129,11 @@ namespace RichTextProcessor {
}
export function parseEntities(text: string) {
var match;
var raw = text, url;
let match: any;
let raw = text;
const entities: MessageEntity[] = [];
let matchIndex;
var rawOffset = 0;
let rawOffset = 0;
// var start = tsNow()
while((match = raw.match(fullRegExp))) {
matchIndex = rawOffset + match.index;
@ -145,19 +154,19 @@ namespace RichTextProcessor { @@ -145,19 +154,19 @@ namespace RichTextProcessor {
length: match[4].length
});
} else {
var url: any = false;
var protocol = match[5];
var tld = match[6];
var excluded = '';
let url: string;
let protocol = match[5];
const tld = match[6];
// let excluded = '';
if(tld) { // URL
if(!protocol && (tld.substr(0, 4) === 'xn--' || Config.TLD.indexOf(tld.toLowerCase()) !== -1)) {
protocol = 'http://';
}
if(protocol) {
var balanced = checkBrackets(match[4]);
if (balanced.length !== match[4].length) {
excluded = match[4].substring(balanced.length);
const balanced = checkBrackets(match[4]);
if(balanced.length !== match[4].length) {
// excluded = match[4].substring(balanced.length);
match[4] = balanced;
}
@ -167,7 +176,7 @@ namespace RichTextProcessor { @@ -167,7 +176,7 @@ namespace RichTextProcessor {
url = (match[5] ? '' : 'http://') + match[4];
}
if (url) {
if(url) {
entities.push({
_: 'messageEntityUrl',
offset: matchIndex,
@ -183,7 +192,7 @@ namespace RichTextProcessor { @@ -183,7 +192,7 @@ namespace RichTextProcessor {
});
} else if(match[8]) { // Emoji
//console.log('hit', match[8]);
let emojiCoords = getEmojiSpritesheetCoords(match[8]);
const emojiCoords = getEmojiSpritesheetCoords(match[8]);
if(emojiCoords) {
entities.push({
_: 'messageEntityEmoji',
@ -233,7 +242,7 @@ namespace RichTextProcessor { @@ -233,7 +242,7 @@ namespace RichTextProcessor {
const entities: MessageEntity[] = [];
let pushedEntity = false;
const pushEntity = (entity: MessageEntity) => !findSameEntity(currentEntities, entity) ? (entities.push(entity), pushedEntity = true) : pushedEntity = false;
const pushEntity = (entity: MessageEntity) => !findConflictingEntity(currentEntities, entity) ? (entities.push(entity), pushedEntity = true) : pushedEntity = false;
let raw = text;
let match;
@ -273,7 +282,7 @@ namespace RichTextProcessor { @@ -273,7 +282,7 @@ namespace RichTextProcessor {
const isSOH = match[6] === '\x01';
entity = {
_: markdownEntities[match[7]],
_: markdownEntities[match[7]] as (MessageEntity.messageEntityBold | MessageEntity.messageEntityCode | MessageEntity.messageEntityItalic)['_'],
//offset: matchIndex + match[6].length,
offset: matchIndex + (isSOH ? 0 : match[6].length),
length: text.length
@ -341,17 +350,25 @@ namespace RichTextProcessor { @@ -341,17 +350,25 @@ namespace RichTextProcessor {
return newText;
}
export function findSameEntity(currentEntities: MessageEntity[], newEntity: MessageEntity) {
export function findConflictingEntity(currentEntities: MessageEntity[], newEntity: MessageEntity) {
return currentEntities.find(currentEntity => {
return newEntity._ === currentEntity._ &&
newEntity.offset >= currentEntity.offset &&
const isConflictingTypes = newEntity._ === currentEntity._ ||
(!passConflictingEntities.has(newEntity._) && !passConflictingEntities.has(currentEntity._));
if(!isConflictingTypes) {
return false;
}
const isConflictingOffset = newEntity.offset >= currentEntity.offset &&
(newEntity.length + newEntity.offset) <= (currentEntity.length + currentEntity.offset);
return isConflictingOffset;
});
}
export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[]) {
const filtered = newEntities.filter(e => {
return !findSameEntity(currentEntities, e);
return !findConflictingEntity(currentEntities, e);
});
currentEntities.push(...filtered);
@ -536,7 +553,7 @@ namespace RichTextProcessor { @@ -536,7 +553,7 @@ namespace RichTextProcessor {
if(!(options.noLinks && !passEntities[entity._])) {
const entityText = text.substr(entity.offset, entity.length);
let inner: string;
// let inner: string;
let url: string;
let masked = false;
if(entity._ === 'messageEntityTextUrl') {
@ -548,6 +565,9 @@ namespace RichTextProcessor { @@ -548,6 +565,9 @@ namespace RichTextProcessor {
nextEntity.length === entity.length &&
nextEntity.offset === entity.offset) {
i++;
}
if(url !== entityText) {
masked = true;
}
} else {
@ -721,7 +741,7 @@ namespace RichTextProcessor { @@ -721,7 +741,7 @@ namespace RichTextProcessor {
}
export function wrapUrl(url: string, unsafe?: number | boolean): string {
if(!url.match(/^https?:\/\//i)) {
if(!matchUrlProtocol(url)) {
url = 'https://' + url;
}
@ -729,7 +749,7 @@ namespace RichTextProcessor { @@ -729,7 +749,7 @@ namespace RichTextProcessor {
let telescoPeMatch;
/* if(unsafe === 2) {
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
} else */if((tgMeMatch = url.match(/^https?:\/\/t(?:elegram)?\.me\/(.+)/))) {
} else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) {
const fullPath = tgMeMatch[1];
const path = fullPath.split('/');
switch(path[0]) {
@ -771,7 +791,7 @@ namespace RichTextProcessor { @@ -771,7 +791,7 @@ namespace RichTextProcessor {
break;
}
} else if((telescoPeMatch = url.match(/^https?:\/\/telesco\.pe\/([^/?]+)\/(\d+)/))) {
} else if((telescoPeMatch = url.match(/^(?:https?:\/\/)?telesco\.pe\/([^/?]+)\/(\d+)/))) {
url = 'tg://resolve?domain=' + telescoPeMatch[1] + '&post=' + telescoPeMatch[2];
}/* else if(unsafe) {
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
@ -779,6 +799,10 @@ namespace RichTextProcessor { @@ -779,6 +799,10 @@ namespace RichTextProcessor {
return url;
}
export function matchUrlProtocol(text: string) {
return !text ? null : text.match(urlAnyProtocolRegExp);
}
export function matchUrl(text: string) {
return !text ? null : text.match(urlRegExp);

19
src/scss/partials/_chatBubble.scss

@ -604,6 +604,21 @@ $bubble-margin: .25rem; @@ -604,6 +604,21 @@ $bubble-margin: .25rem;
}
}
.media-container {
&-aspecter {
position: relative;
margin: 0 auto;
}
&-fitted {
background-color: transparent !important;
.thumbnail {
opacity: .8;
}
}
}
.preloader-container {
z-index: 2;
}
@ -798,11 +813,11 @@ $bubble-margin: .25rem; @@ -798,11 +813,11 @@ $bubble-margin: .25rem;
}
}
&.is-vertical-photo {
/* &.is-vertical-photo {
.bubble-content {
width: fit-content;
}
}
} */
.reply {
padding: 4px;

Loading…
Cancel
Save