Fix memory leaks
This commit is contained in:
parent
25ecb89f2b
commit
d2d184d242
@ -69,6 +69,8 @@ import { attachContextMenuListener } from "../helpers/dom/attachContextMenuListe
|
||||
import contextMenuController from "../helpers/contextMenuController";
|
||||
import positionMenu from "../helpers/positionMenu";
|
||||
import apiManagerProxy from "../lib/mtproto/mtprotoworker";
|
||||
import ListenerSetter from "../helpers/listenerSetter";
|
||||
import SwipeHandler from "./swipeHandler";
|
||||
|
||||
//const testScroll = false;
|
||||
|
||||
@ -107,7 +109,8 @@ class SearchContextMenu {
|
||||
|
||||
constructor(
|
||||
private attachTo: HTMLElement,
|
||||
private searchSuper: AppSearchSuper
|
||||
private searchSuper: AppSearchSuper,
|
||||
private listenerSetter: ListenerSetter
|
||||
) {
|
||||
this.managers = searchSuper.managers;
|
||||
|
||||
@ -162,7 +165,7 @@ class SearchContextMenu {
|
||||
if(IS_TOUCH_SUPPORTED) {
|
||||
|
||||
} else {
|
||||
attachContextMenuListener(attachTo, onContextMenu as any);
|
||||
attachContextMenuListener(attachTo, onContextMenu as any, listenerSetter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,14 +326,18 @@ export default class AppSearchSuper {
|
||||
public managers: AppManagers;
|
||||
private loadFirstTimePromise: Promise<void>;
|
||||
|
||||
private listenerSetter: ListenerSetter;
|
||||
private swipeHandler: SwipeHandler;
|
||||
|
||||
constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender' | 'managers'>) {
|
||||
safeAssign(this, options);
|
||||
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('search-super');
|
||||
|
||||
this.searchContextMenu = new SearchContextMenu(this.container, this);
|
||||
this.selection = new SearchSelection(this, this.managers);
|
||||
this.listenerSetter = new ListenerSetter();
|
||||
this.searchContextMenu = new SearchContextMenu(this.container, this, this.listenerSetter);
|
||||
this.selection = new SearchSelection(this, this.managers, this.listenerSetter);
|
||||
|
||||
const navScrollableContainer = this.navScrollableContainer = document.createElement('div');
|
||||
navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');
|
||||
@ -369,7 +376,7 @@ export default class AppSearchSuper {
|
||||
|
||||
let unlockScroll: ReturnType<typeof lockTouchScroll>;
|
||||
if(IS_TOUCH_SUPPORTED) {
|
||||
handleTabSwipe({
|
||||
this.swipeHandler = handleTabSwipe({
|
||||
element: this.tabsContainer,
|
||||
onSwipe: (xDiff, yDiff, e) => {
|
||||
const prevId = this.selectTab.prevId();
|
||||
@ -521,14 +528,14 @@ export default class AppSearchSuper {
|
||||
}
|
||||
|
||||
this.onTransitionEnd();
|
||||
}, undefined, navScrollable);
|
||||
}, undefined, navScrollable, this.listenerSetter);
|
||||
|
||||
attachClickEvent(this.tabsContainer, (e) => {
|
||||
if(this.selection.isSelecting) {
|
||||
cancelEvent(e);
|
||||
this.selection.toggleByElement(findUpClassName(e.target, 'search-super-item'));
|
||||
}
|
||||
}, {capture: true, passive: false});
|
||||
}, {capture: true, passive: false, listenerSetter: this.listenerSetter});
|
||||
|
||||
const onMediaClick = async(className: string, targetClassName: string, inputFilter: MyInputMessagesFilter, e: MouseEvent) => {
|
||||
const target = findUpClassName(e.target as HTMLDivElement, className);
|
||||
@ -560,8 +567,8 @@ export default class AppSearchSuper {
|
||||
.openMedia(message, targets[idx].element, 0, false, targets.slice(0, idx), targets.slice(idx + 1));
|
||||
};
|
||||
|
||||
attachClickEvent(this.tabs.inputMessagesFilterPhotoVideo, onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'));
|
||||
attachClickEvent(this.tabs.inputMessagesFilterDocument, onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'));
|
||||
attachClickEvent(this.tabs.inputMessagesFilterPhotoVideo, onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'), {listenerSetter: this.listenerSetter});
|
||||
attachClickEvent(this.tabs.inputMessagesFilterDocument, onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'), {listenerSetter: this.listenerSetter});
|
||||
|
||||
/* attachClickEvent(this.tabs.inputMessagesFilterUrl, (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
@ -581,7 +588,7 @@ export default class AppSearchSuper {
|
||||
this.lazyLoadQueue.lock();
|
||||
}, () => {
|
||||
this.lazyLoadQueue.unlockAndRefresh(); // ! maybe not so efficient
|
||||
});
|
||||
}, this.listenerSetter);
|
||||
}
|
||||
|
||||
private onTransitionStart = () => {
|
||||
@ -920,7 +927,7 @@ export default class AppSearchSuper {
|
||||
element.dataset.peerId = '' + message.peerId;
|
||||
monthContainer.items[method](element);
|
||||
|
||||
if(this.selection.isSelecting) {
|
||||
if(this.selection?.isSelecting) {
|
||||
this.selection.toggleElementCheckbox(element, true);
|
||||
}
|
||||
});
|
||||
@ -1524,7 +1531,7 @@ export default class AppSearchSuper {
|
||||
this.usedFromHistory[mediaTab.inputFilter] = -1;
|
||||
});
|
||||
|
||||
if(this.selection.isSelecting) {
|
||||
if(this.selection?.isSelecting) {
|
||||
this.selection.cancelSelection();
|
||||
}
|
||||
|
||||
@ -1641,4 +1648,18 @@ export default class AppSearchSuper {
|
||||
|
||||
this.cleanup();
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.listenerSetter.removeAll();
|
||||
this.scrollable.destroy();
|
||||
this.swipeHandler?.removeListeners();
|
||||
this.selection?.cleanup();
|
||||
|
||||
this.scrollStartCallback = undefined;
|
||||
this.onChangeTab = undefined;
|
||||
this.selectTab = undefined;
|
||||
this.searchContextMenu = undefined;
|
||||
this.swipeHandler = undefined;
|
||||
this.selection = undefined;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export default function callVideoCanvasBlur(video: HTMLVideoElement) {
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
const ctx = canvas.getContext('2d', {alpha: false});
|
||||
ctx.filter = 'blur(2px)';
|
||||
const renderFrame = () => {
|
||||
ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, canvas.width, canvas.height);
|
||||
|
@ -1937,7 +1937,7 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
public onScroll = (ignoreHeavyAnimation?: boolean, scrollDimensions?: ScrollStartCallbackDimensions) => {
|
||||
//return;
|
||||
// return;
|
||||
|
||||
if(this.isHeavyAnimationInProgress) {
|
||||
if(this.sliceViewportDebounced) {
|
||||
@ -2470,8 +2470,7 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
private destroyScrollable() {
|
||||
this.scrollable.removeListeners();
|
||||
this.scrollable.onScrolledTop = this.scrollable.onScrolledBottom = this.scrollable.onAdditionalScroll = null;
|
||||
this.scrollable.destroy();
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
@ -2517,6 +2516,7 @@ export default class ChatBubbles {
|
||||
// clear messages
|
||||
if(bubblesToo) {
|
||||
this.scrollable.container.textContent = '';
|
||||
this.chatInner.textContent = '';
|
||||
this.cleanupPlaceholders();
|
||||
}
|
||||
|
||||
@ -2805,7 +2805,7 @@ export default class ChatBubbles {
|
||||
this.attachPlaceholderOnRender();
|
||||
}
|
||||
|
||||
if(!isTarget && this.chat.type === 'chat') {
|
||||
if(!isTarget && this.chat.type === 'chat' && this.chat.topbar.pinnedMessage) {
|
||||
this.chat.topbar.pinnedMessage.setCorrectIndex(0);
|
||||
}
|
||||
|
||||
|
@ -458,6 +458,11 @@ export default class Chat extends EventListenerBase<{
|
||||
this.cleanup(true);
|
||||
this.bubbles.setPeer(false, peerId);
|
||||
this.appImManager.dispatchEvent('peer_changed', peerId);
|
||||
|
||||
appSidebarRight.replaceSharedMediaTab();
|
||||
this.destroySharedMediaTab();
|
||||
this.sharedMediaTab = undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -283,11 +283,11 @@ export default class ChatBackgroundGradientRenderer {
|
||||
this._hc = document.createElement('canvas');
|
||||
this._hc.width = this._width;
|
||||
this._hc.height = this._height;
|
||||
this._hctx = this._hc.getContext('2d');
|
||||
this._hctx = this._hc.getContext('2d', {alpha: false});
|
||||
}
|
||||
|
||||
this._canvas = el;
|
||||
this._ctx = this._canvas.getContext('2d');
|
||||
this._ctx = this._canvas.getContext('2d', {alpha: false});
|
||||
this.update();
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ import safeAssign from "../../helpers/object/safeAssign";
|
||||
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||
import wrapEmojiText from "../../lib/richTextProcessor/wrapEmojiText";
|
||||
import { AppManagers } from "../../lib/appManagers/managers";
|
||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||
|
||||
export default class ReplyKeyboard extends DropdownHover {
|
||||
private static BASE_CLASS = 'reply-keyboard';
|
||||
@ -74,7 +75,7 @@ export default class ReplyKeyboard extends DropdownHover {
|
||||
}
|
||||
});
|
||||
|
||||
this.listenerSetter.add(this.element)('click', (e) => {
|
||||
attachClickEvent(this.element, (e) => {
|
||||
const target = findUpClassName(e.target, 'btn');
|
||||
if(!target) {
|
||||
return;
|
||||
@ -103,7 +104,7 @@ export default class ReplyKeyboard extends DropdownHover {
|
||||
}
|
||||
|
||||
this.toggle(false);
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
return super.init();
|
||||
}
|
||||
|
@ -533,7 +533,7 @@ export class SearchSelection extends AppSelection {
|
||||
|
||||
private isPrivate: boolean;
|
||||
|
||||
constructor(private searchSuper: AppSearchSuper, managers: AppManagers) {
|
||||
constructor(private searchSuper: AppSearchSuper, managers: AppManagers, listenerSetter: ListenerSetter) {
|
||||
super({
|
||||
managers,
|
||||
verifyTarget: (e, target) => !!target && this.isSelecting,
|
||||
@ -544,7 +544,7 @@ export class SearchSelection extends AppSelection {
|
||||
});
|
||||
|
||||
this.isPrivate = !searchSuper.showSender;
|
||||
this.attachListeners(searchSuper.container, new ListenerSetter());
|
||||
this.attachListeners(searchSuper.container, listenerSetter);
|
||||
}
|
||||
|
||||
/* public appendCheckbox(element: HTMLElement, checkboxField: CheckboxField) {
|
||||
@ -615,7 +615,7 @@ export class SearchSelection extends AppSelection {
|
||||
this.selectionContainer.classList.add(BASE_CLASS + '-container');
|
||||
|
||||
const btnCancel = ButtonIcon(`close ${BASE_CLASS}-cancel`, {noRipple: true});
|
||||
this.listenerSetter.add(btnCancel)('click', () => this.cancelSelection(), {once: true});
|
||||
attachClickEvent(btnCancel, () => this.cancelSelection(), {listenerSetter: this.listenerSetter, once: true});
|
||||
|
||||
this.selectionCountEl = document.createElement('div');
|
||||
this.selectionCountEl.classList.add(BASE_CLASS + '-count');
|
||||
|
@ -9,6 +9,7 @@ import { LangPackKey, _i18n } from "../lib/langPack";
|
||||
import getDeepProperty from "../helpers/object/getDeepProperty";
|
||||
import rootScope from "../lib/rootScope";
|
||||
import apiManagerProxy from "../lib/mtproto/mtprotoworker";
|
||||
import ListenerSetter from "../helpers/listenerSetter";
|
||||
|
||||
export type CheckboxFieldOptions = {
|
||||
text?: LangPackKey,
|
||||
@ -23,6 +24,7 @@ export type CheckboxFieldOptions = {
|
||||
restriction?: boolean,
|
||||
withRipple?: boolean,
|
||||
withHover?: boolean,
|
||||
listenerSetter?: ListenerSetter
|
||||
};
|
||||
export default class CheckboxField {
|
||||
public input: HTMLInputElement;
|
||||
@ -57,7 +59,24 @@ export default class CheckboxField {
|
||||
}
|
||||
|
||||
if(options.stateKey) {
|
||||
let loaded = false;
|
||||
const onChange = () => {
|
||||
if(!loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
let value: any;
|
||||
if(options.stateValues) {
|
||||
value = options.stateValues[input.checked ? 1 : 0];
|
||||
} else {
|
||||
value = input.checked;
|
||||
}
|
||||
|
||||
rootScope.managers.appStateManager.setByKey(options.stateKey, value);
|
||||
};
|
||||
|
||||
apiManagerProxy.getState().then((state) => {
|
||||
loaded = true;
|
||||
const stateValue = getDeepProperty(state, options.stateKey);
|
||||
let checked: boolean;
|
||||
if(options.stateValues) {
|
||||
@ -67,18 +86,10 @@ export default class CheckboxField {
|
||||
}
|
||||
|
||||
this.setValueSilently(checked);
|
||||
|
||||
input.addEventListener('change', () => {
|
||||
let value: any;
|
||||
if(options.stateValues) {
|
||||
value = options.stateValues[input.checked ? 1 : 0];
|
||||
} else {
|
||||
value = input.checked;
|
||||
}
|
||||
|
||||
rootScope.managers.appStateManager.setByKey(options.stateKey, value);
|
||||
});
|
||||
});
|
||||
|
||||
if(options.listenerSetter) options.listenerSetter.add(input)('change', onChange);
|
||||
else input.addEventListener('change', onChange);
|
||||
}
|
||||
|
||||
let span: HTMLSpanElement;
|
||||
|
@ -24,6 +24,7 @@ import { AppManagers } from "../../../lib/appManagers/managers";
|
||||
import fixEmoji from "../../../lib/richTextProcessor/fixEmoji";
|
||||
import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText";
|
||||
import wrapSingleEmoji from "../../../lib/richTextProcessor/wrapSingleEmoji";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
|
||||
const loadedURLs: Set<string> = new Set();
|
||||
export function appendEmoji(emoji: string, container: HTMLElement, prepend = false, unify = false) {
|
||||
@ -258,7 +259,7 @@ export default class EmojiTab implements EmoticonsTab {
|
||||
});
|
||||
});
|
||||
|
||||
this.content.addEventListener('click', this.onContentClick);
|
||||
attachClickEvent(this.content, this.onContentClick);
|
||||
this.init = null;
|
||||
|
||||
rootScope.addEventListener('emoji_recent', (emoji) => {
|
||||
|
@ -9,6 +9,7 @@ import GifsMasonry from "../../gifsMasonry";
|
||||
import Scrollable from "../../scrollable";
|
||||
import { putPreloader } from "../../putPreloader";
|
||||
import { AppManagers } from "../../../lib/appManagers/managers";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
|
||||
export default class GifsTab implements EmoticonsTab {
|
||||
private content: HTMLElement;
|
||||
@ -20,7 +21,7 @@ export default class GifsTab implements EmoticonsTab {
|
||||
init() {
|
||||
this.content = document.getElementById('content-gifs');
|
||||
const gifsContainer = this.content.firstElementChild as HTMLDivElement;
|
||||
gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick);
|
||||
attachClickEvent(gifsContainer, EmoticonsDropdown.onMediaClick);
|
||||
|
||||
const scroll = new Scrollable(this.content, 'GIFS');
|
||||
const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll);
|
||||
|
@ -11,6 +11,8 @@ import { fastRaf } from "../helpers/schedulers";
|
||||
import { FocusDirection } from "../helpers/fastSmoothScroll";
|
||||
import findUpAsChild from "../helpers/dom/findUpAsChild";
|
||||
import whichChild from "../helpers/dom/whichChild";
|
||||
import ListenerSetter from "../helpers/listenerSetter";
|
||||
import { attachClickEvent } from "../helpers/dom/clickEvent";
|
||||
|
||||
export function horizontalMenu(
|
||||
tabs: HTMLElement,
|
||||
@ -18,9 +20,10 @@ export function horizontalMenu(
|
||||
onClick?: (id: number, tabContent: HTMLDivElement, animate: boolean) => void | boolean | Promise<void | boolean>,
|
||||
onTransitionEnd?: () => void,
|
||||
transitionTime = 250,
|
||||
scrollableX?: ScrollableX
|
||||
scrollableX?: ScrollableX,
|
||||
listenerSetter?: ListenerSetter
|
||||
) {
|
||||
const selectTab = TransitionSlider(content, tabs || content.dataset.animation === 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd);
|
||||
const selectTab = TransitionSlider(content, tabs || content.dataset.animation === 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd, undefined, listenerSetter);
|
||||
|
||||
if(!tabs) {
|
||||
return selectTab;
|
||||
@ -109,7 +112,7 @@ export function horizontalMenu(
|
||||
|
||||
//const tagName = tabs.classList.contains('menu-horizontal-div') ? 'BUTTON' : 'LI';
|
||||
const tagName = tabs.firstElementChild.tagName;
|
||||
tabs.addEventListener('click', function(e) {
|
||||
attachClickEvent(tabs, (e) => {
|
||||
let target = e.target as HTMLElement;
|
||||
|
||||
target = findUpAsChild(target, tabs);
|
||||
@ -129,7 +132,7 @@ export function horizontalMenu(
|
||||
}
|
||||
|
||||
selectTarget(target, id);
|
||||
});
|
||||
}, {listenerSetter});
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
@ -105,7 +105,8 @@ export default class PeerProfile {
|
||||
const full = await this.managers.appProfileManager.getProfileByPeerId(this.peerId);
|
||||
copyTextToClipboard(full.about);
|
||||
toast(I18n.format('BioCopied', true));
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
this.bio.title.classList.add('pre-wrap');
|
||||
@ -118,7 +119,8 @@ export default class PeerProfile {
|
||||
const peer: Channel | User.user = await this.managers.appPeersManager.getPeer(this.peerId);
|
||||
copyTextToClipboard('@' + peer.username);
|
||||
toast(I18n.format('UsernameCopied', true));
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
this.phone = new Row({
|
||||
@ -129,7 +131,8 @@ export default class PeerProfile {
|
||||
const peer: User = await this.managers.appUsersManager.getUser(this.peerId);
|
||||
copyTextToClipboard('+' + peer.phone);
|
||||
toast(I18n.format('PhoneCopied', true));
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
this.link = new Row({
|
||||
@ -142,7 +145,8 @@ export default class PeerProfile {
|
||||
// copyTextToClipboard(chatFull.exported_invite.link);
|
||||
toast(I18n.format('LinkCopied', true));
|
||||
// });
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
this.location = new Row({
|
||||
@ -164,7 +168,8 @@ export default class PeerProfile {
|
||||
this.notifications = new Row({
|
||||
checkboxField: new CheckboxField({toggle: true}),
|
||||
titleLangKey: 'Notifications',
|
||||
icon: 'unmute'
|
||||
icon: 'unmute',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
listenerSetter.add(this.notifications.checkboxField.input)('change', (e) => {
|
||||
@ -457,5 +462,6 @@ export default class PeerProfile {
|
||||
public destroy() {
|
||||
this.clearSetMoreDetailsTimeout();
|
||||
clearInterval(this.setPeerStatusInterval);
|
||||
this.avatars?.cleanup();
|
||||
}
|
||||
}
|
||||
|
@ -409,5 +409,6 @@ export default class PeerProfileAvatars {
|
||||
public cleanup() {
|
||||
this.listenerSetter.removeAll();
|
||||
this.swipeHandler.removeListeners();
|
||||
this.intersectionObserver?.disconnect();
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ export default class PopupReactedList extends PopupElement {
|
||||
|
||||
const loader = loaders.get(tabContent);
|
||||
loader.load();
|
||||
});
|
||||
}, undefined, undefined, undefined, this.listenerSetter);
|
||||
|
||||
// selectTab(hasAllReactions && hasReadParticipants ? 1 : 0, false);
|
||||
selectTab(0, false);
|
||||
|
@ -12,6 +12,8 @@ import RadioForm from "./radioForm";
|
||||
import { i18n, LangPackKey } from "../lib/langPack";
|
||||
import replaceContent from "../helpers/dom/replaceContent";
|
||||
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||
import ListenerSetter from "../helpers/listenerSetter";
|
||||
import { attachClickEvent } from "../helpers/dom/clickEvent";
|
||||
|
||||
export default class Row {
|
||||
public container: HTMLElement;
|
||||
@ -41,7 +43,8 @@ export default class Row {
|
||||
navigationTab: SliderSuperTab,
|
||||
havePadding: boolean,
|
||||
noRipple: boolean,
|
||||
noWrap: boolean
|
||||
noWrap: boolean,
|
||||
listenerSetter: ListenerSetter
|
||||
}> = {}) {
|
||||
this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');
|
||||
this.container.classList.add('row');
|
||||
@ -81,9 +84,12 @@ export default class Row {
|
||||
}
|
||||
|
||||
if(!options.noCheckboxSubtitle && !isToggle) {
|
||||
this.checkboxField.input.addEventListener('change', () => {
|
||||
const onChange = () => {
|
||||
replaceContent(this.subtitle, i18n(this.checkboxField.input.checked ? 'Checkbox.Enabled' : 'Checkbox.Disabled'));
|
||||
});
|
||||
};
|
||||
|
||||
if(options.listenerSetter) options.listenerSetter.add(this.checkboxField.input)('change', onChange);
|
||||
else this.checkboxField.input.addEventListener('change', onChange);
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,10 +157,10 @@ export default class Row {
|
||||
|
||||
if(options.clickable || options.radioField || options.checkboxField) {
|
||||
if(typeof(options.clickable) === 'function') {
|
||||
this.container.addEventListener('click', (e) => {
|
||||
attachClickEvent(this.container, (e) => {
|
||||
if(this.freezed) return;
|
||||
(options.clickable as any)(e);
|
||||
});
|
||||
}, {listenerSetter: options.listenerSetter});
|
||||
}
|
||||
|
||||
this.container.classList.add('row-clickable', 'hover-effect');
|
||||
|
@ -143,6 +143,13 @@ export class ScrollableBase {
|
||||
this.removeHeavyAnimationListener = undefined;
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.removeListeners();
|
||||
this.onAdditionalScroll = undefined;
|
||||
this.onScrolledTop = undefined;
|
||||
this.onScrolledBottom = undefined;
|
||||
}
|
||||
|
||||
public append(element: HTMLElement) {
|
||||
this.container.append(element);
|
||||
}
|
||||
@ -160,7 +167,7 @@ export class ScrollableBase {
|
||||
//this.log('onScroll call', this.onScrollMeasure);
|
||||
//}
|
||||
|
||||
//return;
|
||||
// return;
|
||||
|
||||
if(this.isHeavyAnimationInProgress) {
|
||||
this.cancelMeasure();
|
||||
@ -172,7 +179,8 @@ export class ScrollableBase {
|
||||
if((!this.onScrolledTop && !this.onScrolledBottom) && !this.splitUp && !this.onAdditionalScroll) return;
|
||||
if(this.onScrollMeasure) return;
|
||||
// if(this.onScrollMeasure) window.cancelAnimationFrame(this.onScrollMeasure);
|
||||
this.onScrollMeasure = window.requestAnimationFrame(() => {
|
||||
// this.onScrollMeasure = window.requestAnimationFrame(() => {
|
||||
this.onScrollMeasure = window.setTimeout(() => {
|
||||
this.onScrollMeasure = 0;
|
||||
|
||||
const scrollPosition = this.container[this.scrollProperty];
|
||||
@ -187,12 +195,14 @@ export class ScrollableBase {
|
||||
if(this.checkForTriggers) {
|
||||
this.checkForTriggers();
|
||||
}
|
||||
});
|
||||
// });
|
||||
}, 200);
|
||||
};
|
||||
|
||||
public cancelMeasure() {
|
||||
if(this.onScrollMeasure) {
|
||||
window.cancelAnimationFrame(this.onScrollMeasure);
|
||||
// window.cancelAnimationFrame(this.onScrollMeasure);
|
||||
clearTimeout(this.onScrollMeasure);
|
||||
this.onScrollMeasure = 0;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ export default class AppAutoDownloadFileTab extends SliderSuperTabEventable {
|
||||
this.managers.appStateManager.setByKey('settings.autoDownloadNew.file_size_max', sizeMax);
|
||||
}, 200, false, true);
|
||||
|
||||
const section = autoDownloadPeerTypeSection('file', 'AutoDownloadFilesTitle');
|
||||
const section = autoDownloadPeerTypeSection('file', 'AutoDownloadFilesTitle', this.listenerSetter);
|
||||
|
||||
const MIN = 512 * 1024;
|
||||
// const MAX = 2 * 1024 * 1024 * 1024;
|
||||
|
@ -5,11 +5,12 @@
|
||||
*/
|
||||
|
||||
import { SettingSection } from "../..";
|
||||
import ListenerSetter from "../../../../helpers/listenerSetter";
|
||||
import { LangPackKey } from "../../../../lib/langPack";
|
||||
import CheckboxField from "../../../checkboxField";
|
||||
import { SliderSuperTabEventable } from "../../../sliderTab";
|
||||
|
||||
export function autoDownloadPeerTypeSection(type: 'photo' | 'video' | 'file', title: LangPackKey) {
|
||||
export function autoDownloadPeerTypeSection(type: 'photo' | 'video' | 'file', title: LangPackKey, listenerSetter: ListenerSetter) {
|
||||
const section = new SettingSection({name: title});
|
||||
|
||||
const key = 'settings.autoDownload.' + type + '.';
|
||||
@ -17,25 +18,29 @@ export function autoDownloadPeerTypeSection(type: 'photo' | 'video' | 'file', ti
|
||||
text: 'AutodownloadContacts',
|
||||
name: 'contacts',
|
||||
stateKey: key + 'contacts',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter
|
||||
});
|
||||
const privateCheckboxField = new CheckboxField({
|
||||
text: 'AutodownloadPrivateChats',
|
||||
name: 'private',
|
||||
stateKey: key + 'private',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter
|
||||
});
|
||||
const groupsCheckboxField = new CheckboxField({
|
||||
text: 'AutodownloadGroupChats',
|
||||
name: 'groups',
|
||||
stateKey: key + 'groups',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter
|
||||
});
|
||||
const channelsCheckboxField = new CheckboxField({
|
||||
text: 'AutodownloadChannels',
|
||||
name: 'channels',
|
||||
stateKey: key + 'channels',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter
|
||||
});
|
||||
|
||||
section.content.append(
|
||||
@ -53,7 +58,7 @@ export default class AppAutoDownloadPhotoTab extends SliderSuperTabEventable {
|
||||
this.header.classList.add('with-border');
|
||||
this.setTitle('AutoDownloadPhotos');
|
||||
|
||||
const section = autoDownloadPeerTypeSection('photo', 'AutoDownloadPhotosTitle');
|
||||
const section = autoDownloadPeerTypeSection('photo', 'AutoDownloadPhotosTitle', this.listenerSetter);
|
||||
this.scrollable.append(section.container);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ export default class AppAutoDownloadVideoTab extends SliderSuperTabEventable {
|
||||
this.header.classList.add('with-border');
|
||||
this.setTitle('AutoDownloadVideos');
|
||||
|
||||
const section = autoDownloadPeerTypeSection('video', 'AutoDownloadVideosTitle');
|
||||
const section = autoDownloadPeerTypeSection('video', 'AutoDownloadVideosTitle', this.listenerSetter);
|
||||
this.scrollable.append(section.container);
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,8 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
||||
subtitle: '',
|
||||
clickable: () => {
|
||||
openTab(AppAutoDownloadPhotoTab);
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const videoRow = new Row({
|
||||
@ -83,7 +84,8 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
||||
subtitle: '',
|
||||
clickable: () => {
|
||||
openTab(AppAutoDownloadVideoTab);
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const fileRow = new Row({
|
||||
@ -91,7 +93,8 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
||||
subtitle: '',
|
||||
clickable: () => {
|
||||
openTab(AppAutoDownloadFileTab);
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const resetButton = Button('btn-primary btn-transparent primary', {icon: 'delete', text: 'ResetAutomaticMediaDownload'});
|
||||
@ -154,13 +157,15 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
||||
text: 'AutoplayGIF',
|
||||
name: 'gifs',
|
||||
stateKey: 'settings.autoPlay.gifs',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
const videosCheckboxField = new CheckboxField({
|
||||
text: 'AutoplayVideo',
|
||||
name: 'videos',
|
||||
stateKey: 'settings.autoPlay.videos',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
section.content.append(gifsCheckboxField.label, videosCheckboxField.label);
|
||||
|
@ -24,6 +24,7 @@ import deepEqual from "../../../helpers/object/deepEqual";
|
||||
import documentFragmentToHTML from "../../../helpers/dom/documentFragmentToHTML";
|
||||
import wrapDraftText from "../../../lib/richTextProcessor/wrapDraftText";
|
||||
import filterAsync from "../../../helpers/array/filterAsync";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
|
||||
const MAX_FOLDER_NAME_LENGTH = 12;
|
||||
|
||||
@ -79,7 +80,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
}).show();
|
||||
}
|
||||
};
|
||||
this.menuBtn = ButtonMenuToggle({}, 'bottom-left', [deleteFolderButton]);
|
||||
this.menuBtn = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', [deleteFolderButton]);
|
||||
this.menuBtn.classList.add('hide');
|
||||
|
||||
this.header.append(this.confirmBtn, this.menuBtn);
|
||||
@ -174,15 +175,15 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
const includedFlagsContainer = this.includePeerIds.container.querySelector('.folder-categories');
|
||||
const excludedFlagsContainer = this.excludePeerIds.container.querySelector('.folder-categories');
|
||||
|
||||
includedFlagsContainer.querySelector('.btn').addEventListener('click', () => {
|
||||
attachClickEvent(includedFlagsContainer.querySelector('.btn') as HTMLElement, () => {
|
||||
this.slider.createTab(AppIncludedChatsTab).open(this.filter, 'included', this);
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
excludedFlagsContainer.querySelector('.btn').addEventListener('click', () => {
|
||||
attachClickEvent(excludedFlagsContainer.querySelector('.btn') as HTMLElement, () => {
|
||||
this.slider.createTab(AppIncludedChatsTab).open(this.filter, 'excluded', this);
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
this.confirmBtn.addEventListener('click', () => {
|
||||
attachClickEvent(this.confirmBtn, () => {
|
||||
if(this.nameInputField.input.classList.contains('error')) {
|
||||
return;
|
||||
}
|
||||
@ -222,9 +223,9 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
}).finally(() => {
|
||||
this.confirmBtn.removeAttribute('disabled');
|
||||
});
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
this.nameInputField.input.addEventListener('input', () => {
|
||||
this.listenerSetter.add(this.nameInputField.input)('input', () => {
|
||||
this.filter.title = this.nameInputField.value;
|
||||
this.editCheckForChange();
|
||||
});
|
||||
@ -336,7 +337,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
const content = section.generateContentElement();
|
||||
showMore = Button('folder-category-button btn btn-primary btn-transparent', {icon: 'down'});
|
||||
showMore.classList.add('load-more', 'rp-overflow');
|
||||
showMore.addEventListener('click', () => renderMore(20));
|
||||
attachClickEvent(showMore, () => renderMore(20), {listenerSetter: this.listenerSetter});
|
||||
showMore.append(i18n('FilterShowMoreChats', [peers.length]));
|
||||
|
||||
content.append(showMore);
|
||||
|
@ -111,7 +111,8 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
||||
text: 'EnableAnimations',
|
||||
name: 'animations',
|
||||
stateKey: 'settings.animationsEnabled',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
container.append(range.container, chatBackgroundButton, animationsCheckboxField.label);
|
||||
@ -231,13 +232,15 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
||||
text: 'GeneralSettings.EmojiPrediction',
|
||||
name: 'suggest-emoji',
|
||||
stateKey: 'settings.emoji.suggest',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
const bigCheckboxField = new CheckboxField({
|
||||
text: 'GeneralSettings.BigEmoji',
|
||||
name: 'emoji-big',
|
||||
stateKey: 'settings.emoji.big',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
container.append(suggestCheckboxField.label, bigCheckboxField.label);
|
||||
@ -251,7 +254,8 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
||||
havePadding: true,
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppQuickReactionTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const renderQuickReaction = () => {
|
||||
@ -272,13 +276,15 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
||||
text: 'Stickers.SuggestStickers',
|
||||
name: 'suggest',
|
||||
stateKey: 'settings.stickers.suggest',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
const loopCheckboxField = new CheckboxField({
|
||||
text: 'InstalledStickers.LoopAnimated',
|
||||
name: 'loop',
|
||||
stateKey: 'settings.stickers.loop',
|
||||
withRipple: true
|
||||
withRipple: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const stickerSets: {[id: string]: Row} = {};
|
||||
@ -294,7 +300,8 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
||||
havePadding: true,
|
||||
clickable: () => {
|
||||
new PopupStickers({id: stickerSet.id, access_hash: stickerSet.access_hash}).show();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
stickerSets[stickerSet.id] = row;
|
||||
|
@ -19,6 +19,7 @@ import copy from "../../../helpers/object/copy";
|
||||
import forEachReverse from "../../../helpers/array/forEachReverse";
|
||||
import setInnerHTML from "../../../helpers/dom/setInnerHTML";
|
||||
import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
|
||||
export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
private editFolderTab: AppEditFolderTab;
|
||||
@ -39,7 +40,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
|
||||
this.header.append(this.confirmBtn);
|
||||
|
||||
this.confirmBtn.addEventListener('click', async() => {
|
||||
attachClickEvent(this.confirmBtn, async() => {
|
||||
const selected = this.selector.getSelected();
|
||||
|
||||
//this.filter.pFlags = {};
|
||||
@ -103,7 +104,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
|
||||
this.editFolderTab.setFilter(this.filter, false);
|
||||
this.close();
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
this.dialogsByFilters = new Map();
|
||||
return this.managers.filtersStorage.getDialogFilters().then(async(filters) => {
|
||||
|
@ -13,6 +13,7 @@ import AppAddMembersTab from "./addMembers";
|
||||
import { _i18n } from "../../../lib/langPack";
|
||||
import ButtonCorner from "../../buttonCorner";
|
||||
import appImManager from "../../../lib/appManagers/appImManager";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
|
||||
export default class AppNewChannelTab extends SliderSuperTab {
|
||||
private uploadAvatar: () => Promise<InputFile> = null;
|
||||
@ -60,7 +61,7 @@ export default class AppNewChannelTab extends SliderSuperTab {
|
||||
|
||||
this.nextBtn = ButtonCorner({icon: 'arrow_next'});
|
||||
|
||||
this.nextBtn.addEventListener('click', () => {
|
||||
attachClickEvent(this.nextBtn, () => {
|
||||
const title = this.channelNameInputField.value;
|
||||
const about = this.channelDescriptionInputField.value;
|
||||
|
||||
@ -89,7 +90,7 @@ export default class AppNewChannelTab extends SliderSuperTab {
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
this.content.append(this.nextBtn);
|
||||
section.content.append(this.avatarEdit.container, inputWrapper);
|
||||
|
@ -14,6 +14,7 @@ import I18n from "../../../lib/langPack";
|
||||
import ButtonCorner from "../../buttonCorner";
|
||||
import getUserStatusString from "../../wrappers/getUserStatusString";
|
||||
import appImManager from "../../../lib/appManagers/appImManager";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
|
||||
interface OpenStreetMapInterface {
|
||||
place_id?: number;
|
||||
@ -68,7 +69,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
||||
this.groupLocationInputField.container
|
||||
);
|
||||
|
||||
this.groupNameInputField.input.addEventListener('input', () => {
|
||||
this.listenerSetter.add(this.groupNameInputField.input)('input', () => {
|
||||
const value = this.groupNameInputField.value;
|
||||
let valueCheck = !!value.length && !this.groupNameInputField.input.classList.contains('error');
|
||||
if(this.isGeoChat) valueCheck = valueCheck && !!this.userLocationCoords && !!this.userLocationAddress;
|
||||
@ -77,7 +78,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
||||
|
||||
this.nextBtn = ButtonCorner({icon: 'arrow_next'});
|
||||
|
||||
this.nextBtn.addEventListener('click', () => {
|
||||
attachClickEvent(this.nextBtn, () => {
|
||||
const title = this.groupNameInputField.value;
|
||||
|
||||
let promise: Promise<ChatId>;
|
||||
@ -128,7 +129,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
||||
|
||||
appImManager.setInnerPeer({peerId: chatId.toPeerId(true)});
|
||||
});
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
const chatsSection = new SettingSection({
|
||||
name: 'Members',
|
||||
|
@ -36,11 +36,13 @@ export default class AppNotificationsTab extends SliderSuperTabEventable {
|
||||
const enabledRow = new Row({
|
||||
checkboxField: new CheckboxField({text: options.typeText, checked: true}),
|
||||
subtitleLangKey: 'Loading',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const previewEnabledRow = new Row({
|
||||
checkboxField: new CheckboxField({text: 'MessagePreview', checked: true}),
|
||||
subtitleLangKey: 'Loading',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
section.content.append(enabledRow.container, previewEnabledRow.container);
|
||||
@ -112,11 +114,13 @@ export default class AppNotificationsTab extends SliderSuperTabEventable {
|
||||
const contactsSignUpRow = new Row({
|
||||
checkboxField: new CheckboxField({text: 'ContactJoined', checked: true}),
|
||||
subtitleLangKey: 'Loading',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const soundRow = new Row({
|
||||
checkboxField: new CheckboxField({text: 'Notifications.Sound', checked: true, stateKey: 'settings.notifications.sound'}),
|
||||
checkboxField: new CheckboxField({text: 'Notifications.Sound', checked: true, stateKey: 'settings.notifications.sound', listenerSetter: this.listenerSetter}),
|
||||
subtitleLangKey: 'Loading',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
apiManagerProxy.getState().then((state) => {
|
||||
|
@ -56,7 +56,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
const tab = this.slider.createTab(AppBlockedUsersTab);
|
||||
tab.peerIds = blockedPeerIds;
|
||||
tab.open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
blockedUsersRow.freezed = true;
|
||||
|
||||
@ -81,7 +82,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
|
||||
tab.state = passwordState;
|
||||
tab.open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
};
|
||||
|
||||
const twoFactorRow = new Row(twoFactorRowOptions);
|
||||
@ -98,7 +100,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
this.updateActiveSessions();
|
||||
}, {once: true});
|
||||
tab.open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
activeSessionsRow.freezed = true;
|
||||
|
||||
@ -157,7 +160,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppPrivacyPhoneNumberTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({
|
||||
@ -165,7 +169,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppPrivacyLastSeenTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({
|
||||
@ -173,7 +178,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppPrivacyProfilePhotoTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const callRow = rowsByKeys['inputPrivacyKeyPhoneCall'] = new Row({
|
||||
@ -181,7 +187,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppPrivacyCallsTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({
|
||||
@ -189,7 +196,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppPrivacyForwardMessagesTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({
|
||||
@ -197,7 +205,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppPrivacyAddToGroupsTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const updatePrivacyRow = (key: InputPrivacyKey['_']) => {
|
||||
|
@ -27,6 +27,7 @@ import { SliderSuperTabConstructable } from "../../sliderTab";
|
||||
import PopupAvatar from "../../popups/avatar";
|
||||
import { AccountAuthorizations, Authorization } from "../../../layer";
|
||||
import PopupElement from "../../popups";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
//import AppMediaViewer from "../../appMediaViewerNew";
|
||||
|
||||
export default class AppSettingsTab extends SliderSuperTab {
|
||||
@ -50,7 +51,7 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
this.container.classList.add('settings-container');
|
||||
this.setTitle('Settings');
|
||||
|
||||
const btnMenu = ButtonMenuToggle({}, 'bottom-left', [{
|
||||
const btnMenu = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', [{
|
||||
icon: 'logout',
|
||||
text: 'EditAccount.Logout',
|
||||
onClick: () => {
|
||||
@ -78,14 +79,14 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
const fillPromise = this.profile.fillProfileElements();
|
||||
|
||||
const changeAvatarBtn = Button('btn-circle btn-corner z-depth-1 profile-change-avatar', {icon: 'cameraadd'});
|
||||
changeAvatarBtn.addEventListener('click', () => {
|
||||
attachClickEvent(changeAvatarBtn, () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
PopupElement.createPopup(PopupAvatar).open(canvas, (upload) => {
|
||||
upload().then((inputFile) => {
|
||||
return this.managers.appProfileManager.uploadProfilePhoto(inputFile);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
this.profile.element.lastElementChild.firstElementChild.append(changeAvatarBtn);
|
||||
|
||||
const updateChangeAvatarBtn = async() => {
|
||||
@ -160,7 +161,8 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
clickable: () => {
|
||||
this.slider.createTab(tabConstructor).open();
|
||||
// new tabConstructor(this.slider, true).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
});
|
||||
|
||||
@ -181,7 +183,8 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
this.updateActiveSessions(true);
|
||||
}, {once: true});
|
||||
tab.open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
}),
|
||||
|
||||
this.languageRow = new Row({
|
||||
@ -190,7 +193,8 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
icon: 'language',
|
||||
clickable: () => {
|
||||
this.slider.createTab(AppLanguageTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
})
|
||||
);
|
||||
|
||||
@ -204,10 +208,10 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
|
||||
this.scrollable.append(this.profile.element/* profileSection.container */, buttonsSection.container);
|
||||
|
||||
this.buttons.edit.addEventListener('click', () => {
|
||||
attachClickEvent(this.buttons.edit, () => {
|
||||
const tab = this.slider.createTab(AppEditProfileTab);
|
||||
tab.open();
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
lottieLoader.loadLottieWorkers();
|
||||
|
||||
@ -235,4 +239,9 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
this.devicesRow.titleRight.textContent = '' + this.authorizations.length;
|
||||
});
|
||||
}
|
||||
|
||||
public onCloseAfterTimeout() {
|
||||
this.profile.destroy();
|
||||
return super.onCloseAfterTimeout();
|
||||
}
|
||||
}
|
||||
|
@ -46,15 +46,19 @@ export class AppSidebarRight extends SidebarSlider {
|
||||
return tab;
|
||||
}
|
||||
|
||||
public replaceSharedMediaTab(tab: AppSharedMediaTab) {
|
||||
public replaceSharedMediaTab(tab?: AppSharedMediaTab) {
|
||||
let previousTab = this.sharedMediaTab;
|
||||
if(previousTab) {
|
||||
const wasActive = previousTab.container.classList.contains('active');
|
||||
if(wasActive) {
|
||||
tab.container.classList.add('active');
|
||||
if(tab) {
|
||||
const wasActive = previousTab.container.classList.contains('active');
|
||||
if(wasActive) {
|
||||
tab.container.classList.add('active');
|
||||
}
|
||||
|
||||
previousTab.container.replaceWith(tab.container);
|
||||
} else {
|
||||
previousTab.container.remove();
|
||||
}
|
||||
|
||||
previousTab.container.replaceWith(tab.container);
|
||||
} else {
|
||||
this.tabsContainer.prepend(tab.container);
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ export default class AppChatReactionsTab extends SliderSuperTabEventable {
|
||||
const toggleCheckboxField = new CheckboxField({toggle: true, checked: !!enabledReactions.size});
|
||||
const toggleRow = new Row({
|
||||
checkboxField: toggleCheckboxField,
|
||||
titleLangKey: 'EnableReactions'
|
||||
titleLangKey: 'EnableReactions',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
toggleSection.content.append(toggleRow.container);
|
||||
@ -65,7 +66,8 @@ export default class AppChatReactionsTab extends SliderSuperTabEventable {
|
||||
const row = new Row({
|
||||
checkboxField,
|
||||
title: availableReaction.title,
|
||||
havePadding: true
|
||||
havePadding: true,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
wrapStickerToRow({
|
||||
|
@ -78,7 +78,8 @@ export default class AppChatTypeTab extends SliderSuperTabEventable {
|
||||
clickable: () => {
|
||||
copyTextToClipboard((this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link);
|
||||
toast(I18n.format('LinkCopied', true));
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const btnRevoke = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'RevokeLink'});
|
||||
|
@ -113,7 +113,8 @@ export default class AppEditChatTab extends SliderSuperTab {
|
||||
|
||||
this.listenerSetter.add(tab.eventListener)('destroy', setChatTypeSubtitle);
|
||||
},
|
||||
icon: 'lock'
|
||||
icon: 'lock',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const setChatTypeSubtitle = () => {
|
||||
@ -147,7 +148,8 @@ export default class AppEditChatTab extends SliderSuperTab {
|
||||
|
||||
this.listenerSetter.add(tab.eventListener)('destroy', setReactionsLength);
|
||||
});
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const availableReactions = await this.managers.appReactionsManager.getAvailableReactions();
|
||||
@ -182,6 +184,7 @@ export default class AppEditChatTab extends SliderSuperTab {
|
||||
tab.open();
|
||||
},
|
||||
icon: 'permissions',
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const setPermissionsLength = async() => {
|
||||
|
@ -117,7 +117,8 @@ export default class AppEditContactTab extends SliderSuperTab {
|
||||
|
||||
if(!isNew) {
|
||||
const notificationsRow = new Row({
|
||||
checkboxField: notificationsCheckboxField
|
||||
checkboxField: notificationsCheckboxField,
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const enabled = !(await this.managers.appNotificationsManager.isPeerLocalMuted(this.peerId, false));
|
||||
|
@ -185,7 +185,8 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
|
||||
placeholder: 'ExceptionModal.Search.Placeholder',
|
||||
peerId: -this.chatId,
|
||||
});
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const openPermissions = async(peerId: PeerId) => {
|
||||
|
@ -85,7 +85,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||
|
||||
// * body
|
||||
|
||||
this.profile = new PeerProfile(this.managers, this.scrollable);
|
||||
this.profile = new PeerProfile(this.managers, this.scrollable, this.listenerSetter);
|
||||
this.profile.init();
|
||||
|
||||
this.scrollable.append(this.profile.element);
|
||||
@ -124,7 +124,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||
} else if(!this.scrollable.isHeavyAnimationInProgress) {
|
||||
this.slider.onCloseBtnClick();
|
||||
}
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
attachClickEvent(this.editBtn, (e) => {
|
||||
let tab: AppEditChatTab | AppEditContactTab;
|
||||
@ -143,7 +143,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||
|
||||
tab.open();
|
||||
}
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
this.listenerSetter.add(rootScope)('contacts_update', (userId) => {
|
||||
if(this.peerId === userId) {
|
||||
@ -217,7 +217,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||
const btnAddMembers = ButtonCorner({icon: 'addmember_filled'});
|
||||
this.content.append(btnAddMembers);
|
||||
|
||||
btnAddMembers.addEventListener('click', async() => {
|
||||
attachClickEvent(btnAddMembers, async() => {
|
||||
const peerId = this.peerId;
|
||||
const id = this.peerId.toChatId();
|
||||
const isChannel = await this.managers.appChatsManager.isChannel(id);
|
||||
@ -315,7 +315,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
//console.log('construct shared media time:', performance.now() - perf);
|
||||
}
|
||||
@ -458,5 +458,6 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||
this.destroyable = true;
|
||||
this.onCloseAfterTimeout();
|
||||
this.profile.destroy();
|
||||
this.searchSuper.destroy();
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ const SetTransition = (
|
||||
clearTimeout(+timeout);
|
||||
}
|
||||
|
||||
// useRafs = undefined;
|
||||
// duration = 0;
|
||||
|
||||
if(raf !== undefined) {
|
||||
window.cancelAnimationFrame(+raf);
|
||||
if(!useRafs) {
|
||||
|
@ -152,7 +152,7 @@ export default class SidebarSlider {
|
||||
if(tab.onCloseAfterTimeout) {
|
||||
setTimeout(() => {
|
||||
tab.onCloseAfterTimeout();
|
||||
}, TRANSITION_TIME);
|
||||
}, TRANSITION_TIME + 30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ export default class SliderSuperTab implements SliderTab {
|
||||
if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой !
|
||||
this.slider.tabs.delete(this);
|
||||
this.container.remove();
|
||||
this.scrollable.destroy();
|
||||
}
|
||||
|
||||
if(this.listenerSetter) {
|
||||
|
@ -9,6 +9,7 @@ import deferredPromise, { CancellablePromise } from "../helpers/cancellablePromi
|
||||
import { dispatchHeavyAnimationEvent } from "../hooks/useHeavyAnimationCheck";
|
||||
import whichChild from "../helpers/dom/whichChild";
|
||||
import cancelEvent from "../helpers/dom/cancelEvent";
|
||||
import ListenerSetter from "../helpers/listenerSetter";
|
||||
|
||||
function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) {
|
||||
const width = prevTabContent.getBoundingClientRect().width;
|
||||
@ -84,7 +85,8 @@ export const TransitionSlider = (
|
||||
type: 'tabs' | 'navigation' | 'zoom-fade' | 'slide-fade' | 'none'/* | 'counter' */,
|
||||
transitionTime: number,
|
||||
onTransitionEnd?: (id: number) => void,
|
||||
isHeavy = true
|
||||
isHeavy = true,
|
||||
listenerSetter?: ListenerSetter
|
||||
) => {
|
||||
let animationFunction: TransitionFunction = null;
|
||||
|
||||
@ -101,7 +103,7 @@ export const TransitionSlider = (
|
||||
|
||||
content.dataset.animation = type;
|
||||
|
||||
return Transition(content, animationFunction, transitionTime, onTransitionEnd, isHeavy);
|
||||
return Transition(content, animationFunction, transitionTime, onTransitionEnd, isHeavy, undefined, undefined, listenerSetter);
|
||||
};
|
||||
|
||||
type TransitionFunction = (tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) => void | (() => void);
|
||||
@ -113,7 +115,8 @@ const Transition = (
|
||||
onTransitionEnd?: (id: number) => void,
|
||||
isHeavy = true,
|
||||
once = false,
|
||||
withAnimationListener = true
|
||||
withAnimationListener = true,
|
||||
listenerSetter?: ListenerSetter
|
||||
) => {
|
||||
const onTransitionEndCallbacks: Map<HTMLElement, Function> = new Map();
|
||||
let animationDeferred: CancellablePromise<void>;
|
||||
@ -133,7 +136,7 @@ const Transition = (
|
||||
//console.log('Transition: transitionend', /* content, */ e, selectTab.prevId, performance.now() - animationStarted);
|
||||
|
||||
const callback = onTransitionEndCallbacks.get(e.target as HTMLElement);
|
||||
if(callback) callback();
|
||||
callback?.();
|
||||
|
||||
if(e.target !== from) {
|
||||
return;
|
||||
@ -153,14 +156,16 @@ const Transition = (
|
||||
content.classList.remove('animating', 'backwards', 'disable-hover');
|
||||
|
||||
if(once) {
|
||||
content.removeEventListener(listenerName, onEndEvent/* , {capture: false} */);
|
||||
if(listenerSetter) listenerSetter.removeManual(content, listenerName, onEndEvent);
|
||||
else content.removeEventListener(listenerName, onEndEvent/* , {capture: false} */);
|
||||
from = animationDeferred = undefined;
|
||||
onTransitionEndCallbacks.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: check for transition type (transform, etc) using by animationFunction
|
||||
content.addEventListener(listenerName, onEndEvent/* , {passive: true, capture: false} */);
|
||||
if(listenerSetter) listenerSetter.add(content)(listenerName, onEndEvent);
|
||||
else content.addEventListener(listenerName, onEndEvent/* , {passive: true, capture: false} */);
|
||||
}
|
||||
|
||||
function selectTab(id: number | HTMLElement, animate = true, overrideFrom?: typeof from) {
|
||||
@ -196,9 +201,7 @@ const Transition = (
|
||||
if(from) from.classList.remove('active', 'to', 'from');
|
||||
else if(to) { // fix instant opening back from closed slider (e.g. instant closening and opening right sidebar)
|
||||
const callback = onTransitionEndCallbacks.get(to);
|
||||
if(callback) {
|
||||
callback();
|
||||
}
|
||||
callback?.();
|
||||
}
|
||||
|
||||
if(to) {
|
||||
@ -254,21 +257,24 @@ const Transition = (
|
||||
}
|
||||
|
||||
if(from/* && false */) {
|
||||
let timeout: number;
|
||||
const _from = from;
|
||||
const callback = () => {
|
||||
clearTimeout(timeout);
|
||||
_from.classList.remove('active', 'from');
|
||||
|
||||
if(onTransitionEndCallback) {
|
||||
onTransitionEndCallback();
|
||||
onTransitionEndCallback?.();
|
||||
}
|
||||
|
||||
onTransitionEndCallbacks.delete(_from);
|
||||
};
|
||||
|
||||
if(to) {
|
||||
timeout = window.setTimeout(callback, transitionTime + 100); // something happened to container
|
||||
onTransitionEndCallbacks.set(_from, callback);
|
||||
} else {
|
||||
const timeout = window.setTimeout(callback, transitionTime);
|
||||
timeout = window.setTimeout(callback, transitionTime);
|
||||
onTransitionEndCallbacks.set(_from, () => {
|
||||
clearTimeout(timeout);
|
||||
onTransitionEndCallbacks.delete(_from);
|
||||
@ -290,7 +296,7 @@ const Transition = (
|
||||
|
||||
//selectTab.prevId = -1;
|
||||
selectTab.prevId = () => from ? whichChild(from) : -1;
|
||||
|
||||
|
||||
return selectTab;
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,8 @@ import isInDOM from "../../helpers/dom/isInDOM";
|
||||
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
|
||||
import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes";
|
||||
import onMediaLoad from "../../helpers/onMediaLoad";
|
||||
import throttleWithRaf from "../../helpers/schedulers/throttleWithRaf";
|
||||
import { fastRaf } from "../../helpers/schedulers";
|
||||
import throttle from "../../helpers/schedulers/throttle";
|
||||
import sequentialDom from "../../helpers/sequentialDom";
|
||||
import toHHMMSS from "../../helpers/string/toHHMMSS";
|
||||
import { Message, PhotoSize } from "../../layer";
|
||||
@ -245,7 +246,9 @@ export default async function wrapVideo({doc, container, message, boxWidth, boxH
|
||||
spanTime.innerText = toHHMMSS(globalVideo.duration - globalVideo.currentTime, false);
|
||||
};
|
||||
|
||||
const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);
|
||||
const throttledTimeUpdate = throttle(() => {
|
||||
fastRaf(onTimeUpdate);
|
||||
}, 1000, false);
|
||||
|
||||
const onPlay = () => {
|
||||
video.classList.add('hide');
|
||||
@ -437,14 +440,16 @@ export default async function wrapVideo({doc, container, message, boxWidth, boxH
|
||||
|
||||
if(doc.type === 'video') {
|
||||
const onTimeUpdate = () => {
|
||||
if(!video.videoWidth) {
|
||||
if(!video.duration) {
|
||||
return;
|
||||
}
|
||||
|
||||
spanTime.innerText = toHHMMSS(video.duration - video.currentTime, false);
|
||||
};
|
||||
|
||||
const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);
|
||||
const throttledTimeUpdate = throttle(() => {
|
||||
fastRaf(onTimeUpdate);
|
||||
}, 1e3, false);
|
||||
|
||||
video.addEventListener('timeupdate', throttledTimeUpdate);
|
||||
|
||||
|
@ -16,7 +16,7 @@ export default function getTextWidth(text: string, font: string) {
|
||||
// const perf = performance.now();
|
||||
if(!context) {
|
||||
const canvas = document.createElement('canvas');
|
||||
context = canvas.getContext('2d');
|
||||
context = canvas.getContext('2d', {alpha: false});
|
||||
context.font = font;
|
||||
}
|
||||
|
||||
|
@ -38,12 +38,11 @@ export default function renderImageWithFadeIn(
|
||||
image.addEventListener('animationend', () => {
|
||||
sequentialDom.mutate(() => {
|
||||
image.classList.remove('fade-in');
|
||||
|
||||
if(thumbImage) {
|
||||
thumbImage.remove();
|
||||
}
|
||||
thumbImage?.remove();
|
||||
});
|
||||
}, {once: true});
|
||||
} else {
|
||||
thumbImage?.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1516,7 +1516,7 @@ export class AppDialogsManager {
|
||||
}, {capture: true});
|
||||
|
||||
// cancel link click
|
||||
list.addEventListener('click', (e) => {
|
||||
attachClickEvent(list, (e) => {
|
||||
if(e.button === 0) {
|
||||
cancelEvent(e);
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ import apiManagerProxy from '../mtproto/mtprotoworker';
|
||||
import appRuntimeManager from './appRuntimeManager';
|
||||
import paymentsWrapCurrencyAmount from '../../helpers/paymentsWrapCurrencyAmount';
|
||||
import findUpClassName from '../../helpers/dom/findUpClassName';
|
||||
import { CLICK_EVENT_NAME } from '../../helpers/dom/clickEvent';
|
||||
|
||||
export const CHAT_ANIMATION_GROUP = 'chat';
|
||||
|
||||
@ -368,6 +369,10 @@ export class AppImManager extends EventListenerBase<{
|
||||
const isVisible = parentElement.classList.contains(className);
|
||||
if(!isVisible) {
|
||||
cancelEvent(e);
|
||||
|
||||
if(CLICK_EVENT_NAME !== 'click') {
|
||||
window.addEventListener('click', cancelEvent, {capture: true, once: true});
|
||||
}
|
||||
}
|
||||
|
||||
const duration = 400 / 2;
|
||||
|
@ -11,7 +11,6 @@ import cancelEvent from "../helpers/dom/cancelEvent";
|
||||
import ListenerSetter, { Listener } from "../helpers/listenerSetter";
|
||||
import ButtonMenu from "../components/buttonMenu";
|
||||
import { ButtonMenuToggleHandler } from "../components/buttonMenuToggle";
|
||||
import rootScope from "./rootScope";
|
||||
import ControlsHover from "../helpers/dom/controlsHover";
|
||||
import { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from "../helpers/dom/fullScreen";
|
||||
import toHHMMSS from "../helpers/string/toHHMMSS";
|
||||
@ -20,6 +19,7 @@ import VolumeSelector from "../components/volumeSelector";
|
||||
import debounce from "../helpers/schedulers/debounce";
|
||||
import overlayCounter from "../helpers/overlayCounter";
|
||||
import onMediaLoad from "../helpers/onMediaLoad";
|
||||
import { attachClickEvent } from "../helpers/dom/clickEvent";
|
||||
|
||||
export default class VideoPlayer extends ControlsHover {
|
||||
private static PLAYBACK_RATES = [0.5, 1, 1.5, 2];
|
||||
@ -127,15 +127,15 @@ export default class VideoPlayer extends ControlsHover {
|
||||
leftControls.insertBefore(volumeSelector.btn, timeElapsed.parentElement);
|
||||
|
||||
Array.from(toggle).forEach((button) => {
|
||||
listenerSetter.add(button)('click', () => {
|
||||
attachClickEvent(button, () => {
|
||||
this.togglePlay();
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
});
|
||||
|
||||
if(this.pipButton) {
|
||||
listenerSetter.add(this.pipButton)('click', () => {
|
||||
attachClickEvent(this.pipButton, () => {
|
||||
this.video.requestPictureInPicture();
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
const onPip = (pip: boolean) => {
|
||||
this.wrapper.style.visibility = pip ? 'hidden': '';
|
||||
@ -170,9 +170,9 @@ export default class VideoPlayer extends ControlsHover {
|
||||
}
|
||||
|
||||
if(!IS_TOUCH_SUPPORTED) {
|
||||
listenerSetter.add(video)('click', () => {
|
||||
attachClickEvent(video, () => {
|
||||
this.togglePlay();
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
listenerSetter.add(document)('keydown', (e: KeyboardEvent) => {
|
||||
if(overlayCounter.overlaysActive > 1 || document.pictureInPictureElement === video) { // forward popup is active, etc
|
||||
@ -216,9 +216,9 @@ export default class VideoPlayer extends ControlsHover {
|
||||
}
|
||||
});
|
||||
|
||||
listenerSetter.add(fullScreenButton)('click', () => {
|
||||
attachClickEvent(fullScreenButton, () => {
|
||||
this.toggleFullScreen();
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
addFullScreenListener(wrapper, this.onFullScreen.bind(this, fullScreenButton), listenerSetter);
|
||||
|
||||
|
@ -47,7 +47,7 @@ export default class QueryableWorker extends EventListenerBase<{
|
||||
queryMethodArguments: args
|
||||
});
|
||||
} else {
|
||||
const transfer: (ArrayBuffer | OffscreenCanvas)[] = [];
|
||||
const transfer: Transferable[] = [];
|
||||
args.forEach((arg) => {
|
||||
if(arg instanceof ArrayBuffer) {
|
||||
transfer.push(arg);
|
||||
@ -62,7 +62,7 @@ export default class QueryableWorker extends EventListenerBase<{
|
||||
this.worker.postMessage({
|
||||
queryMethod: queryMethod,
|
||||
queryMethodArguments: args
|
||||
}, transfer as Transferable[]);
|
||||
}, transfer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,8 @@ module.exports = {
|
||||
// directory: path.join(__dirname, 'public')
|
||||
// },
|
||||
compress: true,
|
||||
http2: useLocalNotLocal ? true : (useLocal ? undefined : true),
|
||||
// http2: useLocalNotLocal ? true : (useLocal ? undefined : true),
|
||||
http2: true,
|
||||
https: useLocal ? undefined : {
|
||||
key: fs.readFileSync(__dirname + '/certs/server-key.pem', 'utf8'),
|
||||
cert: fs.readFileSync(__dirname + '/certs/server-cert.pem', 'utf8')
|
||||
|
Loading…
Reference in New Issue
Block a user