Browse Source

Fix memory leaks

master
Eduard Kuzmenko 2 years ago
parent
commit
d2d184d242
  1. 45
      src/components/appSearchSuper..ts
  2. 2
      src/components/call/videoCanvasBlur.ts
  3. 8
      src/components/chat/bubbles.ts
  4. 5
      src/components/chat/chat.ts
  5. 4
      src/components/chat/gradientRenderer.ts
  6. 5
      src/components/chat/replyKeyboard.ts
  7. 6
      src/components/chat/selection.ts
  8. 33
      src/components/checkboxField.ts
  9. 3
      src/components/emoticonsDropdown/tabs/emoji.ts
  10. 3
      src/components/emoticonsDropdown/tabs/gifs.ts
  11. 11
      src/components/horizontalMenu.ts
  12. 16
      src/components/peerProfile.ts
  13. 1
      src/components/peerProfileAvatars.ts
  14. 2
      src/components/popups/reactedList.ts
  15. 16
      src/components/row.ts
  16. 18
      src/components/scrollable.ts
  17. 2
      src/components/sidebarLeft/tabs/autoDownload/file.ts
  18. 17
      src/components/sidebarLeft/tabs/autoDownload/photo.ts
  19. 2
      src/components/sidebarLeft/tabs/autoDownload/video.ts
  20. 15
      src/components/sidebarLeft/tabs/dataAndStorage.ts
  21. 19
      src/components/sidebarLeft/tabs/editFolder.ts
  22. 21
      src/components/sidebarLeft/tabs/generalSettings.ts
  23. 5
      src/components/sidebarLeft/tabs/includedChats.ts
  24. 5
      src/components/sidebarLeft/tabs/newChannel.ts
  25. 7
      src/components/sidebarLeft/tabs/newGroup.ts
  26. 6
      src/components/sidebarLeft/tabs/notifications.ts
  27. 27
      src/components/sidebarLeft/tabs/privacyAndSecurity.ts
  28. 25
      src/components/sidebarLeft/tabs/settings.ts
  29. 16
      src/components/sidebarRight/index.ts
  30. 6
      src/components/sidebarRight/tabs/chatReactions.ts
  31. 3
      src/components/sidebarRight/tabs/chatType.ts
  32. 7
      src/components/sidebarRight/tabs/editChat.ts
  33. 3
      src/components/sidebarRight/tabs/editContact.ts
  34. 3
      src/components/sidebarRight/tabs/groupPermissions.ts
  35. 11
      src/components/sidebarRight/tabs/sharedMedia.ts
  36. 3
      src/components/singleTransition.ts
  37. 2
      src/components/slider.ts
  38. 1
      src/components/sliderTab.ts
  39. 30
      src/components/transition.ts
  40. 13
      src/components/wrappers/video.ts
  41. 2
      src/helpers/canvas/getTextWidth.ts
  42. 7
      src/helpers/dom/renderImageWithFadeIn.ts
  43. 2
      src/lib/appManagers/appDialogsManager.ts
  44. 5
      src/lib/appManagers/appImManager.ts
  45. 18
      src/lib/mediaPlayer.ts
  46. 4
      src/lib/rlottie/queryableWorker.ts
  47. 3
      webpack.common.js

45
src/components/appSearchSuper..ts

@ -69,6 +69,8 @@ import { attachContextMenuListener } from "../helpers/dom/attachContextMenuListe @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}

2
src/components/call/videoCanvasBlur.ts

@ -13,7 +13,7 @@ export default function callVideoCanvasBlur(video: HTMLVideoElement) { @@ -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);

8
src/components/chat/bubbles.ts

@ -1937,7 +1937,7 @@ export default class ChatBubbles { @@ -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 { @@ -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 { @@ -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 { @@ -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);
}

5
src/components/chat/chat.ts

@ -458,6 +458,11 @@ export default class Chat extends EventListenerBase<{ @@ -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;
}

4
src/components/chat/gradientRenderer.ts

@ -283,11 +283,11 @@ export default class ChatBackgroundGradientRenderer { @@ -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();
}

5
src/components/chat/replyKeyboard.ts

@ -19,6 +19,7 @@ import safeAssign from "../../helpers/object/safeAssign"; @@ -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 { @@ -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 { @@ -103,7 +104,7 @@ export default class ReplyKeyboard extends DropdownHover {
}
this.toggle(false);
});
}, {listenerSetter: this.listenerSetter});
return super.init();
}

6
src/components/chat/selection.ts

@ -533,7 +533,7 @@ export class SearchSelection extends AppSelection { @@ -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 { @@ -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 { @@ -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');

33
src/components/checkboxField.ts

@ -9,6 +9,7 @@ import { LangPackKey, _i18n } from "../lib/langPack"; @@ -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 = { @@ -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 { @@ -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 { @@ -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;

3
src/components/emoticonsDropdown/tabs/emoji.ts

@ -24,6 +24,7 @@ import { AppManagers } from "../../../lib/appManagers/managers"; @@ -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 { @@ -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) => {

3
src/components/emoticonsDropdown/tabs/gifs.ts

@ -9,6 +9,7 @@ import GifsMasonry from "../../gifsMasonry"; @@ -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 { @@ -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
src/components/horizontalMenu.ts

@ -11,6 +11,8 @@ import { fastRaf } from "../helpers/schedulers"; @@ -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( @@ -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( @@ -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( @@ -129,7 +132,7 @@ export function horizontalMenu(
}
selectTarget(target, id);
});
}, {listenerSetter});
return proxy;
}

16
src/components/peerProfile.ts

@ -105,7 +105,8 @@ export default class PeerProfile { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -457,5 +462,6 @@ export default class PeerProfile {
public destroy() {
this.clearSetMoreDetailsTimeout();
clearInterval(this.setPeerStatusInterval);
this.avatars?.cleanup();
}
}

1
src/components/peerProfileAvatars.ts

@ -409,5 +409,6 @@ export default class PeerProfileAvatars { @@ -409,5 +409,6 @@ export default class PeerProfileAvatars {
public cleanup() {
this.listenerSetter.removeAll();
this.swipeHandler.removeListeners();
this.intersectionObserver?.disconnect();
}
}

2
src/components/popups/reactedList.ts

@ -185,7 +185,7 @@ export default class PopupReactedList extends PopupElement { @@ -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);

16
src/components/row.ts

@ -12,6 +12,8 @@ import RadioForm from "./radioForm"; @@ -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 { @@ -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 { @@ -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 { @@ -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');

18
src/components/scrollable.ts

@ -143,6 +143,13 @@ export class ScrollableBase { @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}

2
src/components/sidebarLeft/tabs/autoDownload/file.ts

@ -21,7 +21,7 @@ export default class AppAutoDownloadFileTab extends SliderSuperTabEventable { @@ -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;

17
src/components/sidebarLeft/tabs/autoDownload/photo.ts

@ -5,11 +5,12 @@ @@ -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 @@ -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 { @@ -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);
}
}

2
src/components/sidebarLeft/tabs/autoDownload/video.ts

@ -12,7 +12,7 @@ export default class AppAutoDownloadVideoTab extends SliderSuperTabEventable { @@ -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);
}
}

15
src/components/sidebarLeft/tabs/dataAndStorage.ts

@ -75,7 +75,8 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable { @@ -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 { @@ -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 { @@ -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 { @@ -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);

19
src/components/sidebarLeft/tabs/editFolder.ts

@ -24,6 +24,7 @@ import deepEqual from "../../../helpers/object/deepEqual"; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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);

21
src/components/sidebarLeft/tabs/generalSettings.ts

@ -111,7 +111,8 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;

5
src/components/sidebarLeft/tabs/includedChats.ts

@ -19,6 +19,7 @@ import copy from "../../../helpers/object/copy"; @@ -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 { @@ -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 { @@ -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) => {

5
src/components/sidebarLeft/tabs/newChannel.ts

@ -13,6 +13,7 @@ import AppAddMembersTab from "./addMembers"; @@ -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 { @@ -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 { @@ -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);

7
src/components/sidebarLeft/tabs/newGroup.ts

@ -14,6 +14,7 @@ import I18n from "../../../lib/langPack"; @@ -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 { @@ -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 { @@ -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 { @@ -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',

6
src/components/sidebarLeft/tabs/notifications.ts

@ -36,11 +36,13 @@ export default class AppNotificationsTab extends SliderSuperTabEventable { @@ -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 { @@ -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) => {

27
src/components/sidebarLeft/tabs/privacyAndSecurity.ts

@ -56,7 +56,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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['_']) => {

25
src/components/sidebarLeft/tabs/settings.ts

@ -27,6 +27,7 @@ import { SliderSuperTabConstructable } from "../../sliderTab"; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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();
}
}

16
src/components/sidebarRight/index.ts

@ -46,15 +46,19 @@ export class AppSidebarRight extends SidebarSlider { @@ -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);
}

6
src/components/sidebarRight/tabs/chatReactions.ts

@ -29,7 +29,8 @@ export default class AppChatReactionsTab extends SliderSuperTabEventable { @@ -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 { @@ -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({

3
src/components/sidebarRight/tabs/chatType.ts

@ -78,7 +78,8 @@ export default class AppChatTypeTab extends SliderSuperTabEventable { @@ -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'});

7
src/components/sidebarRight/tabs/editChat.ts

@ -113,7 +113,8 @@ export default class AppEditChatTab extends SliderSuperTab { @@ -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 { @@ -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 { @@ -182,6 +184,7 @@ export default class AppEditChatTab extends SliderSuperTab {
tab.open();
},
icon: 'permissions',
listenerSetter: this.listenerSetter
});
const setPermissionsLength = async() => {

3
src/components/sidebarRight/tabs/editContact.ts

@ -117,7 +117,8 @@ export default class AppEditContactTab extends SliderSuperTab { @@ -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));

3
src/components/sidebarRight/tabs/groupPermissions.ts

@ -185,7 +185,8 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable { @@ -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) => {

11
src/components/sidebarRight/tabs/sharedMedia.ts

@ -85,7 +85,7 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -458,5 +458,6 @@ export default class AppSharedMediaTab extends SliderSuperTab {
this.destroyable = true;
this.onCloseAfterTimeout();
this.profile.destroy();
this.searchSuper.destroy();
}
}

3
src/components/singleTransition.ts

@ -19,6 +19,9 @@ const SetTransition = ( @@ -19,6 +19,9 @@ const SetTransition = (
clearTimeout(+timeout);
}
// useRafs = undefined;
// duration = 0;
if(raf !== undefined) {
window.cancelAnimationFrame(+raf);
if(!useRafs) {

2
src/components/slider.ts

@ -152,7 +152,7 @@ export default class SidebarSlider { @@ -152,7 +152,7 @@ export default class SidebarSlider {
if(tab.onCloseAfterTimeout) {
setTimeout(() => {
tab.onCloseAfterTimeout();
}, TRANSITION_TIME);
}, TRANSITION_TIME + 30);
}
}
}

1
src/components/sliderTab.ts

@ -107,6 +107,7 @@ export default class SliderSuperTab implements SliderTab { @@ -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) {

30
src/components/transition.ts

@ -9,6 +9,7 @@ import deferredPromise, { CancellablePromise } from "../helpers/cancellablePromi @@ -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 = ( @@ -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 = ( @@ -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 = ( @@ -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 = ( @@ -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 = ( @@ -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 = ( @@ -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 = ( @@ -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 = ( @@ -290,7 +296,7 @@ const Transition = (
//selectTab.prevId = -1;
selectTab.prevId = () => from ? whichChild(from) : -1;
return selectTab;
};

13
src/components/wrappers/video.ts

@ -15,7 +15,8 @@ import isInDOM from "../../helpers/dom/isInDOM"; @@ -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 @@ -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 @@ -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);

2
src/helpers/canvas/getTextWidth.ts

@ -16,7 +16,7 @@ export default function getTextWidth(text: string, font: string) { @@ -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;
}

7
src/helpers/dom/renderImageWithFadeIn.ts

@ -38,12 +38,11 @@ export default function renderImageWithFadeIn( @@ -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();
}
});
});

2
src/lib/appManagers/appDialogsManager.ts

@ -1516,7 +1516,7 @@ export class AppDialogsManager { @@ -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);
}

5
src/lib/appManagers/appImManager.ts

@ -89,6 +89,7 @@ import apiManagerProxy from '../mtproto/mtprotoworker'; @@ -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<{ @@ -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;

18
src/lib/mediaPlayer.ts

@ -11,7 +11,6 @@ import cancelEvent from "../helpers/dom/cancelEvent"; @@ -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"; @@ -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 { @@ -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 { @@ -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 { @@ -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);

4
src/lib/rlottie/queryableWorker.ts

@ -47,7 +47,7 @@ export default class QueryableWorker extends EventListenerBase<{ @@ -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<{ @@ -62,7 +62,7 @@ export default class QueryableWorker extends EventListenerBase<{
this.worker.postMessage({
queryMethod: queryMethod,
queryMethodArguments: args
}, transfer as Transferable[]);
}, transfer);
}
}
}

3
webpack.common.js

@ -185,7 +185,8 @@ module.exports = { @@ -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…
Cancel
Save