fix mediaviewer
mediaviewer forward chat contextmenu with rights support manually attached stickers (not upload) right sidebar fix blink & preloader minor fixes Signed-off-by: morethanwords <thanwords24@gmail.com>
This commit is contained in:
parent
f903f8a1c7
commit
842f69216d
44
package-lock.json
generated
44
package-lock.json
generated
@ -4558,8 +4558,7 @@
|
|||||||
},
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -4577,13 +4576,11 @@
|
|||||||
},
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@ -4596,18 +4593,15 @@
|
|||||||
},
|
},
|
||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -4710,8 +4704,7 @@
|
|||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@ -4721,7 +4714,6 @@
|
|||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -4734,20 +4726,17 @@
|
|||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.9.0",
|
"version": "2.9.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@ -4764,7 +4753,6 @@
|
|||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
@ -4820,8 +4808,7 @@
|
|||||||
},
|
},
|
||||||
"npm-normalize-package-bin": {
|
"npm-normalize-package-bin": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"npm-packlist": {
|
"npm-packlist": {
|
||||||
"version": "1.4.8",
|
"version": "1.4.8",
|
||||||
@ -4846,8 +4833,7 @@
|
|||||||
},
|
},
|
||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@ -4857,7 +4843,6 @@
|
|||||||
"once": {
|
"once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@ -4926,8 +4911,7 @@
|
|||||||
},
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@ -4957,7 +4941,6 @@
|
|||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@ -4975,7 +4958,6 @@
|
|||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@ -5014,13 +4996,11 @@
|
|||||||
},
|
},
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,9 @@ export default class LazyLoadQueue {
|
|||||||
|
|
||||||
private observer: IntersectionObserver;
|
private observer: IntersectionObserver;
|
||||||
|
|
||||||
constructor(private parallelLimit = 5) {
|
constructor(private parallelLimit = 5, withObserver = true) {
|
||||||
|
if(!withObserver) return;
|
||||||
|
|
||||||
this.observer = new IntersectionObserver(entries => {
|
this.observer = new IntersectionObserver(entries => {
|
||||||
if(this.lockPromise) return;
|
if(this.lockPromise) return;
|
||||||
|
|
||||||
@ -41,7 +43,10 @@ export default class LazyLoadQueue {
|
|||||||
this.tempID--;
|
this.tempID--;
|
||||||
this.lazyLoadMedia.length = 0;
|
this.lazyLoadMedia.length = 0;
|
||||||
this.loadingMedia = 0;
|
this.loadingMedia = 0;
|
||||||
this.observer.disconnect();
|
|
||||||
|
if(this.observer) {
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public length() {
|
public length() {
|
||||||
@ -103,15 +108,26 @@ export default class LazyLoadQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public push(el: LazyLoadElement) {
|
|
||||||
this.lazyLoadMedia.push(el);
|
|
||||||
|
|
||||||
|
public addElement(el: LazyLoadElement) {
|
||||||
if(el.wasSeen) {
|
if(el.wasSeen) {
|
||||||
this.processQueue(el);
|
this.processQueue(el);
|
||||||
} else {
|
} else {
|
||||||
el.wasSeen = false;
|
el.wasSeen = false;
|
||||||
this.observer.observe(el.div);
|
|
||||||
|
if(this.observer) {
|
||||||
|
this.observer.observe(el.div);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public push(el: LazyLoadElement) {
|
||||||
|
this.lazyLoadMedia.push(el);
|
||||||
|
this.addElement(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unshift(el: LazyLoadElement) {
|
||||||
|
this.lazyLoadMedia.unshift(el);
|
||||||
|
this.addElement(el);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,6 +341,13 @@ export function formatPhoneNumber(str: string) {
|
|||||||
return {formatted: str, country};
|
return {formatted: str, country};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseMenuButtonsTo(to: {[name: string]: HTMLButtonElement}, elements: HTMLCollection) {
|
||||||
|
Array.from(elements).forEach(el => {
|
||||||
|
let name = el.className.match(/ menu-(.+?) /)[1];
|
||||||
|
to[name] = el as HTMLButtonElement;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let onMouseMove = (e: MouseEvent) => {
|
let onMouseMove = (e: MouseEvent) => {
|
||||||
let rect = openedMenu.getBoundingClientRect();
|
let rect = openedMenu.getBoundingClientRect();
|
||||||
let {clientX, clientY} = e;
|
let {clientX, clientY} = e;
|
||||||
|
92
src/components/popup.ts
Normal file
92
src/components/popup.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import AvatarElement from "./avatar";
|
||||||
|
import { ripple } from "./misc";
|
||||||
|
|
||||||
|
export class PopupElement {
|
||||||
|
protected element = document.createElement('div');
|
||||||
|
protected container = document.createElement('div');
|
||||||
|
protected header = document.createElement('div');
|
||||||
|
protected title = document.createElement('div');
|
||||||
|
|
||||||
|
constructor(className: string) {
|
||||||
|
this.element.classList.add('popup');
|
||||||
|
this.element.className = 'popup' + (className ? ' ' + className : '');
|
||||||
|
this.container.classList.add('popup-container', 'z-depth-1');
|
||||||
|
|
||||||
|
this.header.classList.add('popup-header');
|
||||||
|
this.title.classList.add('popup-title');
|
||||||
|
|
||||||
|
this.header.append(this.title);
|
||||||
|
this.container.append(this.header);
|
||||||
|
this.element.append(this.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show() {
|
||||||
|
document.body.append(this.element);
|
||||||
|
void this.element.offsetWidth; // reflow
|
||||||
|
this.element.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.element.classList.remove('active');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.remove();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PopupPeerButton = {
|
||||||
|
text: string,
|
||||||
|
callback?: () => void,
|
||||||
|
isDanger?: true,
|
||||||
|
isCancel?: true
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PopupPeer extends PopupElement {
|
||||||
|
constructor(private className: string, options: Partial<{
|
||||||
|
peerID: number,
|
||||||
|
title: string,
|
||||||
|
description: string,
|
||||||
|
buttons: Array<PopupPeerButton>
|
||||||
|
}> = {}) {
|
||||||
|
super('popup-peer' + (className ? ' ' + className : ''));
|
||||||
|
|
||||||
|
let avatarEl = new AvatarElement();
|
||||||
|
avatarEl.setAttribute('dialog', '1');
|
||||||
|
avatarEl.setAttribute('peer', '' + options.peerID);
|
||||||
|
avatarEl.classList.add('peer-avatar');
|
||||||
|
|
||||||
|
this.title.innerText = options.title || '';
|
||||||
|
this.header.prepend(avatarEl);
|
||||||
|
|
||||||
|
let p = document.createElement('p');
|
||||||
|
p.classList.add('popup-description');
|
||||||
|
p.innerHTML = options.description;
|
||||||
|
|
||||||
|
let buttonsDiv = document.createElement('div');
|
||||||
|
buttonsDiv.classList.add('popup-buttons');
|
||||||
|
|
||||||
|
let buttons = options.buttons.map(b => {
|
||||||
|
let button = document.createElement('button');
|
||||||
|
ripple(button);
|
||||||
|
button.className = 'btn' + (b.isDanger ? ' danger' : '');
|
||||||
|
button.innerHTML = b.text;
|
||||||
|
|
||||||
|
if(b.callback) {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
b.callback();
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
} else if(b.isCancel) {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonsDiv.append(...buttons);
|
||||||
|
|
||||||
|
this.container.append(p, buttonsDiv);
|
||||||
|
}
|
||||||
|
}
|
@ -364,7 +364,10 @@ export default class Scrollable {
|
|||||||
public scrollIntoView(element: HTMLElement, smooth = true) {
|
public scrollIntoView(element: HTMLElement, smooth = true) {
|
||||||
if(element.parentElement && !this.scrollLocked) {
|
if(element.parentElement && !this.scrollLocked) {
|
||||||
let isFirstUnread = element.classList.contains('is-first-unread');
|
let isFirstUnread = element.classList.contains('is-first-unread');
|
||||||
|
|
||||||
let offsetTop = element.getBoundingClientRect().top - this.container.getBoundingClientRect().top;
|
let offsetTop = element.getBoundingClientRect().top - this.container.getBoundingClientRect().top;
|
||||||
|
offsetTop = this.container.scrollTop + offsetTop;
|
||||||
|
|
||||||
if(!smooth && isFirstUnread) {
|
if(!smooth && isFirstUnread) {
|
||||||
this.scrollTo(offsetTop, false);
|
this.scrollTo(offsetTop, false);
|
||||||
return;
|
return;
|
||||||
@ -374,7 +377,7 @@ export default class Scrollable {
|
|||||||
let height = element.scrollHeight;
|
let height = element.scrollHeight;
|
||||||
|
|
||||||
let d = (clientHeight - height) / 2;
|
let d = (clientHeight - height) / 2;
|
||||||
offsetTop = this.container.scrollTop + offsetTop - d;
|
offsetTop -= d;
|
||||||
|
|
||||||
this.scrollTo(offsetTop, smooth);
|
this.scrollTo(offsetTop, smooth);
|
||||||
}
|
}
|
||||||
|
@ -796,8 +796,6 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
|
|
||||||
//console.timeEnd('decompress sticker' + doc.id);
|
//console.timeEnd('decompress sticker' + doc.id);
|
||||||
|
|
||||||
console.log('sticker json:', json);
|
|
||||||
|
|
||||||
let animation = await LottieLoader.loadAnimation({
|
let animation = await LottieLoader.loadAnimation({
|
||||||
container: div,
|
container: div,
|
||||||
loop: false,
|
loop: false,
|
||||||
|
@ -176,8 +176,8 @@ export class ApiUpdatesManager {
|
|||||||
|
|
||||||
public getDifference() {
|
public getDifference() {
|
||||||
// console.trace(dT(), 'Get full diff')
|
// console.trace(dT(), 'Get full diff')
|
||||||
let updatesState = this.updatesState;
|
const updatesState = this.updatesState;
|
||||||
if (!updatesState.syncLoading) {
|
if(!updatesState.syncLoading) {
|
||||||
updatesState.syncLoading = true;
|
updatesState.syncLoading = true;
|
||||||
updatesState.pendingSeqUpdates = {};
|
updatesState.pendingSeqUpdates = {};
|
||||||
updatesState.pendingPtsUpdates = [];
|
updatesState.pendingPtsUpdates = [];
|
||||||
@ -188,7 +188,7 @@ export class ApiUpdatesManager {
|
|||||||
updatesState.syncPending = false;
|
updatesState.syncPending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
apiManager.invokeApi('updates.getDifference', {
|
return apiManager.invokeApi('updates.getDifference', {
|
||||||
pts: updatesState.pts,
|
pts: updatesState.pts,
|
||||||
date: updatesState.date,
|
date: updatesState.date,
|
||||||
qts: -1
|
qts: -1
|
||||||
@ -232,7 +232,7 @@ export class ApiUpdatesManager {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var nextState = differenceResult.intermediate_state || differenceResult.state;
|
const nextState = differenceResult.intermediate_state || differenceResult.state;
|
||||||
updatesState.seq = nextState.seq;
|
updatesState.seq = nextState.seq;
|
||||||
updatesState.pts = nextState.pts;
|
updatesState.pts = nextState.pts;
|
||||||
updatesState.date = nextState.date;
|
updatesState.date = nextState.date;
|
||||||
@ -515,7 +515,6 @@ export class ApiUpdatesManager {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Object.assign(this.updatesState, state);
|
Object.assign(this.updatesState, state);
|
||||||
this.updatesState.syncLoading = false;
|
|
||||||
this.getDifference();
|
this.getDifference();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,12 +128,10 @@ export class AppChatsManager {
|
|||||||
return this.chats[id] || {id: id, deleted: true, access_hash: this.channelAccess[id]};
|
return this.chats[id] || {id: id, deleted: true, access_hash: this.channelAccess[id]};
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasRights(id: number, action: 'send' | 'edit_title' | 'edit_photo' | 'invite') {
|
public hasRights(id: number, action: 'send' | 'edit_title' | 'edit_photo' | 'invite' | 'pin' | 'deleteRevoke') {
|
||||||
if(!(id in this.chats)) {
|
const chat = this.getChat(id);
|
||||||
return false;
|
if(!chat) return false;
|
||||||
}
|
|
||||||
|
|
||||||
let chat = this.getChat(id);
|
|
||||||
if(chat._ == 'chatForbidden' ||
|
if(chat._ == 'chatForbidden' ||
|
||||||
chat._ == 'channelForbidden' ||
|
chat._ == 'channelForbidden' ||
|
||||||
chat.pFlags.kicked ||
|
chat.pFlags.kicked ||
|
||||||
@ -145,24 +143,50 @@ export class AppChatsManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let myFlags = (chat.admin_rights || chat.banned_rights || chat.default_banned_rights)?.pFlags ?? {};
|
||||||
|
|
||||||
switch(action) {
|
switch(action) {
|
||||||
|
// good
|
||||||
case 'send': {
|
case 'send': {
|
||||||
if(chat._ == 'channel' &&
|
if(chat._ == 'channel' &&
|
||||||
!chat.pFlags.megagroup &&
|
!chat.pFlags.megagroup &&
|
||||||
!chat.pFlags.editor) {
|
!myFlags.post_messages) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// good
|
||||||
|
case 'deleteRevoke': {
|
||||||
|
if(chat._ == 'channel') {
|
||||||
|
return !!myFlags.delete_messages;
|
||||||
|
} else if(!chat.pFlags.admin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// good
|
||||||
|
case 'pin': {
|
||||||
|
if(chat._ == 'channel') {
|
||||||
|
return chat.admin_rights ? !!myFlags.pin_messages || !!myFlags.post_messages : !myFlags.pin_messages;
|
||||||
|
} else {
|
||||||
|
if(myFlags.pin_messages && !chat.pFlags.admin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case 'edit_title':
|
case 'edit_title':
|
||||||
case 'edit_photo':
|
case 'edit_photo':
|
||||||
case 'invite': {
|
case 'invite': {
|
||||||
if(chat._ == 'channel') {
|
if(chat._ == 'channel') {
|
||||||
if(chat.pFlags.megagroup) {
|
if(chat.pFlags.megagroup) {
|
||||||
if(!chat.pFlags.editor &&
|
if(!(action == 'invite' && chat.pFlags.democracy)) {
|
||||||
!(action == 'invite' && chat.pFlags.democracy)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -174,6 +198,7 @@ export class AppChatsManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,7 +331,7 @@ export class AppChatsManager {
|
|||||||
let chat = this.getChat(id);
|
let chat = this.getChat(id);
|
||||||
let myID = appUsersManager.getSelf().id;
|
let myID = appUsersManager.getSelf().id;
|
||||||
if(this.isChannel(id)) {
|
if(this.isChannel(id)) {
|
||||||
let isAdmin = chat.pFlags.creator || chat.pFlags.editor || chat.pFlags.moderator;
|
let isAdmin = chat.pFlags.creator;
|
||||||
participants.forEach((participant) => {
|
participants.forEach((participant) => {
|
||||||
participant.canLeave = myID == participant.user_id;
|
participant.canLeave = myID == participant.user_id;
|
||||||
participant.canKick = isAdmin && participant._ == 'channelParticipant';
|
participant.canKick = isAdmin && participant._ == 'channelParticipant';
|
||||||
|
@ -4,12 +4,13 @@ import appPeersManager from './appPeersManager';
|
|||||||
import appMessagesManager, { AppMessagesManager, Dialog } from "./appMessagesManager";
|
import appMessagesManager, { AppMessagesManager, Dialog } from "./appMessagesManager";
|
||||||
import appUsersManager, { User } from "./appUsersManager";
|
import appUsersManager, { User } from "./appUsersManager";
|
||||||
import { RichTextProcessor } from "../richtextprocessor";
|
import { RichTextProcessor } from "../richtextprocessor";
|
||||||
import { ripple, putPreloader, positionMenu, openBtnMenu } from "../../components/misc";
|
import { ripple, putPreloader, positionMenu, openBtnMenu, parseMenuButtonsTo } from "../../components/misc";
|
||||||
//import Scrollable from "../../components/scrollable";
|
//import Scrollable from "../../components/scrollable";
|
||||||
import Scrollable from "../../components/scrollable_new";
|
import Scrollable from "../../components/scrollable_new";
|
||||||
import { logger } from "../polyfill";
|
import { logger } from "../polyfill";
|
||||||
import appChatsManager from "./appChatsManager";
|
import appChatsManager from "./appChatsManager";
|
||||||
import AvatarElement from "../../components/avatar";
|
import AvatarElement from "../../components/avatar";
|
||||||
|
import { PopupPeerButton, PopupPeer } from "../../components/popup";
|
||||||
|
|
||||||
type DialogDom = {
|
type DialogDom = {
|
||||||
avatarEl: AvatarElement,
|
avatarEl: AvatarElement,
|
||||||
@ -25,95 +26,7 @@ type DialogDom = {
|
|||||||
|
|
||||||
let testScroll = false;
|
let testScroll = false;
|
||||||
|
|
||||||
class PopupElement {
|
|
||||||
protected element = document.createElement('div');
|
|
||||||
protected container = document.createElement('div');
|
|
||||||
protected header = document.createElement('div');
|
|
||||||
protected title = document.createElement('div');
|
|
||||||
|
|
||||||
constructor(className: string) {
|
|
||||||
this.element.classList.add('popup');
|
|
||||||
this.element.className = 'popup' + (className ? ' ' + className : '');
|
|
||||||
this.container.classList.add('popup-container', 'z-depth-1');
|
|
||||||
|
|
||||||
this.header.classList.add('popup-header');
|
|
||||||
this.title.classList.add('popup-title');
|
|
||||||
|
|
||||||
this.header.append(this.title);
|
|
||||||
this.container.append(this.header);
|
|
||||||
this.element.append(this.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public show() {
|
|
||||||
document.body.append(this.element);
|
|
||||||
void this.element.offsetWidth; // reflow
|
|
||||||
this.element.classList.add('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy() {
|
|
||||||
this.element.classList.remove('active');
|
|
||||||
setTimeout(() => {
|
|
||||||
this.element.remove();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PopupPeerButton = {
|
|
||||||
text: string,
|
|
||||||
callback?: () => void,
|
|
||||||
isDanger?: true,
|
|
||||||
isCancel?: true
|
|
||||||
};
|
|
||||||
|
|
||||||
class PopupPeer extends PopupElement {
|
|
||||||
constructor(private className: string, options: Partial<{
|
|
||||||
peerID: number,
|
|
||||||
title: string,
|
|
||||||
description: string,
|
|
||||||
buttons: Array<PopupPeerButton>
|
|
||||||
}> = {}) {
|
|
||||||
super('popup-peer' + (className ? ' ' + className : ''));
|
|
||||||
|
|
||||||
let avatarEl = new AvatarElement();
|
|
||||||
avatarEl.setAttribute('dialog', '1');
|
|
||||||
avatarEl.setAttribute('peer', '' + options.peerID);
|
|
||||||
avatarEl.classList.add('peer-avatar');
|
|
||||||
|
|
||||||
this.title.innerText = options.title || '';
|
|
||||||
this.header.prepend(avatarEl);
|
|
||||||
|
|
||||||
let p = document.createElement('p');
|
|
||||||
p.classList.add('popup-description');
|
|
||||||
p.innerHTML = options.description;
|
|
||||||
|
|
||||||
let buttonsDiv = document.createElement('div');
|
|
||||||
buttonsDiv.classList.add('popup-buttons');
|
|
||||||
|
|
||||||
let buttons = options.buttons.map(b => {
|
|
||||||
let button = document.createElement('button');
|
|
||||||
ripple(button);
|
|
||||||
button.className = 'btn' + (b.isDanger ? ' danger' : '');
|
|
||||||
button.innerHTML = b.text;
|
|
||||||
|
|
||||||
if(b.callback) {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
b.callback();
|
|
||||||
this.destroy();
|
|
||||||
});
|
|
||||||
} else if(b.isCancel) {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
this.destroy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return button;
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonsDiv.append(...buttons);
|
|
||||||
|
|
||||||
this.container.append(p, buttonsDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DialogsContextMenu {
|
class DialogsContextMenu {
|
||||||
private element = document.getElementById('dialogs-contextmenu') as HTMLDivElement;
|
private element = document.getElementById('dialogs-contextmenu') as HTMLDivElement;
|
||||||
@ -129,11 +42,7 @@ class DialogsContextMenu {
|
|||||||
private peerType: 'channel' | 'chat' | 'megagroup' | 'group' | 'saved';
|
private peerType: 'channel' | 'chat' | 'megagroup' | 'group' | 'saved';
|
||||||
|
|
||||||
constructor(private attachTo: HTMLElement[]) {
|
constructor(private attachTo: HTMLElement[]) {
|
||||||
(Array.from(this.element.querySelectorAll('.btn-menu-item')) as HTMLElement[]).forEach(el => {
|
parseMenuButtonsTo(this.buttons, this.element.children);
|
||||||
let name = el.className.match(/ menu-(.+?) /)[1];
|
|
||||||
// @ts-ignore
|
|
||||||
this.buttons[name] = el;
|
|
||||||
});
|
|
||||||
|
|
||||||
const onContextMenu = (e: MouseEvent) => {
|
const onContextMenu = (e: MouseEvent) => {
|
||||||
let li: HTMLDivElement = null;
|
let li: HTMLDivElement = null;
|
||||||
@ -145,13 +54,9 @@ class DialogsContextMenu {
|
|||||||
if(!li) return;
|
if(!li) return;
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if(this.element.classList.contains('active')) {
|
if(this.element.classList.contains('active')) {
|
||||||
/* this.element.classList.remove('active');
|
|
||||||
this.element.parentElement.classList.remove('menu-open'); */
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.cancelBubble = true;
|
e.cancelBubble = true;
|
||||||
|
|
||||||
this.selectedID = +li.getAttribute('data-peerID');
|
this.selectedID = +li.getAttribute('data-peerID');
|
||||||
|
@ -85,10 +85,6 @@ class AppDocsManager {
|
|||||||
if(/* apiDoc.thumbs && */apiDoc.mime_type == 'image/webp') {
|
if(/* apiDoc.thumbs && */apiDoc.mime_type == 'image/webp') {
|
||||||
apiDoc.type = 'sticker';
|
apiDoc.type = 'sticker';
|
||||||
apiDoc.sticker = 1;
|
apiDoc.sticker = 1;
|
||||||
} else if(apiDoc.mime_type == 'application/x-tgsticker') {
|
|
||||||
apiDoc.type = 'sticker';
|
|
||||||
apiDoc.animated = true;
|
|
||||||
apiDoc.sticker = 2;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -134,6 +130,12 @@ class AppDocsManager {
|
|||||||
if(!apiDoc.file_name) {
|
if(!apiDoc.file_name) {
|
||||||
apiDoc.file_name = '';
|
apiDoc.file_name = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(apiDoc.mime_type == 'application/x-tgsticker' && apiDoc.file_name == "AnimatedSticker.tgs") {
|
||||||
|
apiDoc.type = 'sticker';
|
||||||
|
apiDoc.animated = true;
|
||||||
|
apiDoc.sticker = 2;
|
||||||
|
}
|
||||||
|
|
||||||
if(apiDoc._ == 'documentEmpty') {
|
if(apiDoc._ == 'documentEmpty') {
|
||||||
apiDoc.size = 0;
|
apiDoc.size = 0;
|
||||||
|
@ -15,11 +15,10 @@ import lottieLoader from "../lottieLoader";
|
|||||||
import appMediaViewer from "./appMediaViewer";
|
import appMediaViewer from "./appMediaViewer";
|
||||||
import appSidebarLeft from "./appSidebarLeft";
|
import appSidebarLeft from "./appSidebarLeft";
|
||||||
import appChatsManager from "./appChatsManager";
|
import appChatsManager from "./appChatsManager";
|
||||||
import appMessagesIDsManager from "./appMessagesIDsManager";
|
|
||||||
import apiUpdatesManager from './apiUpdatesManager';
|
import apiUpdatesManager from './apiUpdatesManager';
|
||||||
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum, wrapPoll } from '../../components/wrappers';
|
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum, wrapPoll } from '../../components/wrappers';
|
||||||
import ProgressivePreloader from '../../components/preloader';
|
import ProgressivePreloader from '../../components/preloader';
|
||||||
import { openBtnMenu, formatPhoneNumber, positionMenu, ripple } from '../../components/misc';
|
import { openBtnMenu, formatPhoneNumber, positionMenu, ripple, parseMenuButtonsTo } from '../../components/misc';
|
||||||
import { ChatInput } from '../../components/chatInput';
|
import { ChatInput } from '../../components/chatInput';
|
||||||
//import Scrollable from '../../components/scrollable';
|
//import Scrollable from '../../components/scrollable';
|
||||||
import Scrollable from '../../components/scrollable_new';
|
import Scrollable from '../../components/scrollable_new';
|
||||||
@ -31,6 +30,7 @@ import appStickersManager from './appStickersManager';
|
|||||||
import AvatarElement from '../../components/avatar';
|
import AvatarElement from '../../components/avatar';
|
||||||
import appInlineBotsManager from './AppInlineBotsManager';
|
import appInlineBotsManager from './AppInlineBotsManager';
|
||||||
import StickyIntersector from '../../components/stickyIntersector';
|
import StickyIntersector from '../../components/stickyIntersector';
|
||||||
|
import { PopupPeerButton, PopupPeer } from '../../components/popup';
|
||||||
|
|
||||||
console.log('appImManager included!');
|
console.log('appImManager included!');
|
||||||
|
|
||||||
@ -40,6 +40,172 @@ let testScroll = false;
|
|||||||
|
|
||||||
const IGNOREACTIONS = ['messageActionChannelMigrateFrom'];
|
const IGNOREACTIONS = ['messageActionChannelMigrateFrom'];
|
||||||
|
|
||||||
|
class ChatContextMenu {
|
||||||
|
private element = document.getElementById('bubble-contextmenu') as HTMLDivElement;
|
||||||
|
private buttons: {
|
||||||
|
reply: HTMLButtonElement,
|
||||||
|
edit: HTMLButtonElement,
|
||||||
|
copy: HTMLButtonElement,
|
||||||
|
pin: HTMLButtonElement,
|
||||||
|
forward: HTMLButtonElement,
|
||||||
|
delete: HTMLButtonElement
|
||||||
|
} = {} as any;
|
||||||
|
public msgID: number;
|
||||||
|
|
||||||
|
constructor(private attachTo: HTMLElement) {
|
||||||
|
parseMenuButtonsTo(this.buttons, this.element.children);
|
||||||
|
|
||||||
|
attachTo.addEventListener('contextmenu', e => {
|
||||||
|
let bubble: HTMLDivElement = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
bubble = findUpClassName(e.target, 'bubble__container');
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
if(!bubble) return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
if(this.element.classList.contains('active')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
e.cancelBubble = true;
|
||||||
|
|
||||||
|
bubble = bubble.parentElement as HTMLDivElement; // bc container
|
||||||
|
|
||||||
|
let msgID = +bubble.dataset.mid;
|
||||||
|
if(!msgID) return;
|
||||||
|
|
||||||
|
let peerID = $rootScope.selectedPeerID;
|
||||||
|
this.msgID = msgID;
|
||||||
|
|
||||||
|
const message = appMessagesManager.getMessage(msgID);
|
||||||
|
|
||||||
|
this.buttons.copy.style.display = message.message ? '' : 'none';
|
||||||
|
|
||||||
|
if($rootScope.myID == peerID || (peerID < 0 && appChatsManager.hasRights(-peerID, 'pin'))) {
|
||||||
|
this.buttons.pin.style.display = '';
|
||||||
|
} else {
|
||||||
|
this.buttons.pin.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buttons.edit.style.display = appMessagesManager.canEditMessage(msgID) ? '' : 'none';
|
||||||
|
|
||||||
|
let side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';
|
||||||
|
positionMenu(e, this.element, side);
|
||||||
|
openBtnMenu(this.element);
|
||||||
|
|
||||||
|
/////this.log('contextmenu', e, bubble, msgID, side);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.buttons.copy.addEventListener('click', () => {
|
||||||
|
let message = appMessagesManager.getMessage(this.msgID);
|
||||||
|
|
||||||
|
let str = message ? message.message : '';
|
||||||
|
|
||||||
|
var textArea = document.createElement("textarea");
|
||||||
|
textArea.value = str;
|
||||||
|
textArea.style.position = "fixed"; //avoid scrolling to bottom
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Oops, unable to copy', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.buttons.delete.addEventListener('click', () => {
|
||||||
|
let peerID = $rootScope.selectedPeerID;
|
||||||
|
let firstName = appPeersManager.getPeerTitle(peerID, false, true);
|
||||||
|
|
||||||
|
let callback = (revoke: boolean) => {
|
||||||
|
appMessagesManager.deleteMessages([this.msgID], revoke);
|
||||||
|
};
|
||||||
|
|
||||||
|
let title: string, description: string, buttons: PopupPeerButton[];
|
||||||
|
title = 'Delete Message?';
|
||||||
|
description = `Are you sure you want to delete this message?`;
|
||||||
|
|
||||||
|
if(peerID == $rootScope.myID) {
|
||||||
|
buttons = [{
|
||||||
|
text: 'DELETE',
|
||||||
|
isDanger: true,
|
||||||
|
callback: () => callback(false)
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
buttons = [{
|
||||||
|
text: 'DELETE JUST FOR ME',
|
||||||
|
isDanger: true,
|
||||||
|
callback: () => callback(false)
|
||||||
|
}];
|
||||||
|
|
||||||
|
if(peerID > 0) {
|
||||||
|
buttons.push({
|
||||||
|
text: 'DELETE FOR ME AND ' + firstName,
|
||||||
|
isDanger: true,
|
||||||
|
callback: () => callback(true)
|
||||||
|
});
|
||||||
|
} else if(appChatsManager.hasRights(-peerID, 'deleteRevoke')) {
|
||||||
|
buttons.push({
|
||||||
|
text: 'DELETE FOR ALL',
|
||||||
|
isDanger: true,
|
||||||
|
callback: () => callback(true)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.push({
|
||||||
|
text: 'CANCEL',
|
||||||
|
isCancel: true
|
||||||
|
});
|
||||||
|
|
||||||
|
let popup = new PopupPeer('popup-delete-chat', {
|
||||||
|
peerID: peerID,
|
||||||
|
title: title,
|
||||||
|
description: description,
|
||||||
|
buttons: buttons
|
||||||
|
});
|
||||||
|
|
||||||
|
popup.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.buttons.reply.addEventListener('click', () => {
|
||||||
|
const message = appMessagesManager.getMessage(this.msgID);
|
||||||
|
const chatInputC = appImManager.chatInputC;
|
||||||
|
chatInputC.setTopInfo(appPeersManager.getPeerTitle(message.fromID, true), message.message, undefined, message);
|
||||||
|
chatInputC.replyToMsgID = this.msgID;
|
||||||
|
chatInputC.editMsgID = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.buttons.forward.addEventListener('click', () => {
|
||||||
|
appForward.init([this.msgID]);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.buttons.edit.addEventListener('click', () => {
|
||||||
|
const message = appMessagesManager.getMessage(this.msgID);
|
||||||
|
const chatInputC = appImManager.chatInputC;
|
||||||
|
chatInputC.setTopInfo('Editing', message.message, message.message, message);
|
||||||
|
chatInputC.replyToMsgID = 0;
|
||||||
|
chatInputC.editMsgID = this.msgID;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.buttons.pin.addEventListener('click', () => {
|
||||||
|
apiManager.invokeApi('messages.updatePinnedMessage', {
|
||||||
|
flags: 0,
|
||||||
|
peer: appPeersManager.getInputPeerByID($rootScope.selectedPeerID),
|
||||||
|
id: this.msgID
|
||||||
|
}).then(updates => {
|
||||||
|
/////this.log('pinned updates:', updates);
|
||||||
|
apiUpdatesManager.processUpdateMessage(updates);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class AppImManager {
|
export class AppImManager {
|
||||||
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
|
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
|
||||||
@ -58,9 +224,8 @@ export class AppImManager {
|
|||||||
|
|
||||||
public myID = 0;
|
public myID = 0;
|
||||||
public peerID = 0;
|
public peerID = 0;
|
||||||
public muted = false;
|
|
||||||
|
public bubbles: {[mid: string]: HTMLDivElement} = {};
|
||||||
public bubbles: {[mid: number]: HTMLDivElement} = {};
|
|
||||||
public dateMessages: {[timestamp: number]: {
|
public dateMessages: {[timestamp: number]: {
|
||||||
div: HTMLDivElement,
|
div: HTMLDivElement,
|
||||||
firstTimestamp: number,
|
firstTimestamp: number,
|
||||||
@ -94,11 +259,8 @@ export class AppImManager {
|
|||||||
private scrolledAll: boolean;
|
private scrolledAll: boolean;
|
||||||
private scrolledAllDown: boolean;
|
private scrolledAllDown: boolean;
|
||||||
|
|
||||||
public contextMenu = document.getElementById('bubble-contextmenu') as HTMLDivElement;
|
public contextMenu = new ChatContextMenu(this.bubblesContainer);
|
||||||
private contextMenuPin = this.contextMenu.querySelector('.menu-pin') as HTMLDivElement;
|
|
||||||
private contextMenuEdit = this.contextMenu.querySelector('.menu-edit') as HTMLDivElement;
|
|
||||||
private contextMenuMsgID: number;
|
|
||||||
|
|
||||||
private popupDeleteMessage: {
|
private popupDeleteMessage: {
|
||||||
popupEl?: HTMLDivElement,
|
popupEl?: HTMLDivElement,
|
||||||
deleteBothBtn?: HTMLButtonElement,
|
deleteBothBtn?: HTMLButtonElement,
|
||||||
@ -510,123 +672,14 @@ export class AppImManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
document.body.addEventListener('keydown', onKeyDown);
|
document.body.addEventListener('keydown', onKeyDown);
|
||||||
|
|
||||||
this.bubblesContainer.addEventListener('contextmenu', e => {
|
|
||||||
let bubble: HTMLDivElement = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
bubble = findUpClassName(e.target, 'bubble__container');
|
|
||||||
} catch(e) {}
|
|
||||||
|
|
||||||
if(bubble) {
|
|
||||||
bubble = bubble.parentElement as HTMLDivElement; // bc container
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
e.cancelBubble = true;
|
|
||||||
|
|
||||||
let msgID = 0;
|
|
||||||
for(let id in this.bubbles) {
|
|
||||||
if(this.bubbles[id] === bubble) {
|
|
||||||
msgID = +id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!msgID) return;
|
|
||||||
|
|
||||||
if(this.myID == this.peerID || (this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) {
|
|
||||||
this.contextMenuPin.style.display = '';
|
|
||||||
} else this.contextMenuPin.style.display = 'none';
|
|
||||||
|
|
||||||
this.contextMenuMsgID = msgID;
|
|
||||||
|
|
||||||
let side = bubble.classList.contains('is-in') ? 'left' : 'right';
|
|
||||||
|
|
||||||
this.contextMenuEdit.style.display = side == 'right' ? '' : 'none';
|
|
||||||
|
|
||||||
positionMenu(e, this.contextMenu, side as any);
|
|
||||||
openBtnMenu(this.contextMenu);
|
|
||||||
|
|
||||||
/////this.log('contextmenu', e, bubble, msgID, side);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.contextMenu.querySelector('.menu-copy').addEventListener('click', () => {
|
|
||||||
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
|
|
||||||
|
|
||||||
let str = message ? message.message : '';
|
|
||||||
|
|
||||||
var textArea = document.createElement("textarea");
|
|
||||||
textArea.value = str;
|
|
||||||
textArea.style.position = "fixed"; //avoid scrolling to bottom
|
|
||||||
document.body.appendChild(textArea);
|
|
||||||
textArea.focus();
|
|
||||||
textArea.select();
|
|
||||||
|
|
||||||
try {
|
|
||||||
document.execCommand('copy');
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Oops, unable to copy', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.contextMenu.querySelector('.menu-delete').addEventListener('click', () => {
|
|
||||||
if(this.peerID == this.myID) {
|
|
||||||
this.popupDeleteMessage.deleteBothBtn.style.display = 'none';
|
|
||||||
this.popupDeleteMessage.deleteMeBtn.innerText = 'DELETE';
|
|
||||||
} else {
|
|
||||||
this.popupDeleteMessage.deleteBothBtn.style.display = '';
|
|
||||||
this.popupDeleteMessage.deleteMeBtn.innerText = 'DELETE JUST FOR ME';
|
|
||||||
|
|
||||||
if(this.peerID > 0) {
|
|
||||||
let title = appPeersManager.getPeerTitle(this.peerID);
|
|
||||||
this.popupDeleteMessage.deleteBothBtn.innerHTML = 'DELETE FOR ME AND ' + title;
|
|
||||||
} else {
|
|
||||||
this.popupDeleteMessage.deleteBothBtn.innerText = 'DELETE FOR ALL';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.popupDeleteMessage.popupEl.classList.add('active');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.contextMenu.querySelector('.menu-reply').addEventListener('click', () => {
|
|
||||||
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
|
|
||||||
this.chatInputC.setTopInfo(appPeersManager.getPeerTitle(message.fromID, true), message.message, undefined, message);
|
|
||||||
this.chatInputC.replyToMsgID = this.contextMenuMsgID;
|
|
||||||
this.chatInputC.editMsgID = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.contextMenu.querySelector('.menu-forward').addEventListener('click', () => {
|
|
||||||
appForward.init([this.contextMenuMsgID]);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.contextMenuEdit.addEventListener('click', () => {
|
|
||||||
let message = appMessagesManager.getMessage(this.contextMenuMsgID);
|
|
||||||
this.chatInputC.setTopInfo('Editing', message.message, message.message, message);
|
|
||||||
this.chatInputC.replyToMsgID = 0;
|
|
||||||
this.chatInputC.editMsgID = this.contextMenuMsgID;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.contextMenuPin.addEventListener('click', () => {
|
|
||||||
apiManager.invokeApi('messages.updatePinnedMessage', {
|
|
||||||
flags: 0,
|
|
||||||
peer: appPeersManager.getInputPeerByID(this.peerID),
|
|
||||||
id: this.contextMenuMsgID
|
|
||||||
}).then(updates => {
|
|
||||||
/////this.log('pinned updates:', updates);
|
|
||||||
apiUpdatesManager.processUpdateMessage(updates);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.popupDeleteMessage.deleteBothBtn.addEventListener('click', () => {
|
this.popupDeleteMessage.deleteBothBtn.addEventListener('click', () => {
|
||||||
this.deleteMessages(true);
|
appMessagesManager.deleteMessages([this.contextMenu.msgID], true);
|
||||||
this.popupDeleteMessage.cancelBtn.click();
|
this.popupDeleteMessage.cancelBtn.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.popupDeleteMessage.deleteMeBtn.addEventListener('click', () => {
|
this.popupDeleteMessage.deleteMeBtn.addEventListener('click', () => {
|
||||||
this.deleteMessages(false);
|
appMessagesManager.deleteMessages([this.contextMenu.msgID], false);
|
||||||
this.popupDeleteMessage.cancelBtn.click();
|
this.popupDeleteMessage.cancelBtn.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -690,7 +743,7 @@ export class AppImManager {
|
|||||||
} */
|
} */
|
||||||
|
|
||||||
//appMessagesManager.readMessages(readed);
|
//appMessagesManager.readMessages(readed);
|
||||||
/* false && */appMessagesManager.readHistory(this.peerID, max, length).catch((err: any) => {
|
/* false && */ appMessagesManager.readHistory(this.peerID, max, length).catch((err: any) => {
|
||||||
this.log.error('readHistory err:', err);
|
this.log.error('readHistory err:', err);
|
||||||
appMessagesManager.readHistory(this.peerID, max, length);
|
appMessagesManager.readHistory(this.peerID, max, length);
|
||||||
});
|
});
|
||||||
@ -698,36 +751,6 @@ export class AppImManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteMessages(revoke = false) {
|
|
||||||
let flags = revoke ? 1 : 0;
|
|
||||||
let ids = [this.contextMenuMsgID];
|
|
||||||
|
|
||||||
apiManager.invokeApi('messages.deleteMessages', {
|
|
||||||
flags: flags,
|
|
||||||
revoke: revoke,
|
|
||||||
id: ids
|
|
||||||
}).then((affectedMessages: any) => {
|
|
||||||
/////this.log('deleted messages:', affectedMessages);
|
|
||||||
|
|
||||||
apiUpdatesManager.processUpdateMessage({
|
|
||||||
_: 'updateShort',
|
|
||||||
update: {
|
|
||||||
_: 'updatePts',
|
|
||||||
pts: affectedMessages.pts,
|
|
||||||
pts_count: affectedMessages.pts_count
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
apiUpdatesManager.processUpdateMessage({
|
|
||||||
_: 'updateShort',
|
|
||||||
update: {
|
|
||||||
_: 'updateDeleteMessages',
|
|
||||||
messages: ids
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateStatus() {
|
public updateStatus() {
|
||||||
if(!this.myID) return Promise.resolve();
|
if(!this.myID) return Promise.resolve();
|
||||||
|
|
||||||
@ -897,8 +920,7 @@ export class AppImManager {
|
|||||||
////console.time('appImManager cleanup');
|
////console.time('appImManager cleanup');
|
||||||
this.scrolledAll = false;
|
this.scrolledAll = false;
|
||||||
this.scrolledAllDown = false;
|
this.scrolledAllDown = false;
|
||||||
this.muted = false;
|
|
||||||
|
|
||||||
this.bubbles = {};
|
this.bubbles = {};
|
||||||
this.dateMessages = {};
|
this.dateMessages = {};
|
||||||
this.bubbleGroups.cleanup();
|
this.bubbleGroups.cleanup();
|
||||||
@ -951,15 +973,12 @@ export class AppImManager {
|
|||||||
const samePeer = this.peerID == peerID;
|
const samePeer = this.peerID == peerID;
|
||||||
|
|
||||||
if(this.setPeerPromise && samePeer) return this.setPeerPromise;
|
if(this.setPeerPromise && samePeer) return this.setPeerPromise;
|
||||||
|
|
||||||
/* if(lastMsgID) {
|
|
||||||
appMessagesManager.readHistory(peerID, lastMsgID); // lol
|
|
||||||
} */
|
|
||||||
|
|
||||||
const dialog = appMessagesManager.getDialogByPeerID(peerID)[0] || null;
|
const dialog = appMessagesManager.getDialogByPeerID(peerID)[0] || null;
|
||||||
const topMessage = lastMsgID <= 0 ? lastMsgID : dialog?.top_message ?? 0;
|
const topMessage = lastMsgID <= 0 ? lastMsgID : dialog?.top_message ?? 0;
|
||||||
if(lastMsgID === undefined && dialog) {
|
const isTarget = lastMsgID !== undefined;
|
||||||
if(dialog.unread_count) {
|
if(!isTarget && dialog) {
|
||||||
|
if(dialog.unread_count && !samePeer) {
|
||||||
lastMsgID = dialog.read_inbox_max_id;
|
lastMsgID = dialog.read_inbox_max_id;
|
||||||
} else {
|
} else {
|
||||||
lastMsgID = dialog.top_message;
|
lastMsgID = dialog.top_message;
|
||||||
@ -971,7 +990,7 @@ export class AppImManager {
|
|||||||
if(dialog && lastMsgID == topMessage) {
|
if(dialog && lastMsgID == topMessage) {
|
||||||
this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);
|
this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);
|
||||||
this.scroll.scrollTop = this.scroll.scrollHeight;
|
this.scroll.scrollTop = this.scroll.scrollHeight;
|
||||||
} else {
|
} else if(isTarget) {
|
||||||
this.scrollable.scrollIntoView(this.bubbles[lastMsgID]);
|
this.scrollable.scrollIntoView(this.bubbles[lastMsgID]);
|
||||||
this.highlightBubble(this.bubbles[lastMsgID]);
|
this.highlightBubble(this.bubbles[lastMsgID]);
|
||||||
}
|
}
|
||||||
@ -1053,11 +1072,11 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fromUp = maxBubbleID > 0 && (maxBubbleID < lastMsgID || lastMsgID < 0);
|
const fromUp = maxBubbleID > 0 && (maxBubbleID < lastMsgID || lastMsgID < 0);
|
||||||
if(!fromUp && samePeer) {
|
const forwardingUnread = dialog.read_inbox_max_id == lastMsgID;
|
||||||
|
if(!fromUp && (samePeer || forwardingUnread)) {
|
||||||
this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const forwardingUnread = dialog.read_inbox_max_id == lastMsgID;
|
|
||||||
const bubble = forwardingUnread ? (this.firstUnreadBubble || this.bubbles[lastMsgID]) : this.bubbles[lastMsgID];
|
const bubble = forwardingUnread ? (this.firstUnreadBubble || this.bubbles[lastMsgID]) : this.bubbles[lastMsgID];
|
||||||
|
|
||||||
this.scrollable.scrollIntoView(bubble, samePeer/* , fromUp */);
|
this.scrollable.scrollIntoView(bubble, samePeer/* , fromUp */);
|
||||||
@ -1075,6 +1094,12 @@ export class AppImManager {
|
|||||||
|
|
||||||
this.log('scrolledAllDown:', this.scrolledAllDown);
|
this.log('scrolledAllDown:', this.scrolledAllDown);
|
||||||
|
|
||||||
|
if(!this.unreaded.length && dialog) { // lol
|
||||||
|
appMessagesManager.readHistory(peerID, dialog.top_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chatInner.classList.remove('disable-hover', 'is-scrolling'); // warning, performance!
|
||||||
|
|
||||||
//console.timeEnd('appImManager setPeer');
|
//console.timeEnd('appImManager setPeer');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1126,6 +1151,8 @@ export class AppImManager {
|
|||||||
|
|
||||||
this.pinnedMessageContainer.style.display = 'none';
|
this.pinnedMessageContainer.style.display = 'none';
|
||||||
|
|
||||||
|
this.btnMute.style.display = appPeersManager.isBroadcast(peerID) ? '' : 'none';
|
||||||
|
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
let title = '';
|
let title = '';
|
||||||
if(this.peerID == this.myID) title = 'Saved Messages';
|
if(this.peerID == this.myID) title = 'Saved Messages';
|
||||||
@ -1642,6 +1669,8 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isOut = our && (!message.fwd_from || this.peerID != this.myID);
|
||||||
|
|
||||||
// media
|
// media
|
||||||
if(messageMedia/* && messageMedia._ == 'messageMediaPhoto' */) {
|
if(messageMedia/* && messageMedia._ == 'messageMediaPhoto' */) {
|
||||||
@ -1696,7 +1725,7 @@ export class AppImManager {
|
|||||||
boxWidth: 380,
|
boxWidth: 380,
|
||||||
boxHeight: 380,
|
boxHeight: 380,
|
||||||
withTail: doc.type != 'round',
|
withTail: doc.type != 'round',
|
||||||
isOut: our,
|
isOut: isOut,
|
||||||
lazyLoadQueue: this.lazyLoadQueue,
|
lazyLoadQueue: this.lazyLoadQueue,
|
||||||
middleware: null
|
middleware: null
|
||||||
});
|
});
|
||||||
@ -1744,7 +1773,7 @@ export class AppImManager {
|
|||||||
lazyLoadQueue: this.lazyLoadQueue
|
lazyLoadQueue: this.lazyLoadQueue
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
wrapPhoto(photo.id, message, attachmentDiv, undefined, undefined, true, our, this.lazyLoadQueue, () => {
|
wrapPhoto(photo.id, message, attachmentDiv, undefined, undefined, true, isOut, this.lazyLoadQueue, () => {
|
||||||
return this.peerID == peerID;
|
return this.peerID == peerID;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1800,7 +1829,8 @@ export class AppImManager {
|
|||||||
lazyLoadQueue: this.lazyLoadQueue,
|
lazyLoadQueue: this.lazyLoadQueue,
|
||||||
middleware: () => {
|
middleware: () => {
|
||||||
return this.peerID == peerID;
|
return this.peerID == peerID;
|
||||||
}
|
},
|
||||||
|
isOut
|
||||||
});
|
});
|
||||||
//}
|
//}
|
||||||
} else {
|
} else {
|
||||||
@ -1907,7 +1937,7 @@ export class AppImManager {
|
|||||||
boxWidth: 380,
|
boxWidth: 380,
|
||||||
boxHeight: 380,
|
boxHeight: 380,
|
||||||
withTail: doc.type != 'round',
|
withTail: doc.type != 'round',
|
||||||
isOut: our,
|
isOut: isOut,
|
||||||
lazyLoadQueue: this.lazyLoadQueue,
|
lazyLoadQueue: this.lazyLoadQueue,
|
||||||
middleware: () => {
|
middleware: () => {
|
||||||
return this.peerID == peerID;
|
return this.peerID == peerID;
|
||||||
@ -2097,7 +2127,7 @@ export class AppImManager {
|
|||||||
bubble.classList.add('hide-name');
|
bubble.classList.add('hide-name');
|
||||||
}
|
}
|
||||||
|
|
||||||
bubble.classList.add(our && (!message.fwd_from || this.peerID != this.myID) ? 'is-out' : 'is-in');
|
bubble.classList.add(isOut ? 'is-out' : 'is-in');
|
||||||
if(updatePosition) {
|
if(updatePosition) {
|
||||||
this.bubbleGroups.addBubble(bubble, message, reverse);
|
this.bubbleGroups.addBubble(bubble, message, reverse);
|
||||||
|
|
||||||
@ -2151,10 +2181,16 @@ export class AppImManager {
|
|||||||
|
|
||||||
let realLength = this.scrollable.length;
|
let realLength = this.scrollable.length;
|
||||||
let previousScrollHeightMinusTop: number;
|
let previousScrollHeightMinusTop: number;
|
||||||
if(realLength > 0 && reverse) {
|
if(realLength > 0 && reverse) { // for safari need set when scrolling bottom too
|
||||||
this.messagesQueueOnRender = () => {
|
this.messagesQueueOnRender = () => {
|
||||||
let scrollTop = this.scrollable.scrollTop;
|
let scrollTop = this.scrollable.scrollTop;
|
||||||
|
|
||||||
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
||||||
|
/* if(reverse) {
|
||||||
|
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
||||||
|
} else {
|
||||||
|
previousScrollHeightMinusTop = scrollTop;
|
||||||
|
} */
|
||||||
|
|
||||||
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, previousScrollHeightMinusTop);
|
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, previousScrollHeightMinusTop);
|
||||||
this.messagesQueueOnRender = undefined;
|
this.messagesQueueOnRender = undefined;
|
||||||
@ -2168,8 +2204,9 @@ export class AppImManager {
|
|||||||
|
|
||||||
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
||||||
if(previousScrollHeightMinusTop !== undefined) {
|
if(previousScrollHeightMinusTop !== undefined) {
|
||||||
this.log('performHistoryResult: will set scrollTop', this.scrollable.scrollHeight, previousScrollHeightMinusTop);
|
const newScrollTop = reverse ? this.scrollable.scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||||
this.scrollable.scrollTop = this.scrollable.scrollHeight - previousScrollHeightMinusTop;
|
this.log('performHistoryResult: will set scrollTop', this.scrollable.scrollHeight, newScrollTop, this.scrollable.container.clientHeight);
|
||||||
|
this.scrollable.scrollTop = newScrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
@ -2186,7 +2223,7 @@ export class AppImManager {
|
|||||||
let peerID = this.peerID;
|
let peerID = this.peerID;
|
||||||
|
|
||||||
//console.time('appImManager call getHistory');
|
//console.time('appImManager call getHistory');
|
||||||
let pageCount = this.bubblesContainer.clientHeight / 38/* * 1.25 */ | 0;
|
let pageCount = appPhotosManager.windowH / 38/* * 1.25 */ | 0;
|
||||||
//let loadCount = Object.keys(this.bubbles).length > 0 ? 50 : pageCount;
|
//let loadCount = Object.keys(this.bubbles).length > 0 ? 50 : pageCount;
|
||||||
let realLoadCount = Object.keys(this.bubbles).length > 0 ? Math.max(40, pageCount) : pageCount;//let realLoadCount = 50;
|
let realLoadCount = Object.keys(this.bubbles).length > 0 ? Math.max(40, pageCount) : pageCount;//let realLoadCount = 50;
|
||||||
let loadCount = realLoadCount;
|
let loadCount = realLoadCount;
|
||||||
@ -2215,7 +2252,7 @@ export class AppImManager {
|
|||||||
if(result instanceof Promise) {
|
if(result instanceof Promise) {
|
||||||
cached = false;
|
cached = false;
|
||||||
promise = result.then((result) => {
|
promise = result.then((result) => {
|
||||||
this.log('getHistory result by maxID:', maxID, reverse, isBackLimit, result);
|
this.log('getHistory not cached result by maxID:', maxID, reverse, isBackLimit, result, peerID);
|
||||||
|
|
||||||
//console.timeEnd('appImManager call getHistory');
|
//console.timeEnd('appImManager call getHistory');
|
||||||
|
|
||||||
@ -2234,8 +2271,8 @@ export class AppImManager {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.log('getHistory result by maxID:', maxID, reverse, isBackLimit, result);
|
|
||||||
cached = true;
|
cached = true;
|
||||||
|
this.log('getHistory cached result by maxID:', maxID, reverse, isBackLimit, result, peerID);
|
||||||
promise = this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID);
|
promise = this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID);
|
||||||
//return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
|
//return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
|
||||||
//return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
|
//return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
|
||||||
@ -2292,7 +2329,7 @@ export class AppImManager {
|
|||||||
if(!dialog?.unread_count) return;
|
if(!dialog?.unread_count) return;
|
||||||
|
|
||||||
let maxID = dialog.read_inbox_max_id;
|
let maxID = dialog.read_inbox_max_id;
|
||||||
maxID = Object.keys(this.bubbles).map(i => +i).sort((a, b) => a - b).find(i => i > maxID);
|
maxID = Object.keys(this.bubbles).filter(mid => !this.bubbles[mid].classList.contains('is-out')).map(i => +i).sort((a, b) => a - b).find(i => i > maxID);
|
||||||
|
|
||||||
if(maxID && this.bubbles[maxID]) {
|
if(maxID && this.bubbles[maxID]) {
|
||||||
let bubble = this.bubbles[maxID];
|
let bubble = this.bubbles[maxID];
|
||||||
@ -2313,7 +2350,7 @@ export class AppImManager {
|
|||||||
for(let i in this.dateMessages) {
|
for(let i in this.dateMessages) {
|
||||||
let dateMessage = this.dateMessages[i];
|
let dateMessage = this.dateMessages[i];
|
||||||
|
|
||||||
if(dateMessage.container.childElementCount == 1) { // only date div
|
if(dateMessage.container.childElementCount == 2) { // only date div + sentinel div
|
||||||
dateMessage.container.remove();
|
dateMessage.container.remove();
|
||||||
this.stickyIntersector.unobserve(dateMessage.container, dateMessage.div);
|
this.stickyIntersector.unobserve(dateMessage.container, dateMessage.div);
|
||||||
delete this.dateMessages[i];
|
delete this.dateMessages[i];
|
||||||
@ -2324,19 +2361,11 @@ export class AppImManager {
|
|||||||
public setMutedState(muted = false) {
|
public setMutedState(muted = false) {
|
||||||
appSidebarRight.profileElements.notificationsCheckbox.checked = !muted;
|
appSidebarRight.profileElements.notificationsCheckbox.checked = !muted;
|
||||||
appSidebarRight.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled';
|
appSidebarRight.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled';
|
||||||
|
|
||||||
let peerID = this.peerID;
|
if(appPeersManager.isBroadcast(this.peerID)) { // not human
|
||||||
|
this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');
|
||||||
this.muted = muted;
|
this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
|
||||||
if(peerID < 0) { // not human
|
this.btnMute.style.display = '';
|
||||||
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
|
|
||||||
if(isChannel) {
|
|
||||||
this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');
|
|
||||||
this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
|
|
||||||
this.btnMute.style.display = '';
|
|
||||||
} else {
|
|
||||||
this.btnMute.style.display = 'none';
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.btnMute.style.display = 'none';
|
this.btnMute.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import appDocsManager from "./appDocsManager";
|
|||||||
import VideoPlayer from "../mediaPlayer";
|
import VideoPlayer from "../mediaPlayer";
|
||||||
import { renderImageFromUrl } from "../../components/misc";
|
import { renderImageFromUrl } from "../../components/misc";
|
||||||
import AvatarElement from "../../components/avatar";
|
import AvatarElement from "../../components/avatar";
|
||||||
|
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
||||||
|
import appForward from "../../components/appForward";
|
||||||
|
|
||||||
export class AppMediaViewer {
|
export class AppMediaViewer {
|
||||||
private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement;
|
private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement;
|
||||||
@ -59,10 +61,15 @@ export class AppMediaViewer {
|
|||||||
private needLoadMore = true;
|
private needLoadMore = true;
|
||||||
|
|
||||||
private pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
private pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
|
|
||||||
|
private setMoverPromise: Promise<void>;
|
||||||
|
|
||||||
|
private lazyLoadQueue: LazyLoadQueue;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = logger('AMV');
|
this.log = logger('AMV');
|
||||||
this.preloader = new ProgressivePreloader();
|
this.preloader = new ProgressivePreloader();
|
||||||
|
this.lazyLoadQueue = new LazyLoadQueue(5, false);
|
||||||
|
|
||||||
this.onKeyDownBinded = this.onKeyDown.bind(this);
|
this.onKeyDownBinded = this.onKeyDown.bind(this);
|
||||||
|
|
||||||
@ -75,6 +82,7 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
this.peerID = 0;
|
this.peerID = 0;
|
||||||
this.currentMessageID = 0;
|
this.currentMessageID = 0;
|
||||||
|
this.lazyLoadQueue.clear();
|
||||||
|
|
||||||
this.setMoverToTarget(this.lastTarget, true);
|
this.setMoverToTarget(this.lastTarget, true);
|
||||||
|
|
||||||
@ -88,6 +96,8 @@ export class AppMediaViewer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.buttons.prev.addEventListener('click', () => {
|
this.buttons.prev.addEventListener('click', () => {
|
||||||
|
if(this.setMoverPromise) return;
|
||||||
|
|
||||||
let target = this.prevTargets.pop();
|
let target = this.prevTargets.pop();
|
||||||
if(target) {
|
if(target) {
|
||||||
this.nextTargets.unshift({element: this.lastTarget, mid: this.currentMessageID});
|
this.nextTargets.unshift({element: this.lastTarget, mid: this.currentMessageID});
|
||||||
@ -98,6 +108,8 @@ export class AppMediaViewer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.buttons.next.addEventListener('click', () => {
|
this.buttons.next.addEventListener('click', () => {
|
||||||
|
if(this.setMoverPromise) return;
|
||||||
|
|
||||||
let target = this.nextTargets.shift();
|
let target = this.nextTargets.shift();
|
||||||
if(target) {
|
if(target) {
|
||||||
this.prevTargets.push({element: this.lastTarget, mid: this.currentMessageID});
|
this.prevTargets.push({element: this.lastTarget, mid: this.currentMessageID});
|
||||||
@ -124,6 +136,10 @@ export class AppMediaViewer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.buttons.forward.addEventListener('click', () => {
|
||||||
|
appForward.init([this.currentMessageID]);
|
||||||
|
});
|
||||||
|
|
||||||
this.onClickBinded = (e: MouseEvent) => {
|
this.onClickBinded = (e: MouseEvent) => {
|
||||||
let target = e.target as HTMLElement;
|
let target = e.target as HTMLElement;
|
||||||
|
|
||||||
@ -155,7 +171,7 @@ export class AppMediaViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setMoverToTarget(target: HTMLElement, closing = false, fromRight = 0) {
|
public async setMoverToTarget(target: HTMLElement, closing = false, fromRight = 0) {
|
||||||
let mover = this.content.mover;
|
let mover = this.content.mover;
|
||||||
|
|
||||||
if(!closing) {
|
if(!closing) {
|
||||||
@ -222,7 +238,7 @@ export class AppMediaViewer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
aspecter = document.createElement('div');
|
aspecter = document.createElement('div');
|
||||||
aspecter.classList.add('media-viewer-aspecter');
|
aspecter.classList.add('media-viewer-aspecter', 'disable-hover');
|
||||||
mover.prepend(aspecter);
|
mover.prepend(aspecter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,19 +273,25 @@ export class AppMediaViewer {
|
|||||||
let isOut = target.classList.contains('is-out');
|
let isOut = target.classList.contains('is-out');
|
||||||
|
|
||||||
if(!closing) {
|
if(!closing) {
|
||||||
let img: HTMLImageElement;
|
let mediaElement: HTMLImageElement | HTMLVideoElement;
|
||||||
let video: HTMLVideoElement;
|
let src: string;
|
||||||
|
|
||||||
if(target.tagName == 'DIV') { // means backgrounded with cover
|
if(target.tagName == 'DIV') { // useContainerAsTarget
|
||||||
img = new Image();
|
if(target.firstElementChild) {
|
||||||
img.src = target.style.backgroundImage.slice(5, -2);
|
mediaElement = new Image();
|
||||||
|
src = (target.firstElementChild as HTMLImageElement).src;
|
||||||
|
mover.append(mediaElement);
|
||||||
|
}
|
||||||
|
/* mediaElement = new Image();
|
||||||
|
src = target.style.backgroundImage.slice(5, -2); */
|
||||||
|
|
||||||
} else if(target instanceof HTMLImageElement) {
|
} else if(target instanceof HTMLImageElement) {
|
||||||
img = new Image();
|
mediaElement = new Image();
|
||||||
img.src = target.src;
|
src = target.src;
|
||||||
} else if(target instanceof HTMLVideoElement) {
|
} else if(target instanceof HTMLVideoElement) {
|
||||||
video = document.createElement('video');
|
let video = mediaElement = document.createElement('video');
|
||||||
let source = document.createElement('source');
|
let source = document.createElement('source');
|
||||||
source.src = target.querySelector('source')?.src;
|
src = target.querySelector('source')?.src;
|
||||||
video.append(source);
|
video.append(source);
|
||||||
} else if(target instanceof SVGSVGElement) {
|
} else if(target instanceof SVGSVGElement) {
|
||||||
let clipID = target.dataset.clipID;
|
let clipID = target.dataset.clipID;
|
||||||
@ -314,23 +336,42 @@ export class AppMediaViewer {
|
|||||||
path.setAttributeNS(null, 'd', d);
|
path.setAttributeNS(null, 'd', d);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mediaEl = newSvg.lastElementChild;
|
let foreignObject = newSvg.lastElementChild;
|
||||||
mediaEl.setAttributeNS(null, 'width', '' + containerRect.width);
|
foreignObject.setAttributeNS(null, 'width', '' + containerRect.width);
|
||||||
mediaEl.setAttributeNS(null, 'height', '' + containerRect.height);
|
foreignObject.setAttributeNS(null, 'height', '' + containerRect.height);
|
||||||
|
|
||||||
mover.prepend(newSvg);
|
mover.prepend(newSvg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(aspecter) {
|
if(aspecter) {
|
||||||
aspecter.style.borderRadius = borderRadius;
|
aspecter.style.borderRadius = borderRadius;
|
||||||
aspecter.append(img || video);
|
aspecter.append(mediaElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaElement = mover.querySelector('video, img');
|
||||||
|
if(mediaElement instanceof HTMLImageElement) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
mediaElement.addEventListener('load', resolve);
|
||||||
|
|
||||||
|
if(src) {
|
||||||
|
mediaElement.src = src;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if(mediaElement instanceof HTMLVideoElement && mediaElement.firstElementChild && (mediaElement.firstElementChild as HTMLSourceElement).src) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
mediaElement.addEventListener('loadeddata', resolve);
|
||||||
|
|
||||||
|
if(src) {
|
||||||
|
(mediaElement.firstElementChild as HTMLSourceElement).src = src;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
mover.style.display = '';
|
mover.style.display = '';
|
||||||
|
|
||||||
setTimeout(() => {
|
window.requestAnimationFrame(() => {
|
||||||
mover.classList.add(wasActive ? 'moving' : 'active');
|
mover.classList.add(wasActive ? 'moving' : 'active');
|
||||||
}, 0);
|
});
|
||||||
} else {
|
} else {
|
||||||
if(target instanceof SVGSVGElement) {
|
if(target instanceof SVGSVGElement) {
|
||||||
path = mover.querySelector('path');
|
path = mover.querySelector('path');
|
||||||
@ -340,6 +381,10 @@ export class AppMediaViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(target.classList.contains('media-viewer-media')) {
|
||||||
|
mover.classList.add('hiding');
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.overlaysDiv.classList.remove('active');
|
this.overlaysDiv.classList.remove('active');
|
||||||
}, 0);
|
}, 0);
|
||||||
@ -354,46 +399,48 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mover.innerHTML = '';
|
mover.innerHTML = '';
|
||||||
mover.classList.remove('moving', 'active');
|
mover.classList.remove('moving', 'active', 'hiding');
|
||||||
mover.style.display = 'none';
|
mover.style.display = 'none';
|
||||||
}, delay);
|
}, delay);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
//await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
mover.style.transform = `translate(${containerRect.left}px,${containerRect.top}px) scale(1,1)`;
|
await new Promise((resolve) => window.requestAnimationFrame(resolve));
|
||||||
|
|
||||||
if(aspecter) {
|
mover.style.transform = `translate(${containerRect.left}px,${containerRect.top}px) scale(1,1)`;
|
||||||
this.setFullAspect(aspecter, containerRect, rect);
|
|
||||||
aspecter.classList.add('disable-hover');
|
if(aspecter) {
|
||||||
|
this.setFullAspect(aspecter, containerRect, rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
mover.style.borderRadius = '';
|
||||||
|
|
||||||
|
if(mover.firstElementChild) {
|
||||||
|
(mover.firstElementChild as HTMLElement).style.borderRadius = '';
|
||||||
|
}
|
||||||
|
}, delay / 2);
|
||||||
|
|
||||||
|
mover.dataset.timeout = '' + setTimeout(() => {
|
||||||
|
mover.classList.remove('moving');
|
||||||
|
|
||||||
|
if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать
|
||||||
|
mover.classList.remove('active');
|
||||||
|
//aspecter.style.cssText = '';
|
||||||
|
void mover.offsetLeft; // reflow
|
||||||
|
|
||||||
|
aspecter.classList.remove('disable-hover');
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
mover.classList.add('active');
|
||||||
mover.style.borderRadius = '';
|
delete mover.dataset.timeout;
|
||||||
|
}, delay);
|
||||||
|
|
||||||
if(mover.firstElementChild) {
|
if(path) {
|
||||||
(mover.firstElementChild as HTMLElement).style.borderRadius = '';
|
this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius);
|
||||||
}
|
}
|
||||||
}, delay / 2);
|
|
||||||
|
|
||||||
mover.dataset.timeout = '' + setTimeout(() => {
|
|
||||||
mover.classList.remove('moving');
|
|
||||||
|
|
||||||
if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать
|
|
||||||
mover.classList.remove('active');
|
|
||||||
aspecter.style.cssText = '';
|
|
||||||
void mover.offsetLeft; // reflow
|
|
||||||
|
|
||||||
aspecter.classList.remove('disable-hover');
|
|
||||||
}
|
|
||||||
|
|
||||||
mover.classList.add('active');
|
|
||||||
delete mover.dataset.timeout;
|
|
||||||
}, delay);
|
|
||||||
|
|
||||||
if(path) {
|
|
||||||
this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setFullAspect(aspecter: HTMLDivElement, containerRect: DOMRect, rect: DOMRect) {
|
private setFullAspect(aspecter: HTMLDivElement, containerRect: DOMRect, rect: DOMRect) {
|
||||||
@ -415,6 +462,8 @@ export class AppMediaViewer {
|
|||||||
height = width * proportion;
|
height = width * proportion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//this.log('will set style aspecter:', `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`);
|
||||||
|
|
||||||
aspecter.style.cssText = `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`;
|
aspecter.style.cssText = `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -581,7 +630,8 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
public openMedia(message: any, target?: HTMLElement, reverse = false, targetContainer?: HTMLElement,
|
public openMedia(message: any, target?: HTMLElement, reverse = false, targetContainer?: HTMLElement,
|
||||||
prevTargets: AppMediaViewer['prevTargets'] = [], nextTargets: AppMediaViewer['prevTargets'] = [], needLoadMore = true) {
|
prevTargets: AppMediaViewer['prevTargets'] = [], nextTargets: AppMediaViewer['prevTargets'] = [], needLoadMore = true) {
|
||||||
////////this.log('openMedia doc:', message, prevTarget, nextTarget);
|
if(this.setMoverPromise) return this.setMoverPromise;
|
||||||
|
this.log('openMedia doc:', message);
|
||||||
const media = message.media.photo || message.media.document || message.media.webpage.document || message.media.webpage.photo;
|
const media = message.media.photo || message.media.document || message.media.webpage.document || message.media.webpage.photo;
|
||||||
|
|
||||||
const isVideo = media.mime_type == 'video/mp4';
|
const isVideo = media.mime_type == 'video/mp4';
|
||||||
@ -652,7 +702,11 @@ export class AppMediaViewer {
|
|||||||
this.content.caption.innerHTML = '';
|
this.content.caption.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let oldAvatar = this.author.avatarEl;
|
||||||
|
// @ts-ignore
|
||||||
|
this.author.avatarEl = this.author.avatarEl.cloneNode();
|
||||||
this.author.avatarEl.setAttribute('peer', '' + message.fromID);
|
this.author.avatarEl.setAttribute('peer', '' + message.fromID);
|
||||||
|
oldAvatar.parentElement.replaceChild(this.author.avatarEl, oldAvatar);
|
||||||
|
|
||||||
// ok set
|
// ok set
|
||||||
|
|
||||||
@ -675,18 +729,17 @@ export class AppMediaViewer {
|
|||||||
const size = appPhotosManager.setAttachmentSize(isVideo ? media : media.id, container, maxWidth, maxHeight);
|
const size = appPhotosManager.setAttachmentSize(isVideo ? media : media.id, container, maxWidth, maxHeight);
|
||||||
|
|
||||||
// need after setAttachmentSize
|
// need after setAttachmentSize
|
||||||
if(useContainerAsTarget) {
|
/* if(useContainerAsTarget) {
|
||||||
target = target.querySelector('img, video') || target;
|
target = target.querySelector('img, video') || target;
|
||||||
}
|
} */
|
||||||
|
|
||||||
|
let setMoverPromise: Promise<void>;
|
||||||
if(isVideo) {
|
if(isVideo) {
|
||||||
////////this.log('will wrap video', media, size);
|
////////this.log('will wrap video', media, size);
|
||||||
|
|
||||||
let afterTimeout = this.setMoverToTarget(target, false, fromRight);
|
setMoverPromise = this.setMoverToTarget(target, false, fromRight).then(() => {
|
||||||
//return; // set and don't move
|
//return; // set and don't move
|
||||||
//if(wasActive) return;
|
//if(wasActive) return;
|
||||||
setTimeout(() => {
|
|
||||||
afterTimeout();
|
|
||||||
//return;
|
//return;
|
||||||
|
|
||||||
let video = mover.querySelector('video') || document.createElement('video');
|
let video = mover.querySelector('video') || document.createElement('video');
|
||||||
@ -694,6 +747,7 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
if(media.type == 'gif') {
|
if(media.type == 'gif') {
|
||||||
video.autoplay = true;
|
video.autoplay = true;
|
||||||
|
video.loop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let createPlayer = () => {
|
let createPlayer = () => {
|
||||||
@ -704,88 +758,112 @@ export class AppMediaViewer {
|
|||||||
let player = new VideoPlayer(video, true);
|
let player = new VideoPlayer(video, true);
|
||||||
/* player.wrapper.parentElement.append(video);
|
/* player.wrapper.parentElement.append(video);
|
||||||
mover.append(player.wrapper); */
|
mover.append(player.wrapper); */
|
||||||
|
} else {
|
||||||
|
video.play();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if(!source || !source.src) {
|
if(!source || !source.src) {
|
||||||
let promise = appDocsManager.downloadDoc(media);
|
let load = () => {
|
||||||
this.preloader.attach(mover, true, promise);
|
let promise = appDocsManager.downloadDoc(media);
|
||||||
|
this.preloader.attach(mover, true, promise);
|
||||||
|
|
||||||
|
promise.then(() => {
|
||||||
|
if(this.currentMessageID != message.mid) {
|
||||||
|
this.log.warn('media viewer changed video');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
promise.then(() => {
|
let url = media.url;
|
||||||
if(this.currentMessageID != message.mid) {
|
if(target instanceof SVGSVGElement) {
|
||||||
this.log.warn('media viewer changed video');
|
this.updateMediaSource(mover, url, 'source');
|
||||||
return;
|
this.updateMediaSource(target, url, 'source');
|
||||||
}
|
} else {
|
||||||
|
let div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;
|
||||||
let url = media.url;
|
let image = div.firstElementChild as HTMLImageElement;
|
||||||
if(target instanceof SVGSVGElement) {
|
if(image instanceof HTMLImageElement) {
|
||||||
this.updateMediaSource(mover, url, 'source');
|
image.remove();
|
||||||
this.updateMediaSource(target, url, 'source');
|
}
|
||||||
} else {
|
|
||||||
let div = mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;
|
renderImageFromUrl(source, url);
|
||||||
let image = div.firstElementChild as HTMLImageElement;
|
source.type = media.mime_type;
|
||||||
if(image instanceof HTMLImageElement) {
|
|
||||||
image.remove();
|
if(!source.parentElement) {
|
||||||
|
video.append(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!video.parentElement) {
|
||||||
|
div.prepend(video);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPlayer();
|
||||||
|
});
|
||||||
|
|
||||||
renderImageFromUrl(source, url);
|
return promise;
|
||||||
source.type = media.mime_type;
|
};
|
||||||
|
|
||||||
if(!source.parentElement) {
|
this.lazyLoadQueue.unshift({
|
||||||
video.append(source);
|
div: null,
|
||||||
}
|
load,
|
||||||
|
wasSeen: true
|
||||||
if(!video.parentElement) {
|
|
||||||
div.prepend(video);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createPlayer();
|
|
||||||
});
|
});
|
||||||
} else createPlayer();
|
} else createPlayer();
|
||||||
}, 0);
|
});
|
||||||
} else {
|
} else {
|
||||||
let afterTimeout = this.setMoverToTarget(target, false, fromRight);
|
setMoverPromise = this.setMoverToTarget(target, false, fromRight).then(() => {
|
||||||
//return; // set and don't move
|
//return; // set and don't move
|
||||||
//if(wasActive) return;
|
//if(wasActive) return;
|
||||||
setTimeout(() => {
|
|
||||||
afterTimeout();
|
|
||||||
//return;
|
//return;
|
||||||
this.preloader.attach(mover);
|
|
||||||
|
let load = () => {
|
||||||
let cancellablePromise = appPhotosManager.preloadPhoto(media.id, size);
|
let cancellablePromise = appPhotosManager.preloadPhoto(media.id, size);
|
||||||
cancellablePromise.then(() => {
|
this.preloader.attach(mover, true, cancellablePromise);
|
||||||
if(this.currentMessageID != message.mid) {
|
cancellablePromise.then(() => {
|
||||||
this.log.warn('media viewer changed photo');
|
if(this.currentMessageID != message.mid) {
|
||||||
return;
|
this.log.warn('media viewer changed photo');
|
||||||
}
|
return;
|
||||||
|
|
||||||
///////this.log('indochina', blob);
|
|
||||||
|
|
||||||
let url = media.url;
|
|
||||||
if(target instanceof SVGSVGElement) {
|
|
||||||
this.updateMediaSource(target, url, 'img');
|
|
||||||
this.updateMediaSource(mover, url, 'img');
|
|
||||||
} else {
|
|
||||||
let div = mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;
|
|
||||||
let image = div.firstElementChild as HTMLImageElement;
|
|
||||||
if(!image || image.tagName != 'IMG') {
|
|
||||||
image = new Image();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////this.log('indochina', blob);
|
||||||
|
|
||||||
|
let url = media.url;
|
||||||
|
if(target instanceof SVGSVGElement) {
|
||||||
|
this.updateMediaSource(target, url, 'img');
|
||||||
|
this.updateMediaSource(mover, url, 'img');
|
||||||
|
} else {
|
||||||
|
let div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;
|
||||||
|
let image = div.firstElementChild as HTMLImageElement;
|
||||||
|
if(!image || image.tagName != 'IMG') {
|
||||||
|
image = new Image();
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.log('will renderImageFromUrl:', image, div, target);
|
||||||
|
|
||||||
|
renderImageFromUrl(image, url).then(() => {
|
||||||
|
div.append(image);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.preloader.detach();
|
||||||
|
}).catch(err => {
|
||||||
|
this.log.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
//this.log('will renderImageFromUrl:', image, div, target);
|
return cancellablePromise;
|
||||||
|
};
|
||||||
|
|
||||||
renderImageFromUrl(image, url).then(() => {
|
this.lazyLoadQueue.unshift({
|
||||||
div.append(image);
|
div: null,
|
||||||
});
|
load,
|
||||||
}
|
wasSeen: true
|
||||||
|
|
||||||
this.preloader.detach();
|
|
||||||
}).catch(err => {
|
|
||||||
this.log.error(err);
|
|
||||||
});
|
});
|
||||||
}, 0);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.setMoverPromise = setMoverPromise.then(() => {
|
||||||
|
this.setMoverPromise = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1844,42 +1844,21 @@ export class AppMessagesManager {
|
|||||||
case 'messageMediaDocument':
|
case 'messageMediaDocument':
|
||||||
let document = message.media.document;
|
let document = message.media.document;
|
||||||
|
|
||||||
let found = false;
|
|
||||||
for(let attribute of document.attributes) {
|
|
||||||
if(found) break;
|
|
||||||
|
|
||||||
switch(attribute._) {
|
|
||||||
case 'documentAttributeSticker':
|
|
||||||
messageText += RichTextProcessor.wrapRichText(attribute.alt) + '<i>Sticker</i>';
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
case 'documentAttributeFilename':
|
|
||||||
messageText += '<i>' + attribute.file_name + '</i>';
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
/* default:
|
|
||||||
console.warn('Got unknown document type!', message);
|
|
||||||
break; */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(document.type == 'video') {
|
if(document.type == 'video') {
|
||||||
messageText = '<i>Video' + (message.message ? ', ' : '') + '</i>';
|
messageText = '<i>Video' + (message.message ? ', ' : '') + '</i>';
|
||||||
found = true;
|
|
||||||
} else if(document.type == 'voice') {
|
} else if(document.type == 'voice') {
|
||||||
messageText = '<i>Voice message</i>';
|
messageText = '<i>Voice message</i>';
|
||||||
found = true;
|
|
||||||
} else if(document.type == 'gif') {
|
} else if(document.type == 'gif') {
|
||||||
messageText = '<i>GIF' + (message.message ? ', ' : '') + '</i>';
|
messageText = '<i>GIF' + (message.message ? ', ' : '') + '</i>';
|
||||||
found = true;
|
|
||||||
} else if(document.type == 'round') {
|
} else if(document.type == 'round') {
|
||||||
messageText = '<i>Video message' + (message.message ? ', ' : '') + '</i>';
|
messageText = '<i>Video message' + (message.message ? ', ' : '') + '</i>';
|
||||||
found = true;
|
} else if(document.type == 'sticker') {
|
||||||
|
messageText = (document.stickerEmoji || '') + '<i>Sticker</i>';
|
||||||
|
} else {
|
||||||
|
messageText = '<i>' + document.file_name + '</i>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(found) {
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
///////console.warn('Got unknown message.media type!', message);
|
///////console.warn('Got unknown message.media type!', message);
|
||||||
@ -2537,6 +2516,77 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public deleteMessages(messageIDs: number[], revoke: boolean) {
|
||||||
|
const splitted = appMessagesIDsManager.splitMessageIDsByChannels(messageIDs);
|
||||||
|
const promises: Promise<any>[] = [];
|
||||||
|
for(const channelIDStr in splitted.msgIDs) {
|
||||||
|
const channelID = +channelIDStr;
|
||||||
|
let msgIDs = splitted.msgIDs[channelID];
|
||||||
|
|
||||||
|
let promise: Promise<any>;
|
||||||
|
if(channelID > 0) {
|
||||||
|
const channel = appChatsManager.getChat(channelID);
|
||||||
|
if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) {
|
||||||
|
const goodMsgIDs: number[] = [];
|
||||||
|
if (channel.pFlags.editor || channel.pFlags.megagroup) {
|
||||||
|
msgIDs.forEach((msgID, i) => {
|
||||||
|
const message = this.getMessage(splitted.mids[channelID][i]);
|
||||||
|
if(message.pFlags.out) {
|
||||||
|
goodMsgIDs.push(msgID);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!goodMsgIDs.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgIDs = goodMsgIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
promise = apiManager.invokeApi('channels.deleteMessages', {
|
||||||
|
channel: appChatsManager.getChannelInput(channelID),
|
||||||
|
id: msgIDs
|
||||||
|
}).then((affectedMessages) => {
|
||||||
|
apiUpdatesManager.processUpdateMessage({
|
||||||
|
_: 'updateShort',
|
||||||
|
update: {
|
||||||
|
_: 'updateDeleteChannelMessages',
|
||||||
|
channel_id: channelID,
|
||||||
|
messages: msgIDs,
|
||||||
|
pts: affectedMessages.pts,
|
||||||
|
pts_count: affectedMessages.pts_count
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let flags = 0;
|
||||||
|
if(revoke) {
|
||||||
|
flags |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
promise = apiManager.invokeApi('messages.deleteMessages', {
|
||||||
|
flags: flags,
|
||||||
|
id: msgIDs
|
||||||
|
}).then((affectedMessages) => {
|
||||||
|
apiUpdatesManager.processUpdateMessage({
|
||||||
|
_: 'updateShort',
|
||||||
|
update: {
|
||||||
|
_: 'updateDeleteMessages',
|
||||||
|
messages: msgIDs,
|
||||||
|
pts: affectedMessages.pts,
|
||||||
|
pts_count: affectedMessages.pts_count
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
promises.push(promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
public readHistory(peerID: number, maxID = 0, readLength = 0): Promise<boolean> {
|
public readHistory(peerID: number, maxID = 0, readLength = 0): Promise<boolean> {
|
||||||
// console.trace('start read')
|
// console.trace('start read')
|
||||||
const isChannel = appPeersManager.isChannel(peerID);
|
const isChannel = appPeersManager.isChannel(peerID);
|
||||||
@ -2590,7 +2640,7 @@ export class AppMessagesManager {
|
|||||||
index = historyStorage.history.indexOf(maxID);
|
index = historyStorage.history.indexOf(maxID);
|
||||||
}
|
}
|
||||||
|
|
||||||
let readedLength = 0;
|
let readedLength = 1;
|
||||||
|
|
||||||
if(historyStorage.history.length && maxID) {
|
if(historyStorage.history.length && maxID) {
|
||||||
for(let i = index == -1 ? 0 : index, length = historyStorage.history.length; i < length; i++) {
|
for(let i = index == -1 ? 0 : index, length = historyStorage.history.length; i < length; i++) {
|
||||||
|
@ -5,7 +5,7 @@ import appImManager from "./appImManager";
|
|||||||
//import apiManager from '../mtproto/apiManager';
|
//import apiManager from '../mtproto/apiManager';
|
||||||
import apiManager from '../mtproto/mtprotoworker';
|
import apiManager from '../mtproto/mtprotoworker';
|
||||||
import AppSearch, { SearchGroup } from "../../components/appSearch";
|
import AppSearch, { SearchGroup } from "../../components/appSearch";
|
||||||
import { horizontalMenu, putPreloader } from "../../components/misc";
|
import { horizontalMenu, putPreloader, parseMenuButtonsTo } from "../../components/misc";
|
||||||
import appUsersManager from "./appUsersManager";
|
import appUsersManager from "./appUsersManager";
|
||||||
import Scrollable from "../../components/scrollable_new";
|
import Scrollable from "../../components/scrollable_new";
|
||||||
import appPhotosManager from "./appPhotosManager";
|
import appPhotosManager from "./appPhotosManager";
|
||||||
@ -273,10 +273,14 @@ class AppContactsTab implements SliderTab {
|
|||||||
|
|
||||||
public onCloseAfterTimeout() {
|
public onCloseAfterTimeout() {
|
||||||
this.list.innerHTML = '';
|
this.list.innerHTML = '';
|
||||||
|
this.input.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public openContacts(query?: string) {
|
public openContacts(query?: string) {
|
||||||
appSidebarLeft.selectTab(SLIDERITEMSIDS.contacts);
|
if(appSidebarLeft.historyTabIDs.indexOf(SLIDERITEMSIDS.contacts) === -1) {
|
||||||
|
appSidebarLeft.selectTab(SLIDERITEMSIDS.contacts);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.promise) return this.promise;
|
if(this.promise) return this.promise;
|
||||||
this.scrollable.onScrolledBottom = null;
|
this.scrollable.onScrolledBottom = null;
|
||||||
|
|
||||||
@ -288,6 +292,9 @@ class AppContactsTab implements SliderTab {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contacts = contacts.slice();
|
||||||
|
contacts.findAndSplice(u => u == $rootScope.myID);
|
||||||
|
|
||||||
let sorted = contacts
|
let sorted = contacts
|
||||||
.map(userID => {
|
.map(userID => {
|
||||||
let user = appUsersManager.getUser(userID);
|
let user = appUsersManager.getUser(userID);
|
||||||
@ -340,11 +347,7 @@ class AppSettingsTab implements SliderTab {
|
|||||||
} = {} as any;
|
} = {} as any;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
(Array.from(this.container.querySelector('.profile-buttons').children) as HTMLButtonElement[]).forEach(el => {
|
parseMenuButtonsTo(this.buttons, this.container.querySelector('.profile-buttons').children);
|
||||||
let name = el.className.match(/ menu-(.+?) /)[1];
|
|
||||||
// @ts-ignore
|
|
||||||
this.buttons[name] = el;
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootScope.$on('user_auth', (e: CustomEvent) => {
|
$rootScope.$on('user_auth', (e: CustomEvent) => {
|
||||||
this.fillElements();
|
this.fillElements();
|
||||||
@ -569,19 +572,22 @@ class AppSidebarLeft {
|
|||||||
private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
||||||
|
|
||||||
private menuEl = this.toolsBtn.querySelector('.btn-menu');
|
private menuEl = this.toolsBtn.querySelector('.btn-menu');
|
||||||
private newGroupBtn = this.menuEl.querySelector('.menu-new-group');
|
private buttons: {
|
||||||
private contactsBtn = this.menuEl.querySelector('.menu-contacts');
|
newGroup: HTMLButtonElement,
|
||||||
private archivedBtn = this.menuEl.querySelector('.menu-archive');
|
contacts: HTMLButtonElement,
|
||||||
private savedBtn = this.menuEl.querySelector('.menu-saved');
|
archived: HTMLButtonElement,
|
||||||
private settingsBtn = this.menuEl.querySelector('.menu-settings');
|
saved: HTMLButtonElement,
|
||||||
public archivedCount = this.archivedBtn.querySelector('.archived-count') as HTMLSpanElement;
|
settings: HTMLButtonElement,
|
||||||
|
help: HTMLButtonElement
|
||||||
|
} = {} as any;
|
||||||
|
public archivedCount: HTMLSpanElement;
|
||||||
|
|
||||||
private newBtnMenu = this.sidebarEl.querySelector('#new-menu');
|
private newBtnMenu = this.sidebarEl.querySelector('#new-menu');
|
||||||
private newButtons = {
|
private newButtons: {
|
||||||
channel: this.newBtnMenu.querySelector('.menu-channel'),
|
channel: HTMLButtonElement,
|
||||||
group: this.newBtnMenu.querySelector('.menu-group'),
|
group: HTMLButtonElement,
|
||||||
privateChat: this.newBtnMenu.querySelector('.menu-private-chat'),
|
privateChat: HTMLButtonElement,
|
||||||
};
|
} = {} as any;
|
||||||
|
|
||||||
public newChannelTab = new AppNewChannelTab();
|
public newChannelTab = new AppNewChannelTab();
|
||||||
public addMembersTab = new AppAddMembersTab();
|
public addMembersTab = new AppAddMembersTab();
|
||||||
@ -620,7 +626,12 @@ class AppSidebarLeft {
|
|||||||
this.searchGroups.people.container.append(peopleContainer);
|
this.searchGroups.people.container.append(peopleContainer);
|
||||||
let peopleScrollable = new Scrollable(peopleContainer, 'x');
|
let peopleScrollable = new Scrollable(peopleContainer, 'x');
|
||||||
|
|
||||||
this.savedBtn.addEventListener('click', (e) => {
|
parseMenuButtonsTo(this.buttons, this.menuEl.children);
|
||||||
|
parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);
|
||||||
|
|
||||||
|
this.archivedCount = this.buttons.archived.querySelector('.archived-count') as HTMLSpanElement;
|
||||||
|
|
||||||
|
this.buttons.saved.addEventListener('click', (e) => {
|
||||||
///////this.log('savedbtn click');
|
///////this.log('savedbtn click');
|
||||||
setTimeout(() => { // menu doesn't close if no timeout (lol)
|
setTimeout(() => { // menu doesn't close if no timeout (lol)
|
||||||
let dom = appDialogsManager.getDialogDom(appImManager.myID);
|
let dom = appDialogsManager.getDialogDom(appImManager.myID);
|
||||||
@ -628,15 +639,15 @@ class AppSidebarLeft {
|
|||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.archivedBtn.addEventListener('click', (e) => {
|
this.buttons.archived.addEventListener('click', (e) => {
|
||||||
this.selectTab(SLIDERITEMSIDS.archived);
|
this.selectTab(SLIDERITEMSIDS.archived);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.contactsBtn.addEventListener('click', (e) => {
|
this.buttons.contacts.addEventListener('click', (e) => {
|
||||||
this.contactsTab.openContacts();
|
this.contactsTab.openContacts();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.settingsBtn.addEventListener('click', () => {
|
this.buttons.settings.addEventListener('click', () => {
|
||||||
this.settingsTab.fillElements();
|
this.settingsTab.fillElements();
|
||||||
this.selectTab(SLIDERITEMSIDS.settings);
|
this.selectTab(SLIDERITEMSIDS.settings);
|
||||||
});
|
});
|
||||||
@ -676,7 +687,7 @@ class AppSidebarLeft {
|
|||||||
this.selectTab(SLIDERITEMSIDS.newChannel);
|
this.selectTab(SLIDERITEMSIDS.newChannel);
|
||||||
});
|
});
|
||||||
|
|
||||||
[this.newButtons.group, this.newGroupBtn].forEach(btn => {
|
[this.newButtons.group, this.buttons.newGroup].forEach(btn => {
|
||||||
btn.addEventListener('click', (e) => {
|
btn.addEventListener('click', (e) => {
|
||||||
this.addMembersTab.init(0, 'chat', false, (peerIDs) => {
|
this.addMembersTab.init(0, 'chat', false, (peerIDs) => {
|
||||||
this.newGroupTab.init(peerIDs);
|
this.newGroupTab.init(peerIDs);
|
||||||
|
@ -175,7 +175,7 @@ class AppSidebarRight {
|
|||||||
appImManager.mutePeer(this.peerID);
|
appImManager.mutePeer(this.peerID);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(testScroll) {
|
if(testScroll && false) {
|
||||||
let div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
for(let i = 0; i < 500; ++i) {
|
for(let i = 0; i < 500; ++i) {
|
||||||
//div.insertAdjacentHTML('beforeend', `<div style="background-image: url(assets/img/camomile.jpg);"></div>`);
|
//div.insertAdjacentHTML('beforeend', `<div style="background-image: url(assets/img/camomile.jpg);"></div>`);
|
||||||
@ -713,9 +713,8 @@ class AppSidebarRight {
|
|||||||
setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username);
|
setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dialog: any = appMessagesManager.getDialogByPeerID(peerID);
|
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||||
if(dialog.length) {
|
if(dialog) {
|
||||||
dialog = dialog[0];
|
|
||||||
let muted = false;
|
let muted = false;
|
||||||
if(dialog.notify_settings && dialog.notify_settings.mute_until) {
|
if(dialog.notify_settings && dialog.notify_settings.mute_until) {
|
||||||
muted = new Date(dialog.notify_settings.mute_until * 1000) > new Date();
|
muted = new Date(dialog.notify_settings.mute_until * 1000) > new Date();
|
||||||
|
@ -68,7 +68,7 @@ class AppStickersManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//if(!this.stickerSets['emoji']) {
|
//if(!this.stickerSets['emoji']) {
|
||||||
this.getStickerSet({id: 'emoji', access_hash: ''});
|
this.getStickerSet({id: 'emoji', access_hash: ''}, {overwrite: true});
|
||||||
//}
|
//}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -95,8 +95,10 @@ class AppStickersManager {
|
|||||||
public async getStickerSet(set: {
|
public async getStickerSet(set: {
|
||||||
id: string,
|
id: string,
|
||||||
access_hash: string
|
access_hash: string
|
||||||
}) {
|
}, params: Partial<{
|
||||||
if(this.stickerSets[set.id]) return this.stickerSets[set.id];
|
overwrite: boolean
|
||||||
|
}> = {}) {
|
||||||
|
if(this.stickerSets[set.id] && !params.overwrite) return this.stickerSets[set.id];
|
||||||
|
|
||||||
let promise = apiManager.invokeApi('messages.getStickerSet', {
|
let promise = apiManager.invokeApi('messages.getStickerSet', {
|
||||||
stickerset: set.id == 'emoji' ? {
|
stickerset: set.id == 'emoji' ? {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { isInDOM } from "./utils";
|
//import { isInDOM } from "./utils";
|
||||||
import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, AnimationItem } from "lottie-web/build/player/lottie.d";
|
import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, AnimationItem } from "lottie-web/build/player/lottie.d";
|
||||||
|
|
||||||
let convert = (value: number) => {
|
let convert = (value: number) => {
|
||||||
@ -85,7 +85,7 @@ class LottieLoader {
|
|||||||
for(let i = length - 1; i >= 0; --i) {
|
for(let i = length - 1; i >= 0; --i) {
|
||||||
let {animation, container, paused, autoplay, canvas} = animations[i];
|
let {animation, container, paused, autoplay, canvas} = animations[i];
|
||||||
|
|
||||||
if(destroy && !isInDOM(container)) {
|
if(destroy && !container.parentElement/* !isInDOM(container) */) {
|
||||||
this.debug && console.log('destroy animation');
|
this.debug && console.log('destroy animation');
|
||||||
animation.destroy();
|
animation.destroy();
|
||||||
animations.splice(i, 1);
|
animations.splice(i, 1);
|
||||||
@ -140,7 +140,7 @@ class LottieLoader {
|
|||||||
k[2] = (foundReplacement[1] & 255) / 255;
|
k[2] = (foundReplacement[1] & 255) / 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('foundReplacement!', foundReplacement, color.toString(16), k);
|
//console.log('foundReplacement!', foundReplacement, color.toString(16), k);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ let onFirstMount = () => {
|
|||||||
putPreloader(this);
|
putPreloader(this);
|
||||||
//this.innerHTML = 'PLEASE WAIT...';
|
//this.innerHTML = 'PLEASE WAIT...';
|
||||||
|
|
||||||
return;
|
//return;
|
||||||
|
|
||||||
let phone_number = telEl.value;
|
let phone_number = telEl.value;
|
||||||
apiManager.invokeApi('auth.sendCode', {
|
apiManager.invokeApi('auth.sendCode', {
|
||||||
|
@ -74,49 +74,39 @@ $move-duration: .35s;
|
|||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.media-viewer-stub {
|
&-stub {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-viewer-container {
|
&-container {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-viewer-media {
|
&-media {
|
||||||
display: flex;
|
visibility: hidden;
|
||||||
align-items: center;
|
}
|
||||||
justify-content: center;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
img, video {
|
&-caption {
|
||||||
max-height: calc(100vh - 100px);
|
flex: 1;
|
||||||
max-width: calc(100vw - 16px);
|
text-align: center;
|
||||||
/* max-height: 720px;
|
color: $color-gray;
|
||||||
max-width: 1280px; */
|
transition: $open-duration;
|
||||||
}
|
max-width: 50vw;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
.media-viewer-caption {
|
&:hover {
|
||||||
flex: 1;
|
color: #fff;
|
||||||
text-align: center;
|
|
||||||
color: $color-gray;
|
|
||||||
transition: $open-duration;
|
|
||||||
max-width: 50vw;
|
|
||||||
word-break: break-word;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,6 +178,7 @@ $move-duration: .35s;
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
@ -197,6 +188,13 @@ $move-duration: .35s;
|
|||||||
&.moving {
|
&.moving {
|
||||||
transition: $move-duration transform ease;
|
transition: $move-duration transform ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.hiding {
|
||||||
|
img, video {
|
||||||
|
transition: $open-duration opacity;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// возможно тут это вообще не нужно
|
// возможно тут это вообще не нужно
|
||||||
@ -205,6 +203,7 @@ $move-duration: .35s;
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-mover.active &-aspecter {
|
&-mover.active &-aspecter {
|
||||||
|
@ -30,6 +30,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#forward-container {
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-search {
|
.sidebar-search {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
@ -41,7 +45,7 @@
|
|||||||
|
|
||||||
.profile {
|
.profile {
|
||||||
&-content {
|
&-content {
|
||||||
flex: 1 1 auto;
|
/* flex: 1 1 auto; */
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
/* height: 100%; */
|
/* height: 100%; */
|
||||||
@ -54,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-wrapper {
|
&-wrapper {
|
||||||
flex: 0 0 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-bottom: 36px;
|
margin-bottom: 36px;
|
||||||
@ -64,16 +68,18 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
//overflow: hidden;
|
//overflow: hidden;
|
||||||
flex: 1 1 auto;
|
position: absolute;
|
||||||
position: relative;
|
top: 100%;
|
||||||
//height: 1%; // fix safari
|
min-height: calc(100vh - 100% - 60px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* &.loaded { // warning
|
&-container {
|
||||||
.profile-tabs-content {
|
> .scrollable {
|
||||||
position: relative;
|
display: flex;
|
||||||
min-height: auto;
|
flex-direction: column;
|
||||||
}
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,12 +165,13 @@
|
|||||||
position: -webkit-sticky !important;
|
position: -webkit-sticky !important;
|
||||||
position: sticky !important;
|
position: sticky !important;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 3;
|
z-index: 2;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
//min-height: 100%;
|
//min-height: 100%;
|
||||||
min-height: calc(100% - 49px);
|
min-height: calc(100% - 49px);
|
||||||
|
flex: 1 1 auto;
|
||||||
//position: absolute; // FIX THE SAFARI!
|
//position: absolute; // FIX THE SAFARI!
|
||||||
//position: relative;
|
//position: relative;
|
||||||
/* width: 500%;
|
/* width: 500%;
|
||||||
|
@ -26,8 +26,8 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
//position: relative;
|
//position: relative;
|
||||||
|
|
||||||
//will-change: transform;
|
//will-change: transform;
|
||||||
transform: translateZ(0);
|
/* transform: translateZ(0);
|
||||||
-webkit-transform: translateZ(0);
|
-webkit-transform: translateZ(0); */
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-bottom: 0.125rem;
|
margin-bottom: 0.125rem;
|
||||||
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-description {
|
&-description {
|
||||||
|
@ -534,7 +534,7 @@ avatar-element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-download {
|
&-download {
|
||||||
z-index: 2;
|
z-index: 1;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
let allowedIPs = ['195.66.140.39', '192.168.31.144', '127.0.0.1', '192.168.31.1', '192.168.31.192', '192.168.0.111'];
|
let allowedIPs = ['195.66.140.39', '192.168.31.144', '127.0.0.1', '192.168.31.1', '192.168.31.192', '192.168.0.111', '192.168.0.105'];
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
MTPROTO_WORKER: true,
|
MTPROTO_WORKER: true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user