Media aspecter container
Fix urls Fix merging message entities Decrease sticker size
This commit is contained in:
parent
0e5b5c47d1
commit
1bb0f31026
@ -956,7 +956,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
|||||||
// TODO: const maxHeight = mediaSizes.isMobile ? appPhotosManager.windowH : appPhotosManager.windowH - 100;
|
// TODO: const maxHeight = mediaSizes.isMobile ? appPhotosManager.windowH : appPhotosManager.windowH - 100;
|
||||||
const maxHeight = appPhotosManager.windowH - 100;
|
const maxHeight = appPhotosManager.windowH - 100;
|
||||||
let thumbPromise: Promise<any> = Promise.resolve();
|
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) {
|
if(useContainerAsTarget) {
|
||||||
const cacheContext = appDownloadManager.getCacheContext(media, size.type);
|
const cacheContext = appDownloadManager.getCacheContext(media, size.type);
|
||||||
let img: HTMLImageElement;
|
let img: HTMLImageElement;
|
||||||
|
@ -859,9 +859,11 @@ export default class ChatBubbles {
|
|||||||
str += '.attachment video, .attachment img';
|
str += '.attachment video, .attachment img';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasAspecter = !!this.bubbles[id].querySelector('.media-container-aspecter');
|
||||||
let elements = this.bubbles[id].querySelectorAll(str) as NodeListOf<HTMLElement>;
|
let elements = this.bubbles[id].querySelectorAll(str) as NodeListOf<HTMLElement>;
|
||||||
const parents: Set<HTMLElement> = new Set();
|
const parents: Set<HTMLElement> = new Set();
|
||||||
Array.from(elements).forEach((element: HTMLElement) => {
|
Array.from(elements).forEach((element: HTMLElement) => {
|
||||||
|
if(hasAspecter && !findUpClassName(element, 'media-container-aspecter')) return;
|
||||||
let albumItem = findUpClassName(element, 'album-item');
|
let albumItem = findUpClassName(element, 'album-item');
|
||||||
const parent = albumItem || element.parentElement;
|
const parent = albumItem || element.parentElement;
|
||||||
if(parents.has(parent)) return;
|
if(parents.has(parent)) return;
|
||||||
@ -2330,6 +2332,7 @@ export default class ChatBubbles {
|
|||||||
if(size.w === size.h && quoteTextDiv.childElementCount) {
|
if(size.w === size.h && quoteTextDiv.childElementCount) {
|
||||||
bubble.classList.add('is-square-photo');
|
bubble.classList.add('is-square-photo');
|
||||||
isSquare = true;
|
isSquare = true;
|
||||||
|
this.appPhotosManager.setAttachmentSize(webpage.photo, preview, 80, 80, false);
|
||||||
} else if(size.h > size.w) {
|
} else if(size.h > size.w) {
|
||||||
bubble.classList.add('is-vertical-photo');
|
bubble.classList.add('is-vertical-photo');
|
||||||
}
|
}
|
||||||
@ -2338,8 +2341,8 @@ export default class ChatBubbles {
|
|||||||
photo: webpage.photo,
|
photo: webpage.photo,
|
||||||
message,
|
message,
|
||||||
container: preview,
|
container: preview,
|
||||||
boxWidth: mediaSizes.active.webpage.width,
|
boxWidth: isSquare ? 0 : mediaSizes.active.webpage.width,
|
||||||
boxHeight: mediaSizes.active.webpage.height,
|
boxHeight: isSquare ? 0 : mediaSizes.active.webpage.height,
|
||||||
isOut,
|
isOut,
|
||||||
lazyLoadQueue: this.lazyLoadQueue,
|
lazyLoadQueue: this.lazyLoadQueue,
|
||||||
middleware: this.getMiddleware(),
|
middleware: this.getMiddleware(),
|
||||||
@ -2372,8 +2375,9 @@ export default class ChatBubbles {
|
|||||||
bubble.classList.add('sticker-animated');
|
bubble.classList.add('sticker-animated');
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = bubble.classList.contains('emoji-big') ? 140 : 200;
|
const sizes = mediaSizes.active;
|
||||||
this.appPhotosManager.setAttachmentSize(doc, attachmentDiv, size, size);
|
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);
|
//let preloader = new ProgressivePreloader(attachmentDiv, false);
|
||||||
bubbleContainer.style.height = attachmentDiv.style.height;
|
bubbleContainer.style.height = attachmentDiv.style.height;
|
||||||
bubbleContainer.style.width = attachmentDiv.style.width;
|
bubbleContainer.style.width = attachmentDiv.style.width;
|
||||||
|
@ -170,7 +170,11 @@ export default class MarkupTooltip {
|
|||||||
private applyLink(e: Event) {
|
private applyLink(e: Event) {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
this.resetSelection();
|
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(() => {
|
setTimeout(() => {
|
||||||
this.hide();
|
this.hide();
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -283,7 +283,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!video.parentElement && container) {
|
if(!video.parentElement && container) {
|
||||||
container.append(video);
|
(photoRes?.aspecter || container).append(video);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheContext = appDownloadManager.getCacheContext(doc);
|
const cacheContext = appDownloadManager.getCacheContext(doc);
|
||||||
@ -669,7 +669,7 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
|
|||||||
}) {
|
}) {
|
||||||
if(!((photo as MyPhoto).sizes || (photo as MyDocument).thumbs)) {
|
if(!((photo as MyPhoto).sizes || (photo as MyDocument).thumbs)) {
|
||||||
if(boxWidth && boxHeight && !size && photo._ === 'document') {
|
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 {
|
return {
|
||||||
@ -681,7 +681,8 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
|
|||||||
thumb: null,
|
thumb: null,
|
||||||
full: null
|
full: null
|
||||||
},
|
},
|
||||||
preloader: null
|
preloader: null,
|
||||||
|
aspecter: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,7 +691,11 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
|
|||||||
if(boxHeight === undefined) boxHeight = mediaSizes.active.regular.height;
|
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 thumbImage: HTMLImageElement;
|
||||||
let image: HTMLImageElement;
|
let image: HTMLImageElement;
|
||||||
// if(withTail) {
|
// if(withTail) {
|
||||||
@ -699,15 +704,35 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
|
|||||||
image = new Image();
|
image = new Image();
|
||||||
|
|
||||||
if(boxWidth && boxHeight && !size) { // !album
|
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);
|
const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, !noBlur);
|
||||||
if(gotThumb) {
|
if(gotThumb) {
|
||||||
loadThumbPromise = gotThumb.loadPromise;
|
loadThumbPromise = Promise.all([loadThumbPromise, gotThumb.loadPromise]);
|
||||||
thumbImage = gotThumb.image;
|
thumbImage = gotThumb.image;
|
||||||
thumbImage.classList.add('media-photo');
|
thumbImage.classList.add('media-photo');
|
||||||
container.append(thumbImage);
|
aspecter.append(thumbImage);
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@ -754,7 +779,7 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
|
|||||||
|
|
||||||
renderImageFromUrl(image, cacheContext.url, () => {
|
renderImageFromUrl(image, cacheContext.url, () => {
|
||||||
sequentialDom.mutateElement(container, () => {
|
sequentialDom.mutateElement(container, () => {
|
||||||
container.append(image);
|
aspecter.append(image);
|
||||||
|
|
||||||
fastRaf(() => {
|
fastRaf(() => {
|
||||||
resolve();
|
resolve();
|
||||||
@ -820,7 +845,8 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT
|
|||||||
thumb: thumbImage,
|
thumb: thumbImage,
|
||||||
full: image
|
full: image
|
||||||
},
|
},
|
||||||
preloader
|
preloader,
|
||||||
|
aspecter
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,10 @@ type MediaTypeSizes = {
|
|||||||
regular: MediaSize,
|
regular: MediaSize,
|
||||||
webpage: MediaSize,
|
webpage: MediaSize,
|
||||||
album: MediaSize,
|
album: MediaSize,
|
||||||
esgSticker: MediaSize
|
esgSticker: MediaSize,
|
||||||
|
animatedSticker: MediaSize,
|
||||||
|
staticSticker: MediaSize,
|
||||||
|
emojiSticker: MediaSize
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum ScreenSize {
|
export enum ScreenSize {
|
||||||
@ -61,13 +64,19 @@ class MediaSizes extends EventListenerBase<{
|
|||||||
regular: makeMediaSize(270, 270),
|
regular: makeMediaSize(270, 270),
|
||||||
webpage: makeMediaSize(270, 200),
|
webpage: makeMediaSize(270, 200),
|
||||||
album: makeMediaSize(270, 0),
|
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: {
|
desktop: {
|
||||||
regular: makeMediaSize(400, 320),
|
regular: makeMediaSize(400, 320),
|
||||||
webpage: makeMediaSize(400, 320),
|
webpage: makeMediaSize(400, 320),
|
||||||
album: makeMediaSize(420, 0),
|
album: makeMediaSize(420, 0),
|
||||||
esgSticker: makeMediaSize(80, 80)
|
esgSticker: makeMediaSize(80, 80),
|
||||||
|
animatedSticker: makeMediaSize(200, 200),
|
||||||
|
staticSticker: makeMediaSize(200, 200),
|
||||||
|
emojiSticker: makeMediaSize(112, 112)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ export class AppPhotosManager {
|
|||||||
return {image, loadPromise};
|
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);
|
const photoSize = this.choosePhotoSize(photo, boxWidth, boxHeight);
|
||||||
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
|
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
|
||||||
|
|
||||||
@ -227,13 +227,29 @@ export class AppPhotosManager {
|
|||||||
size = makeMediaSize('w' in photoSize ? photoSize.w : 100, 'h' in photoSize ? photoSize.h : 100);
|
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) {
|
let isFit = true;
|
||||||
// w = Math.max(boxWidth, w);
|
|
||||||
// } */
|
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) {
|
// if(element instanceof SVGForeignObjectElement) {
|
||||||
// element.setAttributeNS(null, 'width', '' + w);
|
// element.setAttributeNS(null, 'width', '' + w);
|
||||||
@ -241,16 +257,16 @@ export class AppPhotosManager {
|
|||||||
|
|
||||||
// //console.log('set dimensions to svg element:', element, w, h);
|
// //console.log('set dimensions to svg element:', element, w, h);
|
||||||
// } else {
|
// } else {
|
||||||
element.style.width = size.width + 'px';
|
element.style.width = boxSize.width + 'px';
|
||||||
element.style.height = size.height + '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);
|
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) {
|
if(photo._ === 'document' && cacheContext.downloaded) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -54,17 +54,19 @@ const alphaCharsRegExp = 'a-z' +
|
|||||||
const alphaNumericRegExp = '0-9\_' + alphaCharsRegExp;
|
const alphaNumericRegExp = '0-9\_' + alphaCharsRegExp;
|
||||||
const domainAddChars = '\u00b7';
|
const domainAddChars = '\u00b7';
|
||||||
// Based on Regular Expression for URL validation by Diego Perini
|
// 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
|
// user:pass authentication
|
||||||
'(?:\\S{1,64}(?::\\S{0,64})?@)?' +
|
'(?:' + urlAlphanumericRegExpPart + '{1,64}(?::' + urlAlphanumericRegExpPart + '{0,64})?@)?' +
|
||||||
'(?:' +
|
'(?:' +
|
||||||
// sindresorhus/ip-regexp
|
// 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}' +
|
'(?: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
|
// host name
|
||||||
'[' + alphaCharsRegExp + '0-9][' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}' +
|
urlAlphanumericRegExpPart + '[' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}' +
|
||||||
// domain name
|
// domain name
|
||||||
'(?:\\.[' + alphaCharsRegExp + '0-9][' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}){0,10}' +
|
'(?:\\.' + urlAlphanumericRegExpPart + '[' + alphaCharsRegExp + domainAddChars + '0-9\-]{0,64}){0,10}' +
|
||||||
// TLD identifier
|
// TLD identifier
|
||||||
'(?:\\.(xn--[0-9a-z]{2,16}|[' + alphaCharsRegExp + ']{2,24}))' +
|
'(?:\\.(xn--[0-9a-z]{2,16}|[' + alphaCharsRegExp + ']{2,24}))' +
|
||||||
')' +
|
')' +
|
||||||
@ -72,9 +74,11 @@ const urlRegExp = '((?:https?|ftp)://|mailto:)?' +
|
|||||||
'(?::\\d{2,5})?' +
|
'(?::\\d{2,5})?' +
|
||||||
// resource path
|
// resource path
|
||||||
'(?:/(?:\\S{0,255}[^\\s.;,(\\[\\]{}<>"\'])?)?';
|
'(?:/(?:\\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 usernameRegExp = '[a-zA-Z\\d_]{5,32}';
|
||||||
const botCommandRegExp = '\\/([a-zA-Z\\d_]{1,32})(?:@(' + usernameRegExp + '))?(\\b|$)';
|
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 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 markdownTestRegExp = /[`_*@~]/;
|
||||||
const markdownRegExp = /(^|\s|\n)(````?)([\s\S]+?)(````?)([\s\n\.,:?!;]|$)|(^|\s|\x01)(`|~~|\*\*|__|_-_)([^\n]+?)\7([\x01\s\.,:?!;]|$)|@(\d+)\s*\((.+?)\)|(\[(.+?)\]\((.+?)\))/m;
|
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} = {
|
|||||||
Instagram: 'https://instagram.com/{1}/',
|
Instagram: 'https://instagram.com/{1}/',
|
||||||
GitHub: 'https://github.com/{1}'
|
GitHub: 'https://github.com/{1}'
|
||||||
};
|
};
|
||||||
const markdownEntities: {[markdown: string]: any} = {
|
const markdownEntities: {[markdown: string]: MessageEntity['_']} = {
|
||||||
'`': 'messageEntityCode',
|
'`': 'messageEntityCode',
|
||||||
'``': 'messageEntityPre',
|
'``': 'messageEntityPre',
|
||||||
'**': 'messageEntityBold',
|
'**': 'messageEntityBold',
|
||||||
@ -100,6 +104,11 @@ const markdownEntities: {[markdown: string]: any} = {
|
|||||||
'_-_': 'messageEntityUnderline'
|
'_-_': 'messageEntityUnderline'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const passConflictingEntities: Set<MessageEntity['_']> = new Set();
|
||||||
|
for(let i in markdownEntities) {
|
||||||
|
passConflictingEntities.add(markdownEntities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
namespace RichTextProcessor {
|
namespace RichTextProcessor {
|
||||||
export const emojiSupported = navigator.userAgent.search(/OS X|iPhone|iPad|iOS/i) !== -1/* && false *//* || true */;
|
export const emojiSupported = navigator.userAgent.search(/OS X|iPhone|iPad|iOS/i) !== -1/* && false *//* || true */;
|
||||||
|
|
||||||
@ -120,11 +129,11 @@ namespace RichTextProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseEntities(text: string) {
|
export function parseEntities(text: string) {
|
||||||
var match;
|
let match: any;
|
||||||
var raw = text, url;
|
let raw = text;
|
||||||
const entities: MessageEntity[] = [];
|
const entities: MessageEntity[] = [];
|
||||||
let matchIndex;
|
let matchIndex;
|
||||||
var rawOffset = 0;
|
let rawOffset = 0;
|
||||||
// var start = tsNow()
|
// var start = tsNow()
|
||||||
while((match = raw.match(fullRegExp))) {
|
while((match = raw.match(fullRegExp))) {
|
||||||
matchIndex = rawOffset + match.index;
|
matchIndex = rawOffset + match.index;
|
||||||
@ -145,19 +154,19 @@ namespace RichTextProcessor {
|
|||||||
length: match[4].length
|
length: match[4].length
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var url: any = false;
|
let url: string;
|
||||||
var protocol = match[5];
|
let protocol = match[5];
|
||||||
var tld = match[6];
|
const tld = match[6];
|
||||||
var excluded = '';
|
// let excluded = '';
|
||||||
if(tld) { // URL
|
if(tld) { // URL
|
||||||
if(!protocol && (tld.substr(0, 4) === 'xn--' || Config.TLD.indexOf(tld.toLowerCase()) !== -1)) {
|
if(!protocol && (tld.substr(0, 4) === 'xn--' || Config.TLD.indexOf(tld.toLowerCase()) !== -1)) {
|
||||||
protocol = 'http://';
|
protocol = 'http://';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(protocol) {
|
if(protocol) {
|
||||||
var balanced = checkBrackets(match[4]);
|
const balanced = checkBrackets(match[4]);
|
||||||
if (balanced.length !== match[4].length) {
|
if(balanced.length !== match[4].length) {
|
||||||
excluded = match[4].substring(balanced.length);
|
// excluded = match[4].substring(balanced.length);
|
||||||
match[4] = balanced;
|
match[4] = balanced;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +176,7 @@ namespace RichTextProcessor {
|
|||||||
url = (match[5] ? '' : 'http://') + match[4];
|
url = (match[5] ? '' : 'http://') + match[4];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url) {
|
if(url) {
|
||||||
entities.push({
|
entities.push({
|
||||||
_: 'messageEntityUrl',
|
_: 'messageEntityUrl',
|
||||||
offset: matchIndex,
|
offset: matchIndex,
|
||||||
@ -183,7 +192,7 @@ namespace RichTextProcessor {
|
|||||||
});
|
});
|
||||||
} else if(match[8]) { // Emoji
|
} else if(match[8]) { // Emoji
|
||||||
//console.log('hit', match[8]);
|
//console.log('hit', match[8]);
|
||||||
let emojiCoords = getEmojiSpritesheetCoords(match[8]);
|
const emojiCoords = getEmojiSpritesheetCoords(match[8]);
|
||||||
if(emojiCoords) {
|
if(emojiCoords) {
|
||||||
entities.push({
|
entities.push({
|
||||||
_: 'messageEntityEmoji',
|
_: 'messageEntityEmoji',
|
||||||
@ -233,7 +242,7 @@ namespace RichTextProcessor {
|
|||||||
|
|
||||||
const entities: MessageEntity[] = [];
|
const entities: MessageEntity[] = [];
|
||||||
let pushedEntity = false;
|
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 raw = text;
|
||||||
let match;
|
let match;
|
||||||
@ -273,7 +282,7 @@ namespace RichTextProcessor {
|
|||||||
const isSOH = match[6] === '\x01';
|
const isSOH = match[6] === '\x01';
|
||||||
|
|
||||||
entity = {
|
entity = {
|
||||||
_: markdownEntities[match[7]],
|
_: markdownEntities[match[7]] as (MessageEntity.messageEntityBold | MessageEntity.messageEntityCode | MessageEntity.messageEntityItalic)['_'],
|
||||||
//offset: matchIndex + match[6].length,
|
//offset: matchIndex + match[6].length,
|
||||||
offset: matchIndex + (isSOH ? 0 : match[6].length),
|
offset: matchIndex + (isSOH ? 0 : match[6].length),
|
||||||
length: text.length
|
length: text.length
|
||||||
@ -341,17 +350,25 @@ namespace RichTextProcessor {
|
|||||||
return newText;
|
return newText;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findSameEntity(currentEntities: MessageEntity[], newEntity: MessageEntity) {
|
export function findConflictingEntity(currentEntities: MessageEntity[], newEntity: MessageEntity) {
|
||||||
return currentEntities.find(currentEntity => {
|
return currentEntities.find(currentEntity => {
|
||||||
return newEntity._ === currentEntity._ &&
|
const isConflictingTypes = newEntity._ === currentEntity._ ||
|
||||||
newEntity.offset >= currentEntity.offset &&
|
(!passConflictingEntities.has(newEntity._) && !passConflictingEntities.has(currentEntity._));
|
||||||
|
|
||||||
|
if(!isConflictingTypes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isConflictingOffset = newEntity.offset >= currentEntity.offset &&
|
||||||
(newEntity.length + newEntity.offset) <= (currentEntity.length + currentEntity.offset);
|
(newEntity.length + newEntity.offset) <= (currentEntity.length + currentEntity.offset);
|
||||||
|
|
||||||
|
return isConflictingOffset;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[]) {
|
export function mergeEntities(currentEntities: MessageEntity[], newEntities: MessageEntity[]) {
|
||||||
const filtered = newEntities.filter(e => {
|
const filtered = newEntities.filter(e => {
|
||||||
return !findSameEntity(currentEntities, e);
|
return !findConflictingEntity(currentEntities, e);
|
||||||
});
|
});
|
||||||
|
|
||||||
currentEntities.push(...filtered);
|
currentEntities.push(...filtered);
|
||||||
@ -536,7 +553,7 @@ namespace RichTextProcessor {
|
|||||||
if(!(options.noLinks && !passEntities[entity._])) {
|
if(!(options.noLinks && !passEntities[entity._])) {
|
||||||
const entityText = text.substr(entity.offset, entity.length);
|
const entityText = text.substr(entity.offset, entity.length);
|
||||||
|
|
||||||
let inner: string;
|
// let inner: string;
|
||||||
let url: string;
|
let url: string;
|
||||||
let masked = false;
|
let masked = false;
|
||||||
if(entity._ === 'messageEntityTextUrl') {
|
if(entity._ === 'messageEntityTextUrl') {
|
||||||
@ -548,6 +565,9 @@ namespace RichTextProcessor {
|
|||||||
nextEntity.length === entity.length &&
|
nextEntity.length === entity.length &&
|
||||||
nextEntity.offset === entity.offset) {
|
nextEntity.offset === entity.offset) {
|
||||||
i++;
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(url !== entityText) {
|
||||||
masked = true;
|
masked = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -721,7 +741,7 @@ namespace RichTextProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function wrapUrl(url: string, unsafe?: number | boolean): string {
|
export function wrapUrl(url: string, unsafe?: number | boolean): string {
|
||||||
if(!url.match(/^https?:\/\//i)) {
|
if(!matchUrlProtocol(url)) {
|
||||||
url = 'https://' + url;
|
url = 'https://' + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,7 +749,7 @@ namespace RichTextProcessor {
|
|||||||
let telescoPeMatch;
|
let telescoPeMatch;
|
||||||
/* if(unsafe === 2) {
|
/* if(unsafe === 2) {
|
||||||
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
|
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
|
||||||
} else */if((tgMeMatch = url.match(/^https?:\/\/t(?:elegram)?\.me\/(.+)/))) {
|
} else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) {
|
||||||
const fullPath = tgMeMatch[1];
|
const fullPath = tgMeMatch[1];
|
||||||
const path = fullPath.split('/');
|
const path = fullPath.split('/');
|
||||||
switch(path[0]) {
|
switch(path[0]) {
|
||||||
@ -771,7 +791,7 @@ namespace RichTextProcessor {
|
|||||||
|
|
||||||
break;
|
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];
|
url = 'tg://resolve?domain=' + telescoPeMatch[1] + '&post=' + telescoPeMatch[2];
|
||||||
}/* else if(unsafe) {
|
}/* else if(unsafe) {
|
||||||
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
|
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
|
||||||
@ -780,6 +800,10 @@ namespace RichTextProcessor {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function matchUrlProtocol(text: string) {
|
||||||
|
return !text ? null : text.match(urlAnyProtocolRegExp);
|
||||||
|
}
|
||||||
|
|
||||||
export function matchUrl(text: string) {
|
export function matchUrl(text: string) {
|
||||||
return !text ? null : text.match(urlRegExp);
|
return !text ? null : text.match(urlRegExp);
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
.preloader-container {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
@ -798,11 +813,11 @@ $bubble-margin: .25rem;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-vertical-photo {
|
/* &.is-vertical-photo {
|
||||||
.bubble-content {
|
.bubble-content {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
|
|
||||||
.reply {
|
.reply {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
Loading…
Reference in New Issue
Block a user