Browse Source

Images .onload & several fixes

master
morethanwords 5 years ago
parent
commit
67aca5c877
  1. 28
      src/components/misc.ts
  2. 5
      src/components/scrollable.ts
  3. 36
      src/components/wrappers.ts
  4. 3
      src/lib/appManagers/appDialogsManager.ts
  5. 44
      src/lib/appManagers/appDocsManager.ts
  6. 191
      src/lib/appManagers/appImManager.ts
  7. 16
      src/lib/appManagers/appMediaViewer.ts
  8. 6
      src/lib/appManagers/appPhotosManager.ts
  9. 4
      src/lib/appManagers/appStickersManager.ts
  10. 14
      src/lib/appManagers/appWebpManager.ts
  11. 157
      src/lib/filemanager.ts
  12. 9
      src/scss/partials/_chat.scss

28
src/components/misc.ts

@ -92,14 +92,26 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool @@ -92,14 +92,26 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
});
}
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement, url: string) {
let img = new Image();
img.src = url;
img.onload = () => {
if(elem instanceof HTMLImageElement) elem.src = url;
else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url);
else elem.style.backgroundImage = 'url(' + url + ')';
};
let loadedURLs: {[url: string]: boolean} = {};
let set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) => {
if(elem instanceof HTMLImageElement || elem instanceof HTMLSourceElement) elem.src = url;
else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url);
else elem.style.backgroundImage = 'url(' + url + ')';
};
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) {
if(loadedURLs[url]) return set(elem, url);
if(elem instanceof HTMLSourceElement) {
return elem.src = url;
} else {
let loader = new Image();
loader.src = url;
loader.onload = () => {
set(elem, url);
loadedURLs[url] = true;
};
}
}
export function putPreloader(elem: Element, returnDiv = false) {

5
src/components/scrollable.ts

@ -875,9 +875,8 @@ export default class Scrollable { @@ -875,9 +875,8 @@ export default class Scrollable {
public removeElement(element: Element) {
if(!this.splitUp) {
if(this.container.contains(element)) {
//fastdom.mutate(() => this.container.removeChild(element));
this.container.removeChild(element);
if(element.parentElement) {
element.remove();
}
return;

36
src/components/wrappers.ts

@ -36,6 +36,7 @@ export type MTDocument = { @@ -36,6 +36,7 @@ export type MTDocument = {
file?: File,
duration?: number,
downloaded?: boolean,
url?: string,
version?: any,
audioTitle?: string,
@ -110,11 +111,10 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi @@ -110,11 +111,10 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi
//return;
///////console.log('loaded doc:', doc, blob, container);
console.log('loaded doc:', doc, doc.url, blob, container);
//source.src = doc.url;
renderImageFromUrl(source, doc.url);
source.type = doc.mime_type;
source.src = URL.createObjectURL(blob);
video.append(source);
if(!withTail) {
@ -141,7 +141,7 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi @@ -141,7 +141,7 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi
};
if(doc.type == 'gif' || true) { // extra fix
return this.lazyLoadQueue.push({div: container, load: loadVideo, wasSeen: true});
return doc.downloaded ? loadVideo() : this.lazyLoadQueue.push({div: container, load: loadVideo, wasSeen: true});
} /* else { // if video
let load = () => appPhotosManager.preloadPhoto(doc).then((blob) => {
if((this.peerID ? this.peerID : this.currentMessageID) != peerID) {
@ -446,7 +446,7 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string}, @@ -446,7 +446,7 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string},
let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
svg.append(image);
let size = appPhotosManager.setAttachmentSize(photo.type ? photo : photo.id, svg, boxWidth, boxHeight, false);
let size = appPhotosManager.setAttachmentSize(photo._ == 'document' ? photo : photo.id, svg, boxWidth, boxHeight);
let width = +svg.getAttributeNS(null, 'width');
let height = +svg.getAttributeNS(null, 'height');
@ -540,7 +540,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: ( @@ -540,7 +540,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
console.log('wrap sticker', doc, div, onlyThumb);
if(doc.thumbs && !div.firstElementChild) {
if(doc.thumbs && !div.firstElementChild && (!doc.downloaded || stickerType == 2)) {
let thumb = doc.thumbs[0];
console.log('wrap sticker', thumb, div);
@ -652,17 +652,19 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: ( @@ -652,17 +652,19 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
reader.readAsArrayBuffer(blob);
} else if(stickerType == 1) {
let img = new Image();
appWebpManager.polyfillImage(img, blob).then(() => {
if(div.firstElementChild && div.firstElementChild != img) {
div.firstElementChild.remove();
}
});
//img.src = URL.createObjectURL(blob);
/* div.style.height = doc.h + 'px';
div.style.width = doc.w + 'px'; */
if(!doc.url) {
appWebpManager.polyfillImage(img, blob).then((url) => {
doc.url = url;
if(div.firstElementChild && div.firstElementChild != img) {
div.firstElementChild.remove();
}
});
} else {
img.src = doc.url;
}
div.append(img);
}

3
src/lib/appManagers/appDialogsManager.ts

@ -218,8 +218,7 @@ export class AppDialogsManager { @@ -218,8 +218,7 @@ export class AppDialogsManager {
}
let img = new Image();
img.src = this.savedAvatarURLs[peerID];
//renderImageFromUrl(img, this.savedAvatarURLs[peerID]);
renderImageFromUrl(img, this.savedAvatarURLs[peerID]);
div.innerHTML = '';
//div.style.fontSize = '0'; // need
//div.style.backgroundColor = '';

44
src/lib/appManagers/appDocsManager.ts

@ -37,10 +37,10 @@ class AppDocsManager { @@ -37,10 +37,10 @@ class AppDocsManager {
break;
case 'documentAttributeAudio':
apiDoc.duration = attribute.duration
apiDoc.audioTitle = attribute.title
apiDoc.audioPerformer = attribute.performer
apiDoc.type = attribute.pFlags.voice ? 'voice' : 'audio'
apiDoc.duration = attribute.duration;
apiDoc.audioTitle = attribute.title;
apiDoc.audioPerformer = attribute.performer;
apiDoc.type = attribute.pFlags.voice ? 'voice' : 'audio';
break;
case 'documentAttributeVideo':
@ -49,7 +49,7 @@ class AppDocsManager { @@ -49,7 +49,7 @@ class AppDocsManager {
apiDoc.h = attribute.h;
if(apiDoc.thumbs && attribute.pFlags.round_message) {
apiDoc.type = 'round';
} else if(apiDoc.thumbs) {
} else /* if(apiDoc.thumbs) */ {
apiDoc.type = 'video';
}
break;
@ -64,14 +64,14 @@ class AppDocsManager { @@ -64,14 +64,14 @@ class AppDocsManager {
if(attribute.stickerset) {
if(attribute.stickerset._ == 'inputStickerSetEmpty') {
delete attribute.stickerset
delete attribute.stickerset;
} else if(attribute.stickerset._ == 'inputStickerSetID') {
apiDoc.stickerSetInput = attribute.stickerset
apiDoc.stickerSetInput = attribute.stickerset;
}
}
if(apiDoc.thumbs && apiDoc.mime_type == 'image/webp') {
apiDoc.type = 'sticker'
apiDoc.type = 'sticker';
} else if(apiDoc.mime_type == 'application/x-tgsticker') {
apiDoc.type = 'sticker';
apiDoc.animated = true;
@ -103,22 +103,22 @@ class AppDocsManager { @@ -103,22 +103,22 @@ class AppDocsManager {
apiDoc.mime_type = 'video/mp4';
break;
case 'sticker':
apiDoc.mime_type = 'image/webp'
break
apiDoc.mime_type = 'image/webp';
break;
case 'audio':
apiDoc.mime_type = 'audio/mpeg'
break
apiDoc.mime_type = 'audio/mpeg';
break;
case 'voice':
apiDoc.mime_type = 'audio/ogg'
break
apiDoc.mime_type = 'audio/ogg';
break;
default:
apiDoc.mime_type = 'application/octet-stream'
break
apiDoc.mime_type = 'application/octet-stream';
break;
}
}
if(!apiDoc.file_name) {
apiDoc.file_name = ''
apiDoc.file_name = '';
}
if(apiDoc._ == 'documentEmpty') {
@ -132,10 +132,6 @@ class AppDocsManager { @@ -132,10 +132,6 @@ class AppDocsManager {
return this.docs[docID] || {_: 'documentEmpty'};
}
public hasDoc(docID: string) {
return this.docs[docID] !== undefined;
}
public getFileName(doc: MTDocument) {
if(doc.file_name) {
return doc.file_name;
@ -209,9 +205,9 @@ class AppDocsManager { @@ -209,9 +205,9 @@ class AppDocsManager {
if(blob) {
doc.downloaded = true;
/* FileManager.getFileCorrectUrl(blob, doc.mime_type).then((url) => {
doc.url = url;
}); */
if(/* !doc.animated || */doc.type != 'sticker') {
doc.url = FileManager.getFileCorrectUrl(blob, doc.mime_type);
}
}
/* doc.progress.percent = 100;

191
src/lib/appManagers/appImManager.ts

@ -28,76 +28,6 @@ console.log('appImManager included!'); @@ -28,76 +28,6 @@ console.log('appImManager included!');
let testScroll = false;
class ScrollPosition {
previousScrollHeightMinusTop = 0;
readyFor = 'up';
container: HTMLElement;
rAF: number;
debug = true;
prepared = false;
constructor(node: HTMLElement) {
this.container = node.parentElement;
}
restore(callback?: () => void) {
return;
let setScrollTop = this.container.scrollHeight - this.previousScrollHeightMinusTop;
if(this.debug) appImManager.log('scrollPosition restore', this.readyFor, this.container.scrollHeight,
setScrollTop, this.container, this.container.parentElement.classList.contains('scrolled-down'));
if(this.readyFor === 'up' || this.container.parentElement.classList.contains('scrolled-down')) {
if(this.debug) appImManager.log('scrollPosition restore 2', this.readyFor, this.container.scrollHeight,
setScrollTop, this.container);
if(this.rAF) window.cancelAnimationFrame(this.rAF);
this.rAF = window.requestAnimationFrame(() => {
this.container.scrollTop = this.container.scrollHeight - this.previousScrollHeightMinusTop;
this.rAF = 0;
this.prepared = false;
callback && callback();
});
}/* else if(this.container.parentElement.classList.contains('scrolled-down')) {
if(this.debug) appImManager.log('scrollPosition restore 2', this.readyFor, this.container.scrollHeight,
setScrollTop, this.container);
this.container.scrollTop = setScrollTop;
this.prepared = false;
} */
// 'down' doesn't need to be special cased unless the
// content was flowing upwards, which would only happen
// if the container is position: absolute, bottom: 0 for
// a Facebook messages effect
}
prepareFor(direction = 'up') {
return;
//if(this.prepared) return;
if(this.rAF) {
window.cancelAnimationFrame(this.rAF);
this.rAF = 0;
}
this.readyFor = direction;
if(direction == 'down') {
let scrollTop = this.container.scrollTop;
this.previousScrollHeightMinusTop = scrollTop > 0 ? this.container.scrollHeight - scrollTop : 0;
} else {
this.previousScrollHeightMinusTop = this.container.scrollHeight - this.container.scrollTop;
}
//let scrollTop = this.container.scrollTop;
//this.previousScrollHeightMinusTop = scrollTop > 0 || this.readyFor == 'up' ? this.container.scrollHeight - this.container.scrollTop : 0;
if(this.debug) appImManager.log.warn('scrollPosition prepareFor', direction, this.container.scrollHeight,
this.container.scrollTop, this.previousScrollHeightMinusTop);
}
}
export class AppImManager {
public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
@ -142,8 +72,7 @@ export class AppImManager { @@ -142,8 +72,7 @@ export class AppImManager {
public scroll: HTMLDivElement = null;
public scrollable: Scrollable = null;
public scrollPosition: ScrollPosition = null;
public log: ReturnType<typeof logger>;
private preloader: ProgressivePreloader = null;
@ -171,6 +100,8 @@ export class AppImManager { @@ -171,6 +100,8 @@ export class AppImManager {
private setPeerPromise: Promise<boolean> = null;
public bubbleGroups = new BubbleGroups();
private scrolledDown = true;
constructor() {
/* if(!lottieLoader.loaded) {
@ -204,7 +135,7 @@ export class AppImManager { @@ -204,7 +135,7 @@ export class AppImManager {
$rootScope.$on('history_append', (e: CustomEvent) => {
let details = e.detail;
this.renderMessagesByIDs([details.messageID]);
this.renderNewMessagesByIDs([details.messageID]);
});
// will call when sent for update pos
@ -221,8 +152,6 @@ export class AppImManager { @@ -221,8 +152,6 @@ export class AppImManager {
//this.log('history_update', this.bubbles[mid], mid, message);
this.renderMessage(message, false, false, bubble);
this.deleteEmptySideDivs();
}
});
@ -232,9 +161,7 @@ export class AppImManager { @@ -232,9 +161,7 @@ export class AppImManager {
let msgIDs = msgIDsByPeer[this.peerID];
this.renderMessagesByIDs(msgIDs);
//appDialogsManager.sortDom();
this.renderNewMessagesByIDs(msgIDs);
});
$rootScope.$on('history_delete', (e: CustomEvent) => {
@ -244,10 +171,6 @@ export class AppImManager { @@ -244,10 +171,6 @@ export class AppImManager {
} = e.detail;
this.deleteMessagesByIDs(Object.keys(detail.msgs).map(s => +s));
setTimeout(() => {
this.deleteEmptySideDivs();
}, 0);
});
// Calls when message successfully sent and we have an ID
@ -667,37 +590,6 @@ export class AppImManager { @@ -667,37 +590,6 @@ export class AppImManager {
});
}
public deleteEmptySideDivs() {
return;
let nodes = Array.from(this.chatInner.childNodes) as HTMLDivElement[];
nodes.filter((node) => {
let childElementCount = node.childElementCount;
if(!childElementCount) {
node.remove();
return false;
} else if(childElementCount == 1) {
let child = node.firstElementChild;
if(child.classList.contains('service')) {
node.remove();
return false;
}
}
return true;
}).forEach(node => {
let nextNode = node.nextElementSibling;
if(nextNode && node.className == nextNode.className) {
(Array.from(node.childNodes) as HTMLDivElement[]).reverse().forEach(div => {
nextNode.prepend(div);
});
node.remove();
}
});
}
public updateStatus() {
if(!this.myID) return Promise.resolve();
@ -779,8 +671,10 @@ export class AppImManager { @@ -779,8 +671,10 @@ export class AppImManager {
if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) {
this.scroll.parentElement.classList.add('scrolled-down');
this.scrolledDown = true;
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) {
this.scroll.parentElement.classList.remove('scrolled-down');
this.scrolledDown = false;
}
}
@ -793,8 +687,7 @@ export class AppImManager { @@ -793,8 +687,7 @@ export class AppImManager {
//this.scrollable.setVirtualContainer(this.chatInner);
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
this.scrollPosition = new ScrollPosition(this.chatInner);
this.scroll.addEventListener('scroll', this.onScroll.bind(this));
this.scroll.parentElement.classList.add('scrolled-down');
}
@ -931,6 +824,7 @@ export class AppImManager { @@ -931,6 +824,7 @@ export class AppImManager {
this.getHistoryTopPromise = this.getHistoryBottomPromise = undefined;
//this.scrollable.setVirtualContainer(this.chatInner);
this.scrollable.setVirtualContainer(null);
////console.timeEnd('appImManager cleanup');
}
@ -996,6 +890,8 @@ export class AppImManager { @@ -996,6 +890,8 @@ export class AppImManager {
this.chatInner.style.visibility = 'hidden';
this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : '';
this.topbar.style.display = '';
if(appPeersManager.isAnyGroup(peerID)) this.chatInner.classList.add('is-chat');
else this.chatInner.classList.remove('is-chat');
window.requestAnimationFrame(() => {
//this.chatInner.style.visibility = 'hidden';
@ -1010,8 +906,8 @@ export class AppImManager { @@ -1010,8 +906,8 @@ export class AppImManager {
//this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : '';
//appSidebarRight.toggleSidebar(true);
if(appPeersManager.isAnyGroup(peerID)) this.chatInner.classList.add('is-chat');
else this.chatInner.classList.remove('is-chat');
//if(appPeersManager.isAnyGroup(peerID)) this.chatInner.classList.add('is-chat');
//else this.chatInner.classList.remove('is-chat');
if(!fromClick) {
if(!samePeer && appDialogsManager.lastActiveListElement) {
@ -1141,12 +1037,13 @@ export class AppImManager { @@ -1141,12 +1037,13 @@ export class AppImManager {
lottieLoader.checkAnimations();
}
public renderMessagesByIDs(msgIDs: number[]) {
public renderNewMessagesByIDs(msgIDs: number[]) {
if(!this.bubbles[this.firstTopMsgID] && Object.keys(this.bubbles).length) { // seems search active
//////this.log('seems search is active, skipping render:', msgIDs);
return;
}
let scrolledDown = this.scrolledDown;
msgIDs.forEach((msgID: number) => {
let message = appMessagesManager.getMessage(msgID);
@ -1155,10 +1052,11 @@ export class AppImManager { @@ -1155,10 +1052,11 @@ export class AppImManager {
//this.unreaded.push(msgID);
this.renderMessage(message);
});
if(scrolledDown) this.scrollable.scrollTop = this.scrollable.scrollHeight;
}
// reverse means top, will save scrollPosition if bubble will be higher
public renderMessage(message: any, reverse = false, multipleRender?: boolean, bubble: HTMLDivElement = null, updatePosition = true) {
// reverse means top
public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) {
/////this.log('message to render:', message);
if(message.deleted) return;
@ -1169,11 +1067,7 @@ export class AppImManager { @@ -1169,11 +1067,7 @@ export class AppImManager {
messageDiv.classList.add('message');
//messageDiv.innerText = message.message;
if(!multipleRender) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down'); // лагает из-за этого
}
let bubbleContainer: HTMLDivElement;
// bubble
@ -1406,8 +1300,7 @@ export class AppImManager { @@ -1406,8 +1300,7 @@ export class AppImManager {
if(webpage.photo && !doc) {
bubble.classList.add('photo');
//appPhotosManager.savePhoto(webpage.photo); // hot-fix because no webpage manager
wrapPhoto.call(this, webpage.photo.id, message, preview, 380, 300, false);
}
@ -1440,10 +1333,7 @@ export class AppImManager { @@ -1440,10 +1333,7 @@ export class AppImManager {
case 'messageMediaDocument': {
let doc = message.media.document;
/* if(document.size > 1e6) { // 1mb
break;
} */
this.log('messageMediaDocument', doc, bubble);
if(doc.sticker && doc.size <= 1e6) {
@ -1468,7 +1358,7 @@ export class AppImManager { @@ -1468,7 +1358,7 @@ export class AppImManager {
}, this.lazyLoadQueue, 'chat', false, !!message.pending || !multipleRender);
break;
} else if(doc.mime_type == 'video/mp4' && doc.size <= 20e6) {
} else if((doc.type == 'video' || doc.type == 'gif') && doc.size <= 20e6) {
this.log('never get free 2', doc);
if(doc.type == 'round') {
@ -1614,16 +1504,13 @@ export class AppImManager { @@ -1614,16 +1504,13 @@ export class AppImManager {
} else {
this.scrollable.appendByBatch(bubble);
} */
/* if(reverse) {
this.scrollable.prepend(bubble);
if(!this.scrollable.scrollTop) {
let height = bubble.scrollHeight;
this.scrollable.scrollTop += height;
if(!multipleRender) {
if(reverse) {
this.scrollable.prepend(bubble);
} else {
this.scrollable.append(bubble);
}
} else {
this.scrollable.append(bubble);
} */
}
//});
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
@ -1681,12 +1568,6 @@ export class AppImManager { @@ -1681,12 +1568,6 @@ export class AppImManager {
/* if(bubble.classList.contains('webpage')) {
this.log('night running', bubble, bubble.scrollHeight);
} */
//return //this.scrollPosition.restore();
if(!multipleRender) {
this.scrollPosition.restore(); // лагает из-за этого
}
return bubble;
}
@ -1714,10 +1595,6 @@ export class AppImManager { @@ -1714,10 +1595,6 @@ export class AppImManager {
//console.time('appImManager render history');
this.log('getHistory method', method);
if(!isBackLimit) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down');
}
let firstLoad = !!this.setPeerPromise && false;
@ -1731,7 +1608,7 @@ export class AppImManager { @@ -1731,7 +1608,7 @@ export class AppImManager {
bubbles.push(bubble);
}); */
//let innerHeight = this.scrollable.innerHeight;
let leftHeightToScroll = this.scrollable.innerHeight;
//console.timeEnd('appImManager: pre render start');
@ -1789,7 +1666,12 @@ export class AppImManager { @@ -1789,7 +1666,12 @@ export class AppImManager {
//let height = Math.ceil(bubble.getBoundingClientRect().height);
this.scrollable.scrollTop += height;
//innerHeight -= height;
} else {
}
/* if(leftHeightToScroll >= 0) {
let height = bubble.scrollHeight;
leftHeightToScroll -= height;
this.scrollable.scrollTop += height;
} */ else {
renderedFirstScreen = true;
resolve();
resolved = true;
@ -1906,7 +1788,8 @@ export class AppImManager { @@ -1906,7 +1788,8 @@ export class AppImManager {
return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
} else {
let promise = this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
//return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
return promise;
//return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
}
}

16
src/lib/appManagers/appMediaViewer.ts

@ -8,6 +8,7 @@ import ProgressivePreloader from "../../components/preloader"; @@ -8,6 +8,7 @@ import ProgressivePreloader from "../../components/preloader";
import { findUpClassName, $rootScope, generatePathData } from "../utils";
import appDocsManager from "./appDocsManager";
import { wrapPlayer } from "../ckin";
import { renderImageFromUrl } from "../../components/misc";
export class AppMediaViewer {
private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement;
@ -514,9 +515,8 @@ export class AppMediaViewer { @@ -514,9 +515,8 @@ export class AppMediaViewer {
public updateMediaSource(target: HTMLElement, url: string, tagName: 'source' | 'image') {
//if(target instanceof SVGSVGElement) {
let el = target.querySelector(tagName);
if(tagName == 'source') (el as HTMLSourceElement).src = url;
else el.setAttributeNS(null, 'href', url);
let el = target.querySelector(tagName) as HTMLElement;
renderImageFromUrl(el, url);
/* } else {
} */
@ -644,7 +644,7 @@ export class AppMediaViewer { @@ -644,7 +644,7 @@ export class AppMediaViewer {
return;
}
let url = URL.createObjectURL(blob);
let url = media.url;
if(target instanceof SVGSVGElement) {
this.updateMediaSource(mover, url, 'source');
this.updateMediaSource(target, url, 'source');
@ -655,8 +655,7 @@ export class AppMediaViewer { @@ -655,8 +655,7 @@ export class AppMediaViewer {
}
source = document.createElement('source');
//source.src = doc.url;
source.src = url;
renderImageFromUrl(source, url);
source.type = media.mime_type;
mover.prepend(video);
@ -703,13 +702,14 @@ export class AppMediaViewer { @@ -703,13 +702,14 @@ export class AppMediaViewer {
///////this.log('indochina', blob);
let url = URL.createObjectURL(blob);
let url = media.url;
if(target instanceof SVGSVGElement) {
this.updateMediaSource(target, url, 'image');
this.updateMediaSource(mover, url, 'image');
} else {
let image = mover.firstElementChild as HTMLImageElement || new Image();
image.src = url;
//image.src = url;
renderImageFromUrl(image, url);
mover.prepend(image);
}

6
src/lib/appManagers/appPhotosManager.ts

@ -2,7 +2,7 @@ import appUsersManager from "./appUsersManager"; @@ -2,7 +2,7 @@ import appUsersManager from "./appUsersManager";
import { copy, calcImageInBox } from "../utils";
import fileManager from '../filemanager';
import { bytesFromHex } from "../bin_utils";
import { MTPhotoSize } from "../../components/wrappers";
import { MTPhotoSize, MTDocument } from "../../components/wrappers";
import apiFileManager from "../mtproto/apiFileManager";
import apiManager from "../mtproto/apiManager";
@ -207,7 +207,7 @@ export class AppPhotosManager { @@ -207,7 +207,7 @@ export class AppPhotosManager {
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
let sizes = photo.sizes || photo.thumbs;
if((!photo.downloaded || isSticker) && sizes && sizes[0].bytes) {
if((!photo.downloaded || (isSticker && photo.animated)) && sizes && sizes[0].bytes) {
this.setAttachmentPreview(sizes[0].bytes, element, isSticker);
}
@ -225,6 +225,8 @@ export class AppPhotosManager { @@ -225,6 +225,8 @@ export class AppPhotosManager {
if(element instanceof SVGSVGElement) {
element.setAttributeNS(null, 'width', '' + w);
element.setAttributeNS(null, 'height', '' + h);
console.log('set dimensions to svg element:', element, w, h);
if(element.firstElementChild) {
let imageSvg = element.firstElementChild as SVGImageElement;

4
src/lib/appManagers/appStickersManager.ts

@ -129,7 +129,7 @@ class appStickersManager { @@ -129,7 +129,7 @@ class appStickersManager {
}); */
}
public async getStickerSetThumb(stickerSet: MTStickerSet) {
public getStickerSetThumb(stickerSet: MTStickerSet) {
let thumb = stickerSet.thumb;
let dcID = stickerSet.thumb_dc_id;
@ -144,7 +144,7 @@ class appStickersManager { @@ -144,7 +144,7 @@ class appStickersManager {
local_id: thumb.location.local_id
}, {dcID: dcID});
return await promise;
return promise;
}
public async cleanup() { // if logout

14
src/lib/appManagers/appWebpManager.ts

@ -5,7 +5,7 @@ class AppWebpManager { @@ -5,7 +5,7 @@ class AppWebpManager {
public webpMachine: any = null;
public loaded: Promise<void>;
public busyPromise: Promise<string>;
public queue: {bytes: Uint8Array, img: HTMLImageElement, callback: () => void}[] = [];
public queue: {bytes: Uint8Array, img: HTMLImageElement, callback: (url: string) => void}[] = [];
//public worker: any;
public webpSupport: Promise<boolean> = null;
@ -65,12 +65,13 @@ class AppWebpManager { @@ -65,12 +65,13 @@ class AppWebpManager {
await this.loaded;
this.busyPromise = this.convert(bytes);
let url = await this.busyPromise;
let imgTemp = new Image();
imgTemp.src = await this.busyPromise;
imgTemp.src = url;
imgTemp.onload = () => {
img.src = imgTemp.src;
};
callback();
callback(url);
this.busyPromise = null;
@ -98,11 +99,12 @@ class AppWebpManager { @@ -98,11 +99,12 @@ class AppWebpManager {
//if(await this.webpMachine.webpSupport) {
if(await this.webpSupport) {
img.src = URL.createObjectURL(blob);
return;
let url = URL.createObjectURL(blob);
img.src = url;
return url;
}
return new Promise((resolve, reject) => {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.addEventListener('loadend', (e) => {
// @ts-ignore

157
src/lib/filemanager.ts

@ -8,11 +8,6 @@ if(window.location.href.indexOf('localhost') === -1) { @@ -8,11 +8,6 @@ if(window.location.href.indexOf('localhost') === -1) {
}
class FileManager {
public isSafari = 'safari' in window;
public safariVersion = parseFloat(this.isSafari && (navigator.userAgent.match(/Version\/(\d+\.\d+).* Safari/) || [])[1]);
public safariWithDownload = this.isSafari && this.safariVersion >= 11.0;
public buggyUnknownBlob = this.isSafari && !this.safariWithDownload;
public blobSupported = true;
constructor() {
@ -93,12 +88,12 @@ class FileManager { @@ -93,12 +88,12 @@ class FileManager {
let fileReader = new FileReader();
fileReader.onload = function(event) {
let arrayBuffer = event.target.result as ArrayBuffer;
let arr = new Uint8Array(arrayBuffer);
fileWriter.write(arr).then(resolve, reject);
};
fileReader.readAsArrayBuffer(bytes);
});
} else {
@ -117,7 +112,7 @@ class FileManager { @@ -117,7 +112,7 @@ class FileManager {
let writer = fileStream.getWriter();
return writer;
}
public getFakeFileWriter(mimeType: string, saveFileCallback: any) {
var blobParts: Array<Blob> = [];
var fakeFileWriter = {
@ -143,76 +138,16 @@ class FileManager { @@ -143,76 +138,16 @@ class FileManager {
return fakeFileWriter;
}
public getUrl(fileData: any, mimeType: string) {
public getFileCorrectUrl(fileData: Blob | number[], mimeType: string): string {
var safeMimeType = blobSafeMimeType(mimeType);
// console.log(dT(), 'get url', fileData, mimeType, fileData.toURL !== undefined, fileData instanceof Blob)
if(fileData.toURL !== undefined) {
return fileData.toURL(safeMimeType);
}
if(fileData instanceof Blob) {
return URL.createObjectURL(fileData);
}
return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData);
}
public getByteArray(fileData: any) {
if(fileData instanceof Blob) {
return new Promise((resolve, reject) => {
try {
var reader = new FileReader();
reader.onloadend = (e) => {
// @ts-ignore
resolve(new Uint8Array(e.target.result));
};
reader.onerror = (e) => {
reject(e);
};
reader.readAsArrayBuffer(fileData);
} catch(e) {
reject(e);
}
});
} else if(fileData.file) {
return new Promise((resolve, reject) => {
fileData.file((blob: any) => {
this.getByteArray(blob).then(resolve, reject);
}, reject);
});
}
return Promise.resolve(fileData);
//return $q.when(fileData);
}
public getDataUrl(blob: any) {
return new Promise((resolve, reject) => {
try {
var reader = new FileReader();
reader.onloadend = () => {
resolve(reader.result);
};
reader.readAsDataURL(blob);
} catch (e) {
reject(e);
}
});
}
public getFileCorrectUrl(blob: any, mimeType: string) {
if(this.buggyUnknownBlob && blob instanceof Blob) {
// @ts-ignore
mimeType = blob.type || blob.mimeType || mimeType || ''
if(!mimeType.match(/image\/(jpeg|gif|png|bmp)|video\/quicktime/)) {
return this.getDataUrl(blob);
}
}
return Promise.resolve(this.getUrl(blob, mimeType));
}
// downloadFile
public download(blob: any, mimeType: string, fileName: string) {
public download(blob: Blob, mimeType: string, fileName: string) {
if(window.navigator && navigator.msSaveBlob !== undefined) {
window.navigator.msSaveBlob(blob, fileName);
return false;
@ -244,57 +179,37 @@ class FileManager { @@ -244,57 +179,37 @@ class FileManager {
return;
}
var popup: Window;
if(this.isSafari && !this.safariWithDownload) {
popup = window.open();
let url = this.getFileCorrectUrl(blob, mimeType);
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement;
anchor.href = url as string;
anchor.download = fileName;
if(anchor.dataset) {
anchor.dataset.downloadurl = ['video/quicktime', fileName, url].join(':');
}
this.getFileCorrectUrl(blob, mimeType).then((url) => {
if(popup) {
try {
// @ts-ignore
popup.location.href = url;
return;
} catch (e) {}
}
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement;
anchor.href = url as string;
if(!this.safariWithDownload) {
anchor.target = '_blank';
}
anchor.download = fileName;
if(anchor.dataset) {
anchor.dataset.downloadurl = ['video/quicktime', fileName, url].join(':');
}
anchor.style.position = 'absolute';
anchor.style.top = '1px';
anchor.style.left = '1px';
document.body.append(anchor);
anchor.style.position = 'absolute';
anchor.style.top = '1px';
anchor.style.left = '1px';
document.body.append(anchor);
try {
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
anchor.dispatchEvent(clickEvent);
} catch (e) {
console.error('Download click error', e);
try {
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent(
'click', true, false, window, 0, 0, 0, 0, 0
, false, false, false, false, 0, null
)
anchor.dispatchEvent(clickEvent);
} catch (e) {
console.error('Download click error', e);
try {
anchor.click();
} catch (e) {
window.open(url as string, '_blank');
}
}
setTimeout(() => {
anchor.remove();
}, 100);
})
anchor.click();
} catch (e) {
window.open(url as string, '_blank');
}
}
setTimeout(() => {
anchor.remove();
}, 100);
}
export default new FileManager();
}
export default new FileManager();

9
src/scss/partials/_chat.scss

@ -121,7 +121,10 @@ @@ -121,7 +121,10 @@
bottom: 0;
left: 0;
display: flex; // for end
//display: flex; // for end
//flex-direction: unset;
display: block;
/* display: flex;
flex-direction: column;
@ -156,9 +159,9 @@ @@ -156,9 +159,9 @@
//padding-top: 9px;
margin: 0 auto;
box-sizing: border-box;
/* min-height: 100%; */
min-height: 100%;
justify-content: flex-end;
flex: 1;
//flex: 1;
&.is-chat {
.is-in .bubble__container {

Loading…
Cancel
Save