Fix displaying chat from the archive in main list
This commit is contained in:
parent
34546d49ee
commit
8992a6e7af
80
src/components/chat/audio.ts
Normal file
80
src/components/chat/audio.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import appImManager from "../../lib/appManagers/appImManager";
|
||||||
|
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||||
|
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||||
|
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||||
|
import { cancelEvent, $rootScope } from "../../lib/utils";
|
||||||
|
import appMediaPlaybackController from "../appMediaPlaybackController";
|
||||||
|
import { formatDate } from "../wrappers";
|
||||||
|
|
||||||
|
export class ChatAudio {
|
||||||
|
public container: HTMLElement;
|
||||||
|
private toggle: HTMLElement;
|
||||||
|
private title: HTMLElement;
|
||||||
|
private subtitle: HTMLElement;
|
||||||
|
private close: HTMLElement;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.container = document.createElement('div');
|
||||||
|
this.container.classList.add('pinned-audio', 'pinned-container');
|
||||||
|
this.container.style.display = 'none';
|
||||||
|
|
||||||
|
this.toggle = document.createElement('div');
|
||||||
|
this.toggle.classList.add('pinned-audio-ico', 'tgico');
|
||||||
|
|
||||||
|
this.title = document.createElement('div');
|
||||||
|
this.title.classList.add('pinned-audio-title');
|
||||||
|
|
||||||
|
this.subtitle = document.createElement('div');
|
||||||
|
this.subtitle.classList.add('pinned-audio-subtitle');
|
||||||
|
|
||||||
|
this.close = document.createElement('button');
|
||||||
|
this.close.classList.add('pinned-audio-close', 'btn-icon', 'tgico-close');
|
||||||
|
|
||||||
|
this.container.append(this.toggle, this.title, this.subtitle, this.close);
|
||||||
|
|
||||||
|
this.close.addEventListener('click', (e) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
this.container.style.display = 'none';
|
||||||
|
this.container.parentElement.classList.remove('is-audio-shown');
|
||||||
|
if(this.toggle.classList.contains('flip-icon')) {
|
||||||
|
appMediaPlaybackController.toggle();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.toggle.addEventListener('click', (e) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
appMediaPlaybackController.toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on('audio_play', (e: CustomEvent) => {
|
||||||
|
const {doc, mid} = e.detail;
|
||||||
|
|
||||||
|
let title: string, subtitle: string;
|
||||||
|
if(doc.type == 'voice' || doc.type == 'round') {
|
||||||
|
const message = appMessagesManager.getMessage(mid);
|
||||||
|
title = appPeersManager.getPeerTitle(message.fromID, false, true);
|
||||||
|
//subtitle = 'Voice message';
|
||||||
|
subtitle = formatDate(message.date, false, false);
|
||||||
|
} else {
|
||||||
|
title = doc.audioTitle || doc.file_name;
|
||||||
|
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.title.innerHTML = title;
|
||||||
|
this.subtitle.innerHTML = subtitle;
|
||||||
|
this.toggle.classList.add('flip-icon');
|
||||||
|
|
||||||
|
this.container.dataset.mid = '' + mid;
|
||||||
|
if(this.container.style.display) {
|
||||||
|
const scrollTop = appImManager.scrollable.scrollTop;
|
||||||
|
this.container.style.display = '';
|
||||||
|
this.container.parentElement.classList.add('is-audio-shown');
|
||||||
|
appImManager.scrollable.scrollTop = scrollTop;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on('audio_pause', () => {
|
||||||
|
this.toggle.classList.remove('flip-icon');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
167
src/components/chat/contextMenu.ts
Normal file
167
src/components/chat/contextMenu.ts
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import appChatsManager from "../../lib/appManagers/appChatsManager";
|
||||||
|
import appImManager from "../../lib/appManagers/appImManager";
|
||||||
|
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||||
|
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||||
|
import { findUpClassName, $rootScope } from "../../lib/utils";
|
||||||
|
import appForward from "../appForward";
|
||||||
|
import { parseMenuButtonsTo, attachContextMenuListener, positionMenu, openBtnMenu } from "../misc";
|
||||||
|
import { PopupButton, PopupPeer } from "../popup";
|
||||||
|
|
||||||
|
export 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);
|
||||||
|
|
||||||
|
attachContextMenuListener(attachTo, (e) => {
|
||||||
|
let bubble: HTMLElement = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
bubble = findUpClassName(e.target, 'bubble__container');
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
if(!bubble) return;
|
||||||
|
|
||||||
|
if(e instanceof MouseEvent) e.preventDefault();
|
||||||
|
if(this.element.classList.contains('active')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(e instanceof MouseEvent) 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: PopupButton[];
|
||||||
|
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', () => {
|
||||||
|
appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, this.msgID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,19 @@
|
|||||||
import Scrollable from "./scrollable_new";
|
import Scrollable from "../scrollable_new";
|
||||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||||
import apiManager from "../lib/mtproto/mtprotoworker";
|
import apiManager from "../../lib/mtproto/mtprotoworker";
|
||||||
import appWebPagesManager from "../lib/appManagers/appWebPagesManager";
|
import appWebPagesManager from "../../lib/appManagers/appWebPagesManager";
|
||||||
import appImManager from "../lib/appManagers/appImManager";
|
import appImManager from "../../lib/appManagers/appImManager";
|
||||||
import { getRichValue, calcImageInBox, cancelEvent } from "../lib/utils";
|
import { getRichValue, calcImageInBox, cancelEvent } from "../../lib/utils";
|
||||||
import { wrapDocument, wrapReply } from "./wrappers";
|
import { wrapDocument, wrapReply } from "../wrappers";
|
||||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||||
import { Layouter, RectPart } from "./groupedLayout";
|
import { Layouter, RectPart } from "../groupedLayout";
|
||||||
import Recorder from '../../public/recorder.min';
|
import Recorder from '../../../public/recorder.min';
|
||||||
//import Recorder from '../opus-recorder/dist/recorder.min';
|
//import Recorder from '../opus-recorder/dist/recorder.min';
|
||||||
import opusDecodeController from "../lib/opusDecodeController";
|
import opusDecodeController from "../../lib/opusDecodeController";
|
||||||
import { touchSupport } from "../lib/config";
|
import { touchSupport } from "../../lib/config";
|
||||||
import appDocsManager from "../lib/appManagers/appDocsManager";
|
import appDocsManager from "../../lib/appManagers/appDocsManager";
|
||||||
import emoticonsDropdown from "./emoticonsDropdown";
|
import emoticonsDropdown from "../emoticonsDropdown";
|
||||||
import PopupCreatePoll from "./popupCreatePoll";
|
import PopupCreatePoll from "../popupCreatePoll";
|
||||||
|
|
||||||
export class ChatInput {
|
export class ChatInput {
|
||||||
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
@ -729,7 +729,7 @@ export class ChatInput {
|
|||||||
|
|
||||||
public sendMessageWithDocument(document: any) {
|
public sendMessageWithDocument(document: any) {
|
||||||
document = appDocsManager.getDoc(document);
|
document = appDocsManager.getDoc(document);
|
||||||
if(document._ != 'documentEmpty') {
|
if(document && document._ != 'documentEmpty') {
|
||||||
appMessagesManager.sendFile(appImManager.peerID, document, {isMedia: true, replyToMsgID: this.replyToMsgID});
|
appMessagesManager.sendFile(appImManager.peerID, document, {isMedia: true, replyToMsgID: this.replyToMsgID});
|
||||||
this.onMessageSent(false, true);
|
this.onMessageSent(false, true);
|
||||||
|
|
187
src/components/chat/search.ts
Normal file
187
src/components/chat/search.ts
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
import appImManager from "../../lib/appManagers/appImManager";
|
||||||
|
import { $rootScope, cancelEvent, whichChild, findUpTag } from "../../lib/utils";
|
||||||
|
import AppSearch, { SearchGroup } from "../appSearch";
|
||||||
|
import PopupDatePicker from "../popupDatepicker";
|
||||||
|
import { ripple } from "../ripple";
|
||||||
|
import SearchInput from "../searchInput";
|
||||||
|
|
||||||
|
export class ChatSearch {
|
||||||
|
private element: HTMLElement;
|
||||||
|
private backBtn: HTMLElement;
|
||||||
|
private searchInput: SearchInput;
|
||||||
|
|
||||||
|
private results: HTMLElement;
|
||||||
|
|
||||||
|
private footer: HTMLElement;
|
||||||
|
private dateBtn: HTMLElement;
|
||||||
|
private foundCountEl: HTMLElement;
|
||||||
|
private controls: HTMLElement;
|
||||||
|
private downBtn: HTMLElement;
|
||||||
|
private upBtn: HTMLElement;
|
||||||
|
|
||||||
|
private appSearch: AppSearch;
|
||||||
|
private searchGroup: SearchGroup;
|
||||||
|
|
||||||
|
private foundCount = 0;
|
||||||
|
private selectedIndex = 0;
|
||||||
|
private setPeerPromise: Promise<any>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.element = document.createElement('div');
|
||||||
|
this.element.classList.add('sidebar-header', 'chat-search', 'chats-container');
|
||||||
|
|
||||||
|
this.backBtn = document.createElement('button');
|
||||||
|
this.backBtn.classList.add('btn-icon', 'tgico-back', 'sidebar-close-button');
|
||||||
|
ripple(this.backBtn);
|
||||||
|
|
||||||
|
this.backBtn.addEventListener('click', () => {
|
||||||
|
appImManager.topbar.classList.remove('hide-pinned');
|
||||||
|
this.element.remove();
|
||||||
|
this.searchInput.remove();
|
||||||
|
this.results.remove();
|
||||||
|
this.footer.remove();
|
||||||
|
this.footer.removeEventListener('click', this.onFooterClick);
|
||||||
|
this.dateBtn.removeEventListener('click', this.onDateClick);
|
||||||
|
this.upBtn.removeEventListener('click', this.onUpClick);
|
||||||
|
this.downBtn.removeEventListener('click', this.onDownClick);
|
||||||
|
this.searchGroup.list.removeEventListener('click', this.onResultsClick);
|
||||||
|
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||||
|
}, {once: true});
|
||||||
|
|
||||||
|
this.searchInput = new SearchInput('Search');
|
||||||
|
|
||||||
|
// Results
|
||||||
|
this.results = document.createElement('div');
|
||||||
|
this.results.classList.add('chat-search-results', 'chats-container');
|
||||||
|
|
||||||
|
this.searchGroup = new SearchGroup('', 'messages', undefined, '', false);
|
||||||
|
this.searchGroup.list.addEventListener('click', this.onResultsClick);
|
||||||
|
|
||||||
|
this.appSearch = new AppSearch(this.results, this.searchInput, {
|
||||||
|
messages: this.searchGroup
|
||||||
|
}, (count) => {
|
||||||
|
this.foundCount = count;
|
||||||
|
|
||||||
|
if(!this.foundCount) {
|
||||||
|
this.foundCountEl.innerText = this.searchInput.value ? 'No results' : '';
|
||||||
|
this.results.classList.remove('active');
|
||||||
|
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||||
|
this.upBtn.setAttribute('disabled', 'true');
|
||||||
|
this.downBtn.setAttribute('disabled', 'true');
|
||||||
|
} else {
|
||||||
|
this.selectResult(this.searchGroup.list.children[0] as HTMLElement);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.appSearch.beginSearch($rootScope.selectedPeerID);
|
||||||
|
|
||||||
|
//appImManager.topbar.parentElement.insertBefore(this.results, appImManager.bubblesContainer);
|
||||||
|
appImManager.bubblesContainer.append(this.results);
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
this.footer = document.createElement('div');
|
||||||
|
this.footer.classList.add('chat-search-footer');
|
||||||
|
|
||||||
|
this.footer.addEventListener('click', this.onFooterClick);
|
||||||
|
ripple(this.footer);
|
||||||
|
|
||||||
|
this.foundCountEl = document.createElement('span');
|
||||||
|
this.foundCountEl.classList.add('chat-search-count');
|
||||||
|
|
||||||
|
this.dateBtn = document.createElement('button');
|
||||||
|
this.dateBtn.classList.add('btn-icon', 'tgico-calendar');
|
||||||
|
|
||||||
|
this.controls = document.createElement('div');
|
||||||
|
this.controls.classList.add('chat-search-controls');
|
||||||
|
|
||||||
|
this.upBtn = document.createElement('button');
|
||||||
|
this.upBtn.classList.add('btn-icon', 'tgico-up');
|
||||||
|
this.downBtn = document.createElement('button');
|
||||||
|
this.downBtn.classList.add('btn-icon', 'tgico-down');
|
||||||
|
|
||||||
|
this.upBtn.setAttribute('disabled', 'true');
|
||||||
|
this.downBtn.setAttribute('disabled', 'true');
|
||||||
|
|
||||||
|
this.dateBtn.addEventListener('click', this.onDateClick);
|
||||||
|
this.upBtn.addEventListener('click', this.onUpClick);
|
||||||
|
this.downBtn.addEventListener('click', this.onDownClick);
|
||||||
|
this.controls.append(this.upBtn, this.downBtn);
|
||||||
|
|
||||||
|
this.footer.append(this.foundCountEl, this.dateBtn, this.controls);
|
||||||
|
|
||||||
|
appImManager.topbar.parentElement.insertBefore(this.footer, appImManager.chatInput);
|
||||||
|
|
||||||
|
// Append container
|
||||||
|
this.element.append(this.backBtn, this.searchInput.container);
|
||||||
|
|
||||||
|
appImManager.topbar.classList.add('hide-pinned');
|
||||||
|
appImManager.topbar.parentElement.append(this.element);
|
||||||
|
|
||||||
|
this.searchInput.input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
onDateClick = (e: MouseEvent) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
new PopupDatePicker(new Date(), appImManager.onDatePick).show();
|
||||||
|
};
|
||||||
|
|
||||||
|
selectResult = (elem: HTMLElement) => {
|
||||||
|
if(this.setPeerPromise) return this.setPeerPromise;
|
||||||
|
|
||||||
|
const peerID = +elem.getAttribute('data-peerID');
|
||||||
|
const lastMsgID = +elem.dataset.mid || undefined;
|
||||||
|
|
||||||
|
const index = whichChild(elem);
|
||||||
|
|
||||||
|
if(index == (this.foundCount - 1)) {
|
||||||
|
this.upBtn.setAttribute('disabled', 'true');
|
||||||
|
} else {
|
||||||
|
this.upBtn.removeAttribute('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!index) {
|
||||||
|
this.downBtn.setAttribute('disabled', 'true');
|
||||||
|
} else {
|
||||||
|
this.downBtn.removeAttribute('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.results.classList.remove('active');
|
||||||
|
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||||
|
|
||||||
|
const res = appImManager.setPeer(peerID, lastMsgID);
|
||||||
|
this.setPeerPromise = (res instanceof Promise ? res : Promise.resolve(res)).then(() => {
|
||||||
|
this.selectedIndex = index;
|
||||||
|
this.foundCountEl.innerText = `${index + 1} of ${this.foundCount}`;
|
||||||
|
|
||||||
|
const renderedCount = this.searchGroup.list.childElementCount;
|
||||||
|
if(this.selectedIndex >= (renderedCount - 6)) {
|
||||||
|
this.appSearch.searchMore();
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.setPeerPromise = null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onResultsClick = (e: MouseEvent) => {
|
||||||
|
const target = findUpTag(e.target, 'LI');
|
||||||
|
if(target) {
|
||||||
|
this.selectResult(target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onFooterClick = (e: MouseEvent) => {
|
||||||
|
if(this.foundCount) {
|
||||||
|
appImManager.bubblesContainer.classList.toggle('search-results-active');
|
||||||
|
this.results.classList.toggle('active');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onUpClick = (e: MouseEvent) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
this.selectResult(this.searchGroup.list.children[this.selectedIndex + 1] as HTMLElement);
|
||||||
|
};
|
||||||
|
|
||||||
|
onDownClick = (e: MouseEvent) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
this.selectResult(this.searchGroup.list.children[this.selectedIndex - 1] as HTMLElement);
|
||||||
|
};
|
||||||
|
}
|
3
src/global.d.ts
vendored
3
src/global.d.ts
vendored
@ -5,6 +5,3 @@ declare module 'worker-loader!*' {
|
|||||||
|
|
||||||
export default WebpackWorker;
|
export default WebpackWorker;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare function setInterval(callback: (...args: any[]) => void, ms: number): number;
|
|
||||||
declare function setTimeout(callback: (...args: any[]) => void, ms: number): number;
|
|
9
src/layer.d.ts
vendored
9
src/layer.d.ts
vendored
@ -1076,7 +1076,9 @@ export namespace Dialog {
|
|||||||
notify_settings: PeerNotifySettings,
|
notify_settings: PeerNotifySettings,
|
||||||
pts?: number,
|
pts?: number,
|
||||||
draft?: DraftMessage,
|
draft?: DraftMessage,
|
||||||
folder_id?: number
|
folder_id?: number,
|
||||||
|
index?: number,
|
||||||
|
peerID?: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type dialogFolder = {
|
export type dialogFolder = {
|
||||||
@ -1091,7 +1093,10 @@ export namespace Dialog {
|
|||||||
unread_muted_peers_count: number,
|
unread_muted_peers_count: number,
|
||||||
unread_unmuted_peers_count: number,
|
unread_unmuted_peers_count: number,
|
||||||
unread_muted_messages_count: number,
|
unread_muted_messages_count: number,
|
||||||
unread_unmuted_messages_count: number
|
unread_unmuted_messages_count: number,
|
||||||
|
index?: number,
|
||||||
|
peerID?: number,
|
||||||
|
folder_id?: number
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,7 +733,7 @@ export class AppDialogsManager {
|
|||||||
this.setListClickListener(ul, null, true);
|
this.setListClickListener(ul, null, true);
|
||||||
|
|
||||||
if(!this.showFiltersTimeout) {
|
if(!this.showFiltersTimeout) {
|
||||||
this.showFiltersTimeout = setTimeout(() => {
|
this.showFiltersTimeout = window.setTimeout(() => {
|
||||||
this.showFiltersTimeout = 0;
|
this.showFiltersTimeout = 0;
|
||||||
this.folders.menuScrollContainer.classList.remove('hide');
|
this.folders.menuScrollContainer.classList.remove('hide');
|
||||||
this.setFiltersUnreadCount();
|
this.setFiltersUnreadCount();
|
||||||
@ -1086,7 +1086,7 @@ export class AppDialogsManager {
|
|||||||
|
|
||||||
public accumulateArchivedUnread() {
|
public accumulateArchivedUnread() {
|
||||||
if(this.accumulateArchivedTimeout) return;
|
if(this.accumulateArchivedTimeout) return;
|
||||||
this.accumulateArchivedTimeout = setTimeout(() => {
|
this.accumulateArchivedTimeout = window.setTimeout(() => {
|
||||||
this.accumulateArchivedTimeout = 0;
|
this.accumulateArchivedTimeout = 0;
|
||||||
const dialogs = appMessagesManager.dialogsStorage.getFolder(1);
|
const dialogs = appMessagesManager.dialogsStorage.getFolder(1);
|
||||||
const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);
|
const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);
|
||||||
|
@ -14,10 +14,10 @@ import { logger, LogLevels } from "../logger";
|
|||||||
import appMediaViewer from "./appMediaViewer";
|
import appMediaViewer from "./appMediaViewer";
|
||||||
import appSidebarLeft from "./appSidebarLeft";
|
import appSidebarLeft from "./appSidebarLeft";
|
||||||
import appChatsManager, { Channel, Chat } from "./appChatsManager";
|
import appChatsManager, { Channel, Chat } from "./appChatsManager";
|
||||||
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum, wrapPoll, formatDate } 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, parseMenuButtonsTo, attachContextMenuListener } from '../../components/misc';
|
import { formatPhoneNumber, parseMenuButtonsTo } from '../../components/misc';
|
||||||
import { ChatInput } from '../../components/chatInput';
|
import { ChatInput } from '../../components/chat/input';
|
||||||
//import Scrollable from '../../components/scrollable';
|
//import Scrollable from '../../components/scrollable';
|
||||||
import Scrollable from '../../components/scrollable_new';
|
import Scrollable from '../../components/scrollable_new';
|
||||||
import BubbleGroups from '../../components/bubbleGroups';
|
import BubbleGroups from '../../components/bubbleGroups';
|
||||||
@ -28,19 +28,18 @@ 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 { PopupButton, PopupPeer } from '../../components/popup';
|
|
||||||
import { mediaSizes, touchSupport, isAndroid, isApple } from '../config';
|
import { mediaSizes, touchSupport, isAndroid, isApple } from '../config';
|
||||||
import animationIntersector from '../../components/animationIntersector';
|
import animationIntersector from '../../components/animationIntersector';
|
||||||
import PopupStickers from '../../components/popupStickers';
|
import PopupStickers from '../../components/popupStickers';
|
||||||
import SearchInput from '../../components/searchInput';
|
|
||||||
import AppSearch, { SearchGroup } from '../../components/appSearch';
|
|
||||||
import PopupDatePicker from '../../components/popupDatepicker';
|
import PopupDatePicker from '../../components/popupDatepicker';
|
||||||
import appMediaPlaybackController from '../../components/appMediaPlaybackController';
|
|
||||||
import appPollsManager from './appPollsManager';
|
import appPollsManager from './appPollsManager';
|
||||||
import { ripple } from '../../components/ripple';
|
import { ripple } from '../../components/ripple';
|
||||||
import { horizontalMenu } from '../../components/horizontalMenu';
|
import { horizontalMenu } from '../../components/horizontalMenu';
|
||||||
import AudioElement from '../../components/audio';
|
import AudioElement from '../../components/audio';
|
||||||
import { InputNotifyPeer, InputPeerNotifySettings } from '../../layer';
|
import { InputNotifyPeer, InputPeerNotifySettings } from '../../layer';
|
||||||
|
import { ChatAudio } from '../../components/chat/audio';
|
||||||
|
import { ChatContextMenu } from '../../components/chat/contextMenu';
|
||||||
|
import { ChatSearch } from '../../components/chat/search';
|
||||||
|
|
||||||
//console.log('appImManager included33!');
|
//console.log('appImManager included33!');
|
||||||
|
|
||||||
@ -50,419 +49,6 @@ const testScroll = false;
|
|||||||
|
|
||||||
const ANIMATIONGROUP = 'chat';
|
const ANIMATIONGROUP = 'chat';
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
attachContextMenuListener(attachTo, (e) => {
|
|
||||||
let bubble: HTMLElement = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
bubble = findUpClassName(e.target, 'bubble__container');
|
|
||||||
} catch(e) {}
|
|
||||||
|
|
||||||
if(!bubble) return;
|
|
||||||
|
|
||||||
if(e instanceof MouseEvent) e.preventDefault();
|
|
||||||
if(this.element.classList.contains('active')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(e instanceof MouseEvent) 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: PopupButton[];
|
|
||||||
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', () => {
|
|
||||||
appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, this.msgID);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatSearch {
|
|
||||||
private element: HTMLElement;
|
|
||||||
private backBtn: HTMLElement;
|
|
||||||
private searchInput: SearchInput;
|
|
||||||
|
|
||||||
private results: HTMLElement;
|
|
||||||
|
|
||||||
private footer: HTMLElement;
|
|
||||||
private dateBtn: HTMLElement;
|
|
||||||
private foundCountEl: HTMLElement;
|
|
||||||
private controls: HTMLElement;
|
|
||||||
private downBtn: HTMLElement;
|
|
||||||
private upBtn: HTMLElement;
|
|
||||||
|
|
||||||
private appSearch: AppSearch;
|
|
||||||
private searchGroup: SearchGroup;
|
|
||||||
|
|
||||||
private foundCount = 0;
|
|
||||||
private selectedIndex = 0;
|
|
||||||
private setPeerPromise: Promise<any>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.element = document.createElement('div');
|
|
||||||
this.element.classList.add('sidebar-header', 'chat-search', 'chats-container');
|
|
||||||
|
|
||||||
this.backBtn = document.createElement('button');
|
|
||||||
this.backBtn.classList.add('btn-icon', 'tgico-back', 'sidebar-close-button');
|
|
||||||
ripple(this.backBtn);
|
|
||||||
|
|
||||||
this.backBtn.addEventListener('click', () => {
|
|
||||||
appImManager.topbar.classList.remove('hide-pinned');
|
|
||||||
this.element.remove();
|
|
||||||
this.searchInput.remove();
|
|
||||||
this.results.remove();
|
|
||||||
this.footer.remove();
|
|
||||||
this.footer.removeEventListener('click', this.onFooterClick);
|
|
||||||
this.dateBtn.removeEventListener('click', this.onDateClick);
|
|
||||||
this.upBtn.removeEventListener('click', this.onUpClick);
|
|
||||||
this.downBtn.removeEventListener('click', this.onDownClick);
|
|
||||||
this.searchGroup.list.removeEventListener('click', this.onResultsClick);
|
|
||||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
|
||||||
}, {once: true});
|
|
||||||
|
|
||||||
this.searchInput = new SearchInput('Search');
|
|
||||||
|
|
||||||
// Results
|
|
||||||
this.results = document.createElement('div');
|
|
||||||
this.results.classList.add('chat-search-results', 'chats-container');
|
|
||||||
|
|
||||||
this.searchGroup = new SearchGroup('', 'messages', undefined, '', false);
|
|
||||||
this.searchGroup.list.addEventListener('click', this.onResultsClick);
|
|
||||||
|
|
||||||
this.appSearch = new AppSearch(this.results, this.searchInput, {
|
|
||||||
messages: this.searchGroup
|
|
||||||
}, (count) => {
|
|
||||||
this.foundCount = count;
|
|
||||||
|
|
||||||
if(!this.foundCount) {
|
|
||||||
this.foundCountEl.innerText = this.searchInput.value ? 'No results' : '';
|
|
||||||
this.results.classList.remove('active');
|
|
||||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
|
||||||
this.upBtn.setAttribute('disabled', 'true');
|
|
||||||
this.downBtn.setAttribute('disabled', 'true');
|
|
||||||
} else {
|
|
||||||
this.selectResult(this.searchGroup.list.children[0] as HTMLElement);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.appSearch.beginSearch($rootScope.selectedPeerID);
|
|
||||||
|
|
||||||
//appImManager.topbar.parentElement.insertBefore(this.results, appImManager.bubblesContainer);
|
|
||||||
appImManager.bubblesContainer.append(this.results);
|
|
||||||
|
|
||||||
// Footer
|
|
||||||
this.footer = document.createElement('div');
|
|
||||||
this.footer.classList.add('chat-search-footer');
|
|
||||||
|
|
||||||
this.footer.addEventListener('click', this.onFooterClick);
|
|
||||||
ripple(this.footer);
|
|
||||||
|
|
||||||
this.foundCountEl = document.createElement('span');
|
|
||||||
this.foundCountEl.classList.add('chat-search-count');
|
|
||||||
|
|
||||||
this.dateBtn = document.createElement('button');
|
|
||||||
this.dateBtn.classList.add('btn-icon', 'tgico-calendar');
|
|
||||||
|
|
||||||
this.controls = document.createElement('div');
|
|
||||||
this.controls.classList.add('chat-search-controls');
|
|
||||||
|
|
||||||
this.upBtn = document.createElement('button');
|
|
||||||
this.upBtn.classList.add('btn-icon', 'tgico-up');
|
|
||||||
this.downBtn = document.createElement('button');
|
|
||||||
this.downBtn.classList.add('btn-icon', 'tgico-down');
|
|
||||||
|
|
||||||
this.upBtn.setAttribute('disabled', 'true');
|
|
||||||
this.downBtn.setAttribute('disabled', 'true');
|
|
||||||
|
|
||||||
this.dateBtn.addEventListener('click', this.onDateClick);
|
|
||||||
this.upBtn.addEventListener('click', this.onUpClick);
|
|
||||||
this.downBtn.addEventListener('click', this.onDownClick);
|
|
||||||
this.controls.append(this.upBtn, this.downBtn);
|
|
||||||
|
|
||||||
this.footer.append(this.foundCountEl, this.dateBtn, this.controls);
|
|
||||||
|
|
||||||
appImManager.topbar.parentElement.insertBefore(this.footer, appImManager.chatInput);
|
|
||||||
|
|
||||||
// Append container
|
|
||||||
this.element.append(this.backBtn, this.searchInput.container);
|
|
||||||
|
|
||||||
appImManager.topbar.classList.add('hide-pinned');
|
|
||||||
appImManager.topbar.parentElement.append(this.element);
|
|
||||||
|
|
||||||
this.searchInput.input.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
onDateClick = (e: MouseEvent) => {
|
|
||||||
cancelEvent(e);
|
|
||||||
new PopupDatePicker(new Date(), appImManager.onDatePick).show();
|
|
||||||
};
|
|
||||||
|
|
||||||
selectResult = (elem: HTMLElement) => {
|
|
||||||
if(this.setPeerPromise) return this.setPeerPromise;
|
|
||||||
|
|
||||||
const peerID = +elem.getAttribute('data-peerID');
|
|
||||||
const lastMsgID = +elem.dataset.mid || undefined;
|
|
||||||
|
|
||||||
const index = whichChild(elem);
|
|
||||||
|
|
||||||
if(index == (this.foundCount - 1)) {
|
|
||||||
this.upBtn.setAttribute('disabled', 'true');
|
|
||||||
} else {
|
|
||||||
this.upBtn.removeAttribute('disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!index) {
|
|
||||||
this.downBtn.setAttribute('disabled', 'true');
|
|
||||||
} else {
|
|
||||||
this.downBtn.removeAttribute('disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.results.classList.remove('active');
|
|
||||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
|
||||||
|
|
||||||
const res = appImManager.setPeer(peerID, lastMsgID);
|
|
||||||
this.setPeerPromise = (res instanceof Promise ? res : Promise.resolve(res)).then(() => {
|
|
||||||
this.selectedIndex = index;
|
|
||||||
this.foundCountEl.innerText = `${index + 1} of ${this.foundCount}`;
|
|
||||||
|
|
||||||
const renderedCount = this.searchGroup.list.childElementCount;
|
|
||||||
if(this.selectedIndex >= (renderedCount - 6)) {
|
|
||||||
this.appSearch.searchMore();
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
this.setPeerPromise = null;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onResultsClick = (e: MouseEvent) => {
|
|
||||||
const target = findUpTag(e.target, 'LI');
|
|
||||||
if(target) {
|
|
||||||
this.selectResult(target);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onFooterClick = (e: MouseEvent) => {
|
|
||||||
if(this.foundCount) {
|
|
||||||
appImManager.bubblesContainer.classList.toggle('search-results-active');
|
|
||||||
this.results.classList.toggle('active');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onUpClick = (e: MouseEvent) => {
|
|
||||||
cancelEvent(e);
|
|
||||||
this.selectResult(this.searchGroup.list.children[this.selectedIndex + 1] as HTMLElement);
|
|
||||||
};
|
|
||||||
|
|
||||||
onDownClick = (e: MouseEvent) => {
|
|
||||||
cancelEvent(e);
|
|
||||||
this.selectResult(this.searchGroup.list.children[this.selectedIndex - 1] as HTMLElement);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatAudio {
|
|
||||||
public container: HTMLElement;
|
|
||||||
private toggle: HTMLElement;
|
|
||||||
private title: HTMLElement;
|
|
||||||
private subtitle: HTMLElement;
|
|
||||||
private close: HTMLElement;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.container = document.createElement('div');
|
|
||||||
this.container.classList.add('pinned-audio', 'pinned-container');
|
|
||||||
this.container.style.display = 'none';
|
|
||||||
|
|
||||||
this.toggle = document.createElement('div');
|
|
||||||
this.toggle.classList.add('pinned-audio-ico', 'tgico');
|
|
||||||
|
|
||||||
this.title = document.createElement('div');
|
|
||||||
this.title.classList.add('pinned-audio-title');
|
|
||||||
|
|
||||||
this.subtitle = document.createElement('div');
|
|
||||||
this.subtitle.classList.add('pinned-audio-subtitle');
|
|
||||||
|
|
||||||
this.close = document.createElement('button');
|
|
||||||
this.close.classList.add('pinned-audio-close', 'btn-icon', 'tgico-close');
|
|
||||||
|
|
||||||
this.container.append(this.toggle, this.title, this.subtitle, this.close);
|
|
||||||
|
|
||||||
this.close.addEventListener('click', (e) => {
|
|
||||||
cancelEvent(e);
|
|
||||||
this.container.style.display = 'none';
|
|
||||||
this.container.parentElement.classList.remove('is-audio-shown');
|
|
||||||
if(this.toggle.classList.contains('flip-icon')) {
|
|
||||||
appMediaPlaybackController.toggle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.toggle.addEventListener('click', (e) => {
|
|
||||||
cancelEvent(e);
|
|
||||||
appMediaPlaybackController.toggle();
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootScope.$on('audio_play', (e: CustomEvent) => {
|
|
||||||
const {doc, mid} = e.detail;
|
|
||||||
|
|
||||||
let title: string, subtitle: string;
|
|
||||||
if(doc.type == 'voice' || doc.type == 'round') {
|
|
||||||
const message = appMessagesManager.getMessage(mid);
|
|
||||||
title = appPeersManager.getPeerTitle(message.fromID, false, true);
|
|
||||||
//subtitle = 'Voice message';
|
|
||||||
subtitle = formatDate(message.date, false, false);
|
|
||||||
} else {
|
|
||||||
title = doc.audioTitle || doc.file_name;
|
|
||||||
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.title.innerHTML = title;
|
|
||||||
this.subtitle.innerHTML = subtitle;
|
|
||||||
this.toggle.classList.add('flip-icon');
|
|
||||||
|
|
||||||
this.container.dataset.mid = '' + mid;
|
|
||||||
if(this.container.style.display) {
|
|
||||||
const scrollTop = appImManager.scrollable.scrollTop;
|
|
||||||
this.container.style.display = '';
|
|
||||||
this.container.parentElement.classList.add('is-audio-shown');
|
|
||||||
appImManager.scrollable.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootScope.$on('audio_pause', () => {
|
|
||||||
this.toggle.classList.remove('flip-icon');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AppImManager {
|
export class AppImManager {
|
||||||
public columnEl = document.getElementById('column-center') as HTMLDivElement;
|
public columnEl = document.getElementById('column-center') as HTMLDivElement;
|
||||||
public btnJoin = this.columnEl.querySelector('.chat-join') as HTMLButtonElement;
|
public btnJoin = this.columnEl.querySelector('.chat-join') as HTMLButtonElement;
|
||||||
@ -651,14 +237,14 @@ export class AppImManager {
|
|||||||
if(message.media) {
|
if(message.media) {
|
||||||
if(message.media.photo) {
|
if(message.media.photo) {
|
||||||
const photo = appPhotosManager.getPhoto(tempID);
|
const photo = appPhotosManager.getPhoto(tempID);
|
||||||
//if(photo._ != 'photoEmpty') {
|
if(/* photo._ != 'photoEmpty' */photo) {
|
||||||
const newPhoto = message.media.photo;
|
const newPhoto = message.media.photo;
|
||||||
newPhoto.downloaded = photo.downloaded;
|
newPhoto.downloaded = photo.downloaded;
|
||||||
newPhoto.url = photo.url;
|
newPhoto.url = photo.url;
|
||||||
//}
|
}
|
||||||
} else if(message.media.document) {
|
} else if(message.media.document) {
|
||||||
const doc = appDocsManager.getDoc(tempID);
|
const doc = appDocsManager.getDoc(tempID);
|
||||||
if(/* doc._ != 'documentEmpty' && */doc.type && doc.type != 'sticker') {
|
if(/* doc._ != 'documentEmpty' && */doc?.type && doc.type != 'sticker') {
|
||||||
const newDoc = message.media.document;
|
const newDoc = message.media.document;
|
||||||
newDoc.downloaded = doc.downloaded;
|
newDoc.downloaded = doc.downloaded;
|
||||||
newDoc.url = doc.url;
|
newDoc.url = doc.url;
|
||||||
@ -1223,7 +809,7 @@ export class AppImManager {
|
|||||||
this.chatInner.classList.add('is-scrolling');
|
this.chatInner.classList.add('is-scrolling');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isScrollingTimeout = setTimeout(() => {
|
this.isScrollingTimeout = window.setTimeout(() => {
|
||||||
this.chatInner.classList.remove('is-scrolling');
|
this.chatInner.classList.remove('is-scrolling');
|
||||||
this.isScrollingTimeout = 0;
|
this.isScrollingTimeout = 0;
|
||||||
}, 1350);
|
}, 1350);
|
||||||
@ -1283,7 +869,7 @@ export class AppImManager {
|
|||||||
clearTimeout(this.isScrollingTimeout);
|
clearTimeout(this.isScrollingTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isScrollingTimeout = setTimeout(() => {
|
this.isScrollingTimeout = window.setTimeout(() => {
|
||||||
this.chatInner.classList.remove('is-scrolling');
|
this.chatInner.classList.remove('is-scrolling');
|
||||||
this.isScrollingTimeout = 0;
|
this.isScrollingTimeout = 0;
|
||||||
}, 1350);
|
}, 1350);
|
||||||
@ -3035,7 +2621,7 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.typingTimeouts[peerID] = setTimeout(() => {
|
this.typingTimeouts[peerID] = window.setTimeout(() => {
|
||||||
this.typingTimeouts[peerID] = 0;
|
this.typingTimeouts[peerID] = 0;
|
||||||
delete this.typingUsers[update.user_id];
|
delete this.typingUsers[update.user_id];
|
||||||
|
|
||||||
|
@ -24,9 +24,10 @@ import { Modify } from "../../types";
|
|||||||
import { logger, LogLevels } from "../logger";
|
import { logger, LogLevels } from "../logger";
|
||||||
import type {ApiFileManager} from '../mtproto/apiFileManager';
|
import type {ApiFileManager} from '../mtproto/apiFileManager';
|
||||||
import appDownloadManager from "./appDownloadManager";
|
import appDownloadManager from "./appDownloadManager";
|
||||||
import { DialogFilter, InputDialogPeer, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize } from "../../layer";
|
import { DialogFilter, InputDialogPeer, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize, DocumentAttribute, Dialog as MTDialog, MessagesDialogs, MessagesPeerDialogs } from "../../layer";
|
||||||
|
|
||||||
//console.trace('include');
|
//console.trace('include');
|
||||||
|
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
|
||||||
|
|
||||||
const APITIMEOUT = 0;
|
const APITIMEOUT = 0;
|
||||||
|
|
||||||
@ -47,27 +48,7 @@ export type HistoryResult = {
|
|||||||
unreadSkip: boolean
|
unreadSkip: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Dialog = {
|
export type Dialog = MTDialog.dialog;
|
||||||
_: 'dialog',
|
|
||||||
top_message: number,
|
|
||||||
read_inbox_max_id: number,
|
|
||||||
read_outbox_max_id: number,
|
|
||||||
peer: any,
|
|
||||||
notify_settings: any,
|
|
||||||
folder_id: number,
|
|
||||||
flags: number,
|
|
||||||
draft: any,
|
|
||||||
unread_count: number,
|
|
||||||
unread_mentions_count: number,
|
|
||||||
|
|
||||||
index: number,
|
|
||||||
peerID: number,
|
|
||||||
pFlags: Partial<{
|
|
||||||
pinned: true,
|
|
||||||
unread_mark: true
|
|
||||||
}>,
|
|
||||||
pts: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DialogsStorage {
|
export class DialogsStorage {
|
||||||
public dialogs: {[peerID: string]: Dialog} = {};
|
public dialogs: {[peerID: string]: Dialog} = {};
|
||||||
@ -487,7 +468,7 @@ export class AppMessagesManager {
|
|||||||
public pendingByRandomID: {[randomID: string]: [number, number]} = {};
|
public pendingByRandomID: {[randomID: string]: [number, number]} = {};
|
||||||
public pendingByMessageID: any = {};
|
public pendingByMessageID: any = {};
|
||||||
public pendingAfterMsgs: any = {};
|
public pendingAfterMsgs: any = {};
|
||||||
public pendingTopMsgs: any = {};
|
public pendingTopMsgs: {[peerID: string]: number} = {};
|
||||||
public sendFilePromise: CancellablePromise<void> = Promise.resolve();
|
public sendFilePromise: CancellablePromise<void> = Promise.resolve();
|
||||||
public tempID = -1;
|
public tempID = -1;
|
||||||
public tempFinalizeCallbacks: any = {};
|
public tempFinalizeCallbacks: any = {};
|
||||||
@ -1009,7 +990,7 @@ export class AppMessagesManager {
|
|||||||
attributes.push({_: 'documentAttributeFilename', file_name: fileName || apiFileName});
|
attributes.push({_: 'documentAttributeFilename', file_name: fileName || apiFileName});
|
||||||
|
|
||||||
if(['document', 'video', 'audio', 'voice'].indexOf(attachType) !== -1 && !isDocument) {
|
if(['document', 'video', 'audio', 'voice'].indexOf(attachType) !== -1 && !isDocument) {
|
||||||
let doc: any = {
|
let doc: MyDocument = {
|
||||||
_: 'document',
|
_: 'document',
|
||||||
id: '' + messageID,
|
id: '' + messageID,
|
||||||
duration: options.duration,
|
duration: options.duration,
|
||||||
@ -1021,7 +1002,7 @@ export class AppMessagesManager {
|
|||||||
mime_type: fileType,
|
mime_type: fileType,
|
||||||
url: options.objectURL || '',
|
url: options.objectURL || '',
|
||||||
size: file.size
|
size: file.size
|
||||||
};
|
} as any;
|
||||||
|
|
||||||
appDocsManager.saveDoc(doc);
|
appDocsManager.saveDoc(doc);
|
||||||
}
|
}
|
||||||
@ -1297,21 +1278,18 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
if(file.type.indexOf('video/') === 0) {
|
if(file.type.indexOf('video/') === 0) {
|
||||||
let flags = 1;
|
let flags = 1;
|
||||||
let videoAttribute = {
|
let videoAttribute: DocumentAttribute.documentAttributeVideo = {
|
||||||
_: 'documentAttributeVideo',
|
_: 'documentAttributeVideo',
|
||||||
flags: flags,
|
flags: flags,
|
||||||
pFlags: { // that's only for client, not going to telegram
|
pFlags: { // that's only for client, not going to telegram
|
||||||
supports_streaming: true,
|
supports_streaming: true
|
||||||
round_message: false
|
},
|
||||||
},
|
|
||||||
round_message: false,
|
|
||||||
supports_streaming: true,
|
|
||||||
duration: details.duration,
|
duration: details.duration,
|
||||||
w: details.width,
|
w: details.width,
|
||||||
h: details.height
|
h: details.height
|
||||||
};
|
};
|
||||||
|
|
||||||
let doc: any = {
|
let doc: MyDocument = {
|
||||||
_: 'document',
|
_: 'document',
|
||||||
id: '' + messageID,
|
id: '' + messageID,
|
||||||
attributes: [videoAttribute],
|
attributes: [videoAttribute],
|
||||||
@ -1320,7 +1298,7 @@ export class AppMessagesManager {
|
|||||||
mime_type: file.type,
|
mime_type: file.type,
|
||||||
url: details.objectURL || '',
|
url: details.objectURL || '',
|
||||||
size: file.size
|
size: file.size
|
||||||
};
|
} as any;
|
||||||
|
|
||||||
appDocsManager.saveDoc(doc);
|
appDocsManager.saveDoc(doc);
|
||||||
media.document = doc;
|
media.document = doc;
|
||||||
@ -1894,9 +1872,11 @@ export class AppMessagesManager {
|
|||||||
hash: 0
|
hash: 0
|
||||||
}, {
|
}, {
|
||||||
timeout: APITIMEOUT
|
timeout: APITIMEOUT
|
||||||
}).then((dialogsResult: any) => {
|
}).then((dialogsResult) => {
|
||||||
///////this.log('messages.getDialogs result:', dialogsResult);
|
///////this.log('messages.getDialogs result:', dialogsResult);
|
||||||
|
|
||||||
|
if(dialogsResult._ == 'messages.dialogsNotModified') return null;
|
||||||
|
|
||||||
if(!offsetDate) {
|
if(!offsetDate) {
|
||||||
telegramMeWebService.setAuthorized(true);
|
telegramMeWebService.setAuthorized(true);
|
||||||
}
|
}
|
||||||
@ -1905,21 +1885,31 @@ export class AppMessagesManager {
|
|||||||
appChatsManager.saveApiChats(dialogsResult.chats);
|
appChatsManager.saveApiChats(dialogsResult.chats);
|
||||||
this.saveMessages(dialogsResult.messages);
|
this.saveMessages(dialogsResult.messages);
|
||||||
|
|
||||||
var maxSeenIdIncremented = offsetDate ? true : false;
|
let maxSeenIdIncremented = offsetDate ? true : false;
|
||||||
var hasPrepend = false;
|
let hasPrepend = false;
|
||||||
let length = dialogsResult.dialogs.length;
|
let noIDsDialogs: {[peerID: number]: Dialog} = {};
|
||||||
let noIDsDialogs: any = {};
|
(dialogsResult.dialogs as Dialog[]).forEachReverse(dialog => {
|
||||||
for(let i = length - 1; i >= 0; --i) {
|
//const d = Object.assign({}, dialog);
|
||||||
let dialog = dialogsResult.dialogs[i];
|
// ! нужно передавать folderID, так как по папке != 0 нет свойства folder_id
|
||||||
|
this.saveConversation(dialog, folderID);
|
||||||
|
|
||||||
|
/* if(dialog.peerID == 239602833) {
|
||||||
|
this.log.error('lun bot', folderID, d);
|
||||||
|
} */
|
||||||
|
|
||||||
this.saveConversation(dialog);
|
|
||||||
if(offsetIndex && dialog.index > offsetIndex) {
|
if(offsetIndex && dialog.index > offsetIndex) {
|
||||||
this.newDialogsToHandle[dialog.peerID] = dialog;
|
this.newDialogsToHandle[dialog.peerID] = dialog;
|
||||||
hasPrepend = true;
|
hasPrepend = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ! это может случиться, если запрос идёт не по папке 0, а по 1. почему-то read'ов нет
|
||||||
|
// ! в итоге, чтобы получить 1 диалог, делается первый запрос по папке 0, потом запрос для архивных по папке 1, и потом ещё перезагрузка архивного диалога
|
||||||
if(!dialog.read_inbox_max_id && !dialog.read_outbox_max_id) {
|
if(!dialog.read_inbox_max_id && !dialog.read_outbox_max_id) {
|
||||||
noIDsDialogs[dialog.peerID] = dialog;
|
noIDsDialogs[dialog.peerID] = dialog;
|
||||||
|
|
||||||
|
/* if(dialog.peerID == 239602833) {
|
||||||
|
this.log.error('lun bot', folderID);
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!maxSeenIdIncremented &&
|
if(!maxSeenIdIncremented &&
|
||||||
@ -1927,7 +1917,7 @@ export class AppMessagesManager {
|
|||||||
this.incrementMaxSeenID(dialog.top_message);
|
this.incrementMaxSeenID(dialog.top_message);
|
||||||
maxSeenIdIncremented = true;
|
maxSeenIdIncremented = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if(Object.keys(noIDsDialogs).length) {
|
if(Object.keys(noIDsDialogs).length) {
|
||||||
//setTimeout(() => { // test bad situation
|
//setTimeout(() => { // test bad situation
|
||||||
@ -1941,9 +1931,11 @@ export class AppMessagesManager {
|
|||||||
//}, 10e3);
|
//}, 10e3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const count = (dialogsResult as MessagesDialogs.messagesDialogsSlice).count;
|
||||||
|
|
||||||
if(!dialogsResult.dialogs.length ||
|
if(!dialogsResult.dialogs.length ||
|
||||||
!dialogsResult.count ||
|
!count ||
|
||||||
dialogs.length >= dialogsResult.count) {
|
dialogs.length >= count) {
|
||||||
this.dialogsStorage.allDialogsLoaded[folderID] = true;
|
this.dialogsStorage.allDialogsLoaded[folderID] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1953,7 +1945,7 @@ export class AppMessagesManager {
|
|||||||
$rootScope.$broadcast('dialogs_multiupdate', {});
|
$rootScope.$broadcast('dialogs_multiupdate', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
return dialogsResult.count;
|
return count;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2115,11 +2107,11 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(justClear) {
|
if(justClear) {
|
||||||
$rootScope.$broadcast('dialog_flush', {peerID: peerID});
|
$rootScope.$broadcast('dialog_flush', {peerID});
|
||||||
} else {
|
} else {
|
||||||
this.dialogsStorage.dropDialog(peerID);
|
this.dialogsStorage.dropDialog(peerID);
|
||||||
|
|
||||||
$rootScope.$broadcast('dialog_drop', {peerID: peerID});
|
$rootScope.$broadcast('dialog_drop', {peerID});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2598,7 +2590,9 @@ export class AppMessagesManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public applyConversations(dialogsResult: any) {
|
public applyConversations(dialogsResult: MessagesPeerDialogs.messagesPeerDialogs) {
|
||||||
|
// * В эту функцию попадут только те диалоги, в которых есть read_inbox_max_id и read_outbox_max_id, в отличие от тех, что будут в getTopMessages
|
||||||
|
|
||||||
appUsersManager.saveApiUsers(dialogsResult.users);
|
appUsersManager.saveApiUsers(dialogsResult.users);
|
||||||
appChatsManager.saveApiChats(dialogsResult.chats);
|
appChatsManager.saveApiChats(dialogsResult.chats);
|
||||||
this.saveMessages(dialogsResult.messages);
|
this.saveMessages(dialogsResult.messages);
|
||||||
@ -2607,27 +2601,33 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
const updatedDialogs: {[peerID: number]: Dialog} = {};
|
const updatedDialogs: {[peerID: number]: Dialog} = {};
|
||||||
let hasUpdated = false;
|
let hasUpdated = false;
|
||||||
dialogsResult.dialogs.forEach((dialog: any) => {
|
(dialogsResult.dialogs as Dialog[]).forEach((dialog) => {
|
||||||
const peerID = appPeersManager.getPeerID(dialog.peer);
|
const peerID = appPeersManager.getPeerID(dialog.peer);
|
||||||
let topMessage = dialog.top_message;
|
let topMessage = dialog.top_message;
|
||||||
const topPendingMesage = this.pendingTopMsgs[peerID];
|
const topPendingMessage = this.pendingTopMsgs[peerID];
|
||||||
if(topPendingMesage) {
|
if(topPendingMessage) {
|
||||||
if(!topMessage || this.getMessage(topPendingMesage).date > this.getMessage(topMessage).date) {
|
if(!topMessage || this.getMessage(topPendingMessage).date > this.getMessage(topMessage).date) {
|
||||||
dialog.top_message = topMessage = topPendingMesage;
|
dialog.top_message = topMessage = topPendingMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* const d = Object.assign({}, dialog);
|
||||||
|
if(peerID == 239602833) {
|
||||||
|
this.log.error('applyConversation lun', dialog, d);
|
||||||
|
} */
|
||||||
|
|
||||||
if(topMessage) {
|
if(topMessage) {
|
||||||
const wasDialogBefore = this.getDialogByPeerID(peerID)[0];
|
const wasDialogBefore = this.getDialogByPeerID(peerID)[0];
|
||||||
|
|
||||||
// here need to just replace, not FULL replace dialog! WARNING
|
// here need to just replace, not FULL replace dialog! WARNING
|
||||||
if(wasDialogBefore && wasDialogBefore.pFlags && wasDialogBefore.pFlags.pinned) {
|
/* if(wasDialogBefore?.pFlags?.pinned && !dialog?.pFlags?.pinned) {
|
||||||
|
this.log.error('here need to just replace, not FULL replace dialog! WARNING', wasDialogBefore, dialog);
|
||||||
if(!dialog.pFlags) dialog.pFlags = {};
|
if(!dialog.pFlags) dialog.pFlags = {};
|
||||||
dialog.pFlags.pinned = true;
|
dialog.pFlags.pinned = true;
|
||||||
}
|
} */
|
||||||
|
|
||||||
this.saveConversation(dialog);
|
this.saveConversation(dialog);
|
||||||
|
|
||||||
if(wasDialogBefore) {
|
if(wasDialogBefore) {
|
||||||
$rootScope.$broadcast('dialog_top', dialog);
|
$rootScope.$broadcast('dialog_top', dialog);
|
||||||
} else {
|
} else {
|
||||||
@ -2656,11 +2656,16 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public saveConversation(dialog: Dialog) {
|
public saveConversation(dialog: Dialog, folderID = 0) {
|
||||||
const peerID = appPeersManager.getPeerID(dialog.peer);
|
const peerID = appPeersManager.getPeerID(dialog.peer);
|
||||||
if(!peerID) {
|
if(!peerID) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(dialog._ != 'dialog'/* || peerID == 239602833 */) {
|
||||||
|
console.error('saveConversation not regular dialog', dialog, Object.assign({}, dialog));
|
||||||
|
}
|
||||||
|
|
||||||
const channelID = appPeersManager.isChannel(peerID) ? -peerID : 0;
|
const channelID = appPeersManager.isChannel(peerID) ? -peerID : 0;
|
||||||
const peerText = appPeersManager.getPeerSearchText(peerID);
|
const peerText = appPeersManager.getPeerSearchText(peerID);
|
||||||
searchIndexManager.indexObject(peerID, peerText, this.dialogsIndex);
|
searchIndexManager.indexObject(peerID, peerText, this.dialogsIndex);
|
||||||
@ -2700,7 +2705,14 @@ export class AppMessagesManager {
|
|||||||
dialog.read_inbox_max_id = appMessagesIDsManager.getFullMessageID(dialog.read_inbox_max_id, channelID);
|
dialog.read_inbox_max_id = appMessagesIDsManager.getFullMessageID(dialog.read_inbox_max_id, channelID);
|
||||||
dialog.read_outbox_max_id = appMessagesIDsManager.getFullMessageID(dialog.read_outbox_max_id, channelID);
|
dialog.read_outbox_max_id = appMessagesIDsManager.getFullMessageID(dialog.read_outbox_max_id, channelID);
|
||||||
|
|
||||||
if(!dialog.hasOwnProperty('folder_id')) dialog.folder_id = 0;
|
if(!dialog.hasOwnProperty('folder_id')) {
|
||||||
|
if(dialog._ == 'dialog') {
|
||||||
|
dialog.folder_id = folderID;
|
||||||
|
}/* else if(dialog._ == 'dialogFolder') {
|
||||||
|
dialog.folder_id = dialog.folder.id;
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
dialog.peerID = peerID;
|
dialog.peerID = peerID;
|
||||||
|
|
||||||
this.dialogsStorage.generateIndexForDialog(dialog);
|
this.dialogsStorage.generateIndexForDialog(dialog);
|
||||||
@ -3057,7 +3069,7 @@ export class AppMessagesManager {
|
|||||||
this.incrementMaxSeenID(newMaxSeenID);
|
this.incrementMaxSeenID(newMaxSeenID);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rootScope.$broadcast('dialogs_multiupdate', this.newDialogsToHandle);
|
$rootScope.$broadcast('dialogs_multiupdate', this.newDialogsToHandle as any);
|
||||||
this.newDialogsToHandle = {};
|
this.newDialogsToHandle = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3502,7 +3514,7 @@ export class AppMessagesManager {
|
|||||||
if(!update.order) {
|
if(!update.order) {
|
||||||
apiManager.invokeApi('messages.getPinnedDialogs', {
|
apiManager.invokeApi('messages.getPinnedDialogs', {
|
||||||
folder_id: folderID
|
folder_id: folderID
|
||||||
}).then((dialogsResult: any) => {
|
}).then((dialogsResult) => {
|
||||||
dialogsResult.dialogs.reverse();
|
dialogsResult.dialogs.reverse();
|
||||||
this.applyConversations(dialogsResult);
|
this.applyConversations(dialogsResult);
|
||||||
|
|
||||||
@ -3750,8 +3762,9 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(historiesUpdated).forEach(peerID => {
|
Object.keys(historiesUpdated).forEach(_peerID => {
|
||||||
let updatedData = historiesUpdated[+peerID];
|
const peerID = +_peerID;
|
||||||
|
let updatedData = historiesUpdated[peerID];
|
||||||
let historyStorage = this.historiesStorage[peerID];
|
let historyStorage = this.historiesStorage[peerID];
|
||||||
if(historyStorage !== undefined) {
|
if(historyStorage !== undefined) {
|
||||||
let newHistory: number[] = [];
|
let newHistory: number[] = [];
|
||||||
@ -3778,22 +3791,22 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
historyStorage.pending = newPending;
|
historyStorage.pending = newPending;
|
||||||
|
|
||||||
$rootScope.$broadcast('history_delete', {peerID: peerID, msgs: updatedData.msgs});
|
$rootScope.$broadcast('history_delete', {peerID, msgs: updatedData.msgs});
|
||||||
}
|
}
|
||||||
|
|
||||||
let foundDialog = this.getDialogByPeerID(+peerID)[0];
|
let foundDialog = this.getDialogByPeerID(peerID)[0];
|
||||||
if(foundDialog) {
|
if(foundDialog) {
|
||||||
if(updatedData.unread) {
|
if(updatedData.unread) {
|
||||||
foundDialog.unread_count -= updatedData.unread;
|
foundDialog.unread_count -= updatedData.unread;
|
||||||
|
|
||||||
$rootScope.$broadcast('dialog_unread', {
|
$rootScope.$broadcast('dialog_unread', {
|
||||||
peerID: peerID,
|
peerID,
|
||||||
count: foundDialog.unread_count
|
count: foundDialog.unread_count
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(updatedData.msgs[foundDialog.top_message]) {
|
if(updatedData.msgs[foundDialog.top_message]) {
|
||||||
this.reloadConversation(+peerID);
|
this.reloadConversation(peerID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@ import appUsersManager from "./appUsersManager";
|
|||||||
import appChatsManager from "./appChatsManager";
|
import appChatsManager from "./appChatsManager";
|
||||||
import { isObject } from "../utils";
|
import { isObject } from "../utils";
|
||||||
import { RichTextProcessor } from "../richtextprocessor";
|
import { RichTextProcessor } from "../richtextprocessor";
|
||||||
import { InputPeer, InputDialogPeer } from "../../layer";
|
import { InputPeer, InputDialogPeer, Peer } from "../../layer";
|
||||||
|
|
||||||
// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC
|
// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC
|
||||||
/*
|
/*
|
||||||
@ -20,30 +20,30 @@ const DialogColorsFg = ['#c03d33', '#4fad2d', '#d09306', '#168acd', '#8544d6', '
|
|||||||
const DialogColors = ['#e17076', '#7bc862', '#e5ca77', '#65AADD', '#a695e7', '#ee7aae', '#6ec9cb', '#faa774'];
|
const DialogColors = ['#e17076', '#7bc862', '#e5ca77', '#65AADD', '#a695e7', '#ee7aae', '#6ec9cb', '#faa774'];
|
||||||
const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];
|
const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];
|
||||||
|
|
||||||
const AppPeersManager = {
|
export class AppPeersManager {
|
||||||
getPeerPhoto: (peerID: number) => {
|
public getPeerPhoto(peerID: number) {
|
||||||
return peerID > 0
|
return peerID > 0
|
||||||
? appUsersManager.getUserPhoto(peerID)
|
? appUsersManager.getUserPhoto(peerID)
|
||||||
: appChatsManager.getChatPhoto(-peerID);
|
: appChatsManager.getChatPhoto(-peerID);
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeerMigratedTo: (peerID: number) => {
|
public getPeerMigratedTo(peerID: number) {
|
||||||
if(peerID >= 0) {
|
if(peerID >= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let chat = appChatsManager.getChat(-peerID);
|
let chat = appChatsManager.getChat(-peerID);
|
||||||
if(chat && chat.migrated_to && chat.pFlags.deactivated) {
|
if(chat && chat.migrated_to && chat.pFlags.deactivated) {
|
||||||
return AppPeersManager.getPeerID(chat.migrated_to);
|
return this.getPeerID(chat.migrated_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeerTitle: (peerID: number | any, plainText = false, onlyFirstName = false) => {
|
public getPeerTitle(peerID: number | any, plainText = false, onlyFirstName = false) {
|
||||||
let peer: any = {};
|
let peer: any = {};
|
||||||
if(!isObject(peerID)) {
|
if(!isObject(peerID)) {
|
||||||
peer = AppPeersManager.getPeer(peerID);
|
peer = this.getPeer(peerID);
|
||||||
} else peer = peerID;
|
} else peer = peerID;
|
||||||
|
|
||||||
let title = '';
|
let title = '';
|
||||||
@ -62,9 +62,9 @@ const AppPeersManager = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return plainText ? title : RichTextProcessor.wrapEmojiText(title);
|
return plainText ? title : RichTextProcessor.wrapEmojiText(title);
|
||||||
},
|
}
|
||||||
|
|
||||||
getOutputPeer: (peerID: number) => {
|
public getOutputPeer(peerID: number): Peer {
|
||||||
if(peerID > 0) {
|
if(peerID > 0) {
|
||||||
return {_: 'peerUser', user_id: peerID};
|
return {_: 'peerUser', user_id: peerID};
|
||||||
}
|
}
|
||||||
@ -75,29 +75,29 @@ const AppPeersManager = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {_: 'peerChat', chat_id: chatID};
|
return {_: 'peerChat', chat_id: chatID};
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeerString: (peerID: number) => {
|
public getPeerString(peerID: number) {
|
||||||
if(peerID > 0) {
|
if(peerID > 0) {
|
||||||
return appUsersManager.getUserString(peerID);
|
return appUsersManager.getUserString(peerID);
|
||||||
}
|
}
|
||||||
return appChatsManager.getChatString(-peerID);
|
return appChatsManager.getChatString(-peerID);
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeerUsername: (peerID: number): string => {
|
public getPeerUsername(peerID: number): string {
|
||||||
if(peerID > 0) {
|
if(peerID > 0) {
|
||||||
return appUsersManager.getUser(peerID).username || '';
|
return appUsersManager.getUser(peerID).username || '';
|
||||||
}
|
}
|
||||||
return appChatsManager.getChat(-peerID).username || '';
|
return appChatsManager.getChat(-peerID).username || '';
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeer: (peerID: number) => {
|
public getPeer(peerID: number) {
|
||||||
return peerID > 0
|
return peerID > 0
|
||||||
? appUsersManager.getUser(peerID)
|
? appUsersManager.getUser(peerID)
|
||||||
: appChatsManager.getChat(-peerID)
|
: appChatsManager.getChat(-peerID)
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeerID: (peerString: any): number => {
|
public getPeerID(peerString: any): number {
|
||||||
if(typeof(peerString) === 'number') return peerString;
|
if(typeof(peerString) === 'number') return peerString;
|
||||||
else if(isObject(peerString)) {
|
else if(isObject(peerString)) {
|
||||||
return peerString.user_id
|
return peerString.user_id
|
||||||
@ -108,29 +108,29 @@ const AppPeersManager = {
|
|||||||
const peerParams = peerString.substr(1).split('_');
|
const peerParams = peerString.substr(1).split('_');
|
||||||
|
|
||||||
return isUser ? peerParams[0] : -peerParams[0] || 0;
|
return isUser ? peerParams[0] : -peerParams[0] || 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
isChannel: (peerID: number): boolean => {
|
public isChannel(peerID: number): boolean {
|
||||||
return (peerID < 0) && appChatsManager.isChannel(-peerID);
|
return (peerID < 0) && appChatsManager.isChannel(-peerID);
|
||||||
},
|
}
|
||||||
|
|
||||||
isMegagroup: (peerID: number) => {
|
public isMegagroup(peerID: number) {
|
||||||
return (peerID < 0) && appChatsManager.isMegagroup(-peerID);
|
return (peerID < 0) && appChatsManager.isMegagroup(-peerID);
|
||||||
},
|
}
|
||||||
|
|
||||||
isAnyGroup: (peerID: number): boolean => {
|
public isAnyGroup(peerID: number): boolean {
|
||||||
return (peerID < 0) && !appChatsManager.isBroadcast(-peerID);
|
return (peerID < 0) && !appChatsManager.isBroadcast(-peerID);
|
||||||
},
|
}
|
||||||
|
|
||||||
isBroadcast: (id: number): boolean => {
|
public isBroadcast(id: number): boolean {
|
||||||
return AppPeersManager.isChannel(id) && !AppPeersManager.isMegagroup(id);
|
return this.isChannel(id) && !this.isMegagroup(id);
|
||||||
},
|
}
|
||||||
|
|
||||||
isBot: (peerID: number): boolean => {
|
public isBot(peerID: number): boolean {
|
||||||
return (peerID > 0) && appUsersManager.isBot(peerID);
|
return (peerID > 0) && appUsersManager.isBot(peerID);
|
||||||
},
|
}
|
||||||
|
|
||||||
getInputPeer: (peerString: string): any => {
|
public getInputPeer(peerString: string): InputPeer {
|
||||||
var firstChar = peerString.charAt(0);
|
var firstChar = peerString.charAt(0);
|
||||||
var peerParams = peerString.substr(1).split('_');
|
var peerParams = peerString.substr(1).split('_');
|
||||||
let id = +peerParams[0];
|
let id = +peerParams[0];
|
||||||
@ -152,7 +152,7 @@ const AppPeersManager = {
|
|||||||
return {
|
return {
|
||||||
_: 'inputPeerChannel',
|
_: 'inputPeerChannel',
|
||||||
channel_id: id,
|
channel_id: id,
|
||||||
access_hash: peerParams[1] || 0
|
access_hash: peerParams[1] || '0'
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@ -160,9 +160,9 @@ const AppPeersManager = {
|
|||||||
chat_id: id
|
chat_id: id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
getInputPeerByID: (peerID: number): InputPeer => {
|
public getInputPeerByID(peerID: number): InputPeer {
|
||||||
if(!peerID) {
|
if(!peerID) {
|
||||||
return {_: 'inputPeerEmpty'};
|
return {_: 'inputPeerEmpty'};
|
||||||
}
|
}
|
||||||
@ -181,22 +181,22 @@ const AppPeersManager = {
|
|||||||
user_id: peerID,
|
user_id: peerID,
|
||||||
access_hash: appUsersManager.getUser(peerID).access_hash
|
access_hash: appUsersManager.getUser(peerID).access_hash
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
getInputDialogPeerByID: (peerID: number): InputDialogPeer => {
|
public getInputDialogPeerByID(peerID: number): InputDialogPeer {
|
||||||
return {
|
return {
|
||||||
_: 'inputDialogPeer',
|
_: 'inputDialogPeer',
|
||||||
peer: AppPeersManager.getInputPeerByID(peerID)
|
peer: this.getInputPeerByID(peerID)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeerColorByID: (peerID: number, pic = true) => {
|
public getPeerColorByID(peerID: number, pic = true) {
|
||||||
const idx = DialogColorsMap[(peerID < 0 ? -peerID : peerID) % 7];
|
const idx = DialogColorsMap[(peerID < 0 ? -peerID : peerID) % 7];
|
||||||
const color = (pic ? DialogColors : DialogColorsFg)[idx];
|
const color = (pic ? DialogColors : DialogColorsFg)[idx];
|
||||||
return color;
|
return color;
|
||||||
},
|
}
|
||||||
|
|
||||||
getPeerSearchText: (peerID: number) => {
|
public getPeerSearchText(peerID: number) {
|
||||||
let text;
|
let text;
|
||||||
if(peerID > 0) {
|
if(peerID > 0) {
|
||||||
text = '%pu ' + appUsersManager.getUserSearchText(peerID);
|
text = '%pu ' + appUsersManager.getUserSearchText(peerID);
|
||||||
@ -206,6 +206,7 @@ const AppPeersManager = {
|
|||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default AppPeersManager;
|
const appPeersManager = new AppPeersManager();
|
||||||
|
export default appPeersManager;
|
||||||
|
@ -228,7 +228,7 @@ export class AppPhotosManager {
|
|||||||
const photo = this.getPhoto(photoID);
|
const photo = this.getPhoto(photoID);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if(photo._ == 'photoEmpty') {
|
if(!photo || photo._ == 'photoEmpty') {
|
||||||
throw new Error('preloadPhoto photoEmpty!');
|
throw new Error('preloadPhoto photoEmpty!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +416,7 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async performSearchResult(messages: any[], type: string) {
|
public async performSearchResult(messages: any[], type: SharedMediaType) {
|
||||||
const peerID = this.peerID;
|
const peerID = this.peerID;
|
||||||
const elemsToAppend: HTMLElement[] = [];
|
const elemsToAppend: HTMLElement[] = [];
|
||||||
const promises: Promise<any>[] = [];
|
const promises: Promise<any>[] = [];
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Dialog } from "./appManagers/appMessagesManager";
|
||||||
/*!
|
/*!
|
||||||
* Webogram v0.7.0 - messaging web application for MTProto
|
* Webogram v0.7.0 - messaging web application for MTProto
|
||||||
* https://github.com/zhukov/webogram
|
* https://github.com/zhukov/webogram
|
||||||
@ -156,29 +157,36 @@ type BroadcastEvents = {
|
|||||||
'user_update': any,
|
'user_update': any,
|
||||||
'user_auth': any,
|
'user_auth': any,
|
||||||
'peer_changed': any,
|
'peer_changed': any,
|
||||||
|
|
||||||
'filter_delete': any,
|
'filter_delete': any,
|
||||||
'filter_update': any,
|
'filter_update': any,
|
||||||
'message_edit': any,
|
|
||||||
'dialog_draft': any,
|
'dialog_draft': any,
|
||||||
'messages_pending': any,
|
'dialog_unread': {peerID: number, count?: number},
|
||||||
|
'dialog_flush': {peerID: number},
|
||||||
|
'dialog_drop': {peerID: number, dialog?: Dialog},
|
||||||
|
'dialog_migrate': any,
|
||||||
|
'dialog_top': Dialog,
|
||||||
|
'dialog_notify_settings': number,
|
||||||
|
'dialogs_multiupdate': {[peerID: string]: Dialog},
|
||||||
|
'dialogs_archived_unread': any,
|
||||||
|
|
||||||
'history_append': any,
|
'history_append': any,
|
||||||
'history_update': any,
|
'history_update': any,
|
||||||
'dialogs_multiupdate': any,
|
|
||||||
'dialog_unread': any,
|
|
||||||
'dialog_flush': any,
|
|
||||||
'dialog_drop': any,
|
|
||||||
'dialog_migrate': any,
|
|
||||||
'dialog_top': any,
|
|
||||||
'history_reply_markup': any,
|
'history_reply_markup': any,
|
||||||
'history_multiappend': any,
|
'history_multiappend': any,
|
||||||
'messages_read': any,
|
'history_delete': {peerID: number, msgs: {[mid: number]: true}},
|
||||||
'history_delete': any,
|
'history_forbidden': number,
|
||||||
'history_forbidden': any,
|
'history_reload': number,
|
||||||
'history_reload': any,
|
'history_request': any,
|
||||||
|
|
||||||
|
'message_edit': any,
|
||||||
'message_views': any,
|
'message_views': any,
|
||||||
'message_sent': any,
|
'message_sent': any,
|
||||||
'history_request': any,
|
'messages_pending': void,
|
||||||
|
'messages_read': any,
|
||||||
'messages_downloaded': any,
|
'messages_downloaded': any,
|
||||||
|
|
||||||
'contacts_update': any,
|
'contacts_update': any,
|
||||||
'avatar_update': any,
|
'avatar_update': any,
|
||||||
'stickers_installed': any,
|
'stickers_installed': any,
|
||||||
@ -186,7 +194,6 @@ type BroadcastEvents = {
|
|||||||
'chat_full_update': any,
|
'chat_full_update': any,
|
||||||
'peer_pinned_message': any,
|
'peer_pinned_message': any,
|
||||||
'poll_update': any,
|
'poll_update': any,
|
||||||
'dialogs_archived_unread': any,
|
|
||||||
'audio_play': any,
|
'audio_play': any,
|
||||||
'audio_pause': any,
|
'audio_pause': any,
|
||||||
'chat_update': any,
|
'chat_update': any,
|
||||||
@ -195,7 +202,6 @@ type BroadcastEvents = {
|
|||||||
'channel_settings': any,
|
'channel_settings': any,
|
||||||
'webpage_updated': any,
|
'webpage_updated': any,
|
||||||
'draft_updated': any,
|
'draft_updated': any,
|
||||||
'dialog_notify_settings': number,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const $rootScope = {
|
export const $rootScope = {
|
||||||
|
@ -41,4 +41,17 @@
|
|||||||
"params": [
|
"params": [
|
||||||
{"name": "url", "type": "string"}
|
{"name": "url", "type": "string"}
|
||||||
]
|
]
|
||||||
|
}, {
|
||||||
|
"predicate": "dialog",
|
||||||
|
"params": [
|
||||||
|
{"name": "index", "type": "number"},
|
||||||
|
{"name": "peerID", "type": "number"}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
"predicate": "dialogFolder",
|
||||||
|
"params": [
|
||||||
|
{"name": "index", "type": "number"},
|
||||||
|
{"name": "peerID", "type": "number"},
|
||||||
|
{"name": "folder_id", "type": "number"}
|
||||||
|
]
|
||||||
}]
|
}]
|
@ -21,7 +21,7 @@
|
|||||||
// "noEmit": true, /* Do not emit outputs. */
|
// "noEmit": true, /* Do not emit outputs. */
|
||||||
//"importHelpers": true, /* Import emit helpers from 'tslib'. */
|
//"importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
"isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
|
||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
@ -30,6 +30,7 @@
|
|||||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
"strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
|
"strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
|
||||||
|
// "skipLibCheck": true,
|
||||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
|
||||||
@ -40,7 +41,7 @@
|
|||||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||||
|
|
||||||
/* Module Resolution Options */
|
/* Module Resolution Options */
|
||||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
@ -66,6 +67,7 @@
|
|||||||
"./public/recorder.min.js",
|
"./public/recorder.min.js",
|
||||||
"public",
|
"public",
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"./src/scripts",
|
||||||
"./public/*.js",
|
"./public/*.js",
|
||||||
"./src/lib/crypto/crypto.worker.js",
|
"./src/lib/crypto/crypto.worker.js",
|
||||||
"./src/vendor/StackBlur.js",
|
"./src/vendor/StackBlur.js",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user