From 070ae70f7cd635f2b8742a6c406d1ef7b09ccc51 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 16 Feb 2020 16:33:48 -0500 Subject: [PATCH] Create EventListenerCollection class --- .eslintrc.json | 1 + ext/bg/js/settings/dictionaries.js | 24 +++--------- ext/mixed/js/core.js | 23 ++++++++++++ ext/mixed/js/display.js | 59 ++++++++++++++---------------- ext/mixed/js/text-scanner.js | 24 +++--------- 5 files changed, 64 insertions(+), 67 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index d4ae215b..bda308e2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -51,6 +51,7 @@ "stringReplaceAsync": "readonly", "parseUrl": "readonly", "EventDispatcher": "readonly", + "EventListenerCollection": "readonly", "EXTENSION_IS_BROWSER_EDGE": "readonly" } }, diff --git a/ext/bg/js/settings/dictionaries.js b/ext/bg/js/settings/dictionaries.js index fb459404..adad76fb 100644 --- a/ext/bg/js/settings/dictionaries.js +++ b/ext/bg/js/settings/dictionaries.js @@ -179,7 +179,7 @@ class SettingsDictionaryEntryUI { this.dictionaryInfo = dictionaryInfo; this.optionsDictionary = optionsDictionary; this.counts = null; - this.eventListeners = []; + this.eventListeners = new EventListenerCollection(); this.isDeleting = false; this.content = content; @@ -198,10 +198,10 @@ class SettingsDictionaryEntryUI { this.applyValues(); - this.addEventListener(this.enabledCheckbox, 'change', (e) => this.onEnabledChanged(e), false); - this.addEventListener(this.allowSecondarySearchesCheckbox, 'change', (e) => this.onAllowSecondarySearchesChanged(e), false); - this.addEventListener(this.priorityInput, 'change', (e) => this.onPriorityChanged(e), false); - this.addEventListener(this.deleteButton, 'click', (e) => this.onDeleteButtonClicked(e), false); + this.eventListeners.addEventListener(this.enabledCheckbox, 'change', (e) => this.onEnabledChanged(e), false); + this.eventListeners.addEventListener(this.allowSecondarySearchesCheckbox, 'change', (e) => this.onAllowSecondarySearchesChanged(e), false); + this.eventListeners.addEventListener(this.priorityInput, 'change', (e) => this.onPriorityChanged(e), false); + this.eventListeners.addEventListener(this.deleteButton, 'click', (e) => this.onDeleteButtonClicked(e), false); } cleanup() { @@ -212,7 +212,7 @@ class SettingsDictionaryEntryUI { this.content = null; } this.dictionaryInfo = null; - this.clearEventListeners(); + this.eventListeners.removeAllEventListeners(); } setCounts(counts) { @@ -229,18 +229,6 @@ class SettingsDictionaryEntryUI { this.parent.save(); } - addEventListener(node, type, listener, options) { - node.addEventListener(type, listener, options); - this.eventListeners.push([node, type, listener, options]); - } - - clearEventListeners() { - for (const [node, type, listener, options] of this.eventListeners) { - node.removeEventListener(type, listener, options); - } - this.eventListeners = []; - } - applyValues() { this.enabledCheckbox.checked = this.optionsDictionary.enabled; this.allowSecondarySearchesCheckbox.checked = this.optionsDictionary.allowSecondarySearches; diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index b6ecb48b..330a30fb 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -236,6 +236,29 @@ class EventDispatcher { } } +class EventListenerCollection { + constructor() { + this._eventListeners = []; + } + + get size() { + return this._eventListeners.length; + } + + addEventListener(node, type, listener, options) { + node.addEventListener(type, listener, options); + this._eventListeners.push([node, type, listener, options]); + } + + removeAllEventListeners() { + if (this._eventListeners.length === 0) { return; } + for (const [node, type, listener, options] of this._eventListeners) { + node.removeEventListener(type, listener, options); + } + this._eventListeners = []; + } +} + /* * Default message handlers diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index e914b082..8113260c 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -35,8 +35,8 @@ class Display { this.audioCache = new Map(); this.styleNode = null; - this.eventListeners = []; - this.persistentEventListeners = []; + this.eventListeners = new EventListenerCollection(); + this.persistentEventListeners = new EventListenerCollection(); this.interactive = false; this.eventListenersActive = false; this.clickScanPrevent = false; @@ -301,13 +301,23 @@ class Display { this.interactive = interactive; if (interactive) { - Display.addEventListener(this.persistentEventListeners, document, 'keydown', this.onKeyDown.bind(this), false); - Display.addEventListener(this.persistentEventListeners, document, 'wheel', this.onWheel.bind(this), {passive: false}); - Display.addEventListener(this.persistentEventListeners, document.querySelector('.action-previous'), 'click', this.onSourceTermView.bind(this)); - Display.addEventListener(this.persistentEventListeners, document.querySelector('.action-next'), 'click', this.onNextTermView.bind(this)); - Display.addEventListener(this.persistentEventListeners, document.querySelector('.navigation-header'), 'wheel', this.onHistoryWheel.bind(this), {passive: false}); + const actionPrevious = document.querySelector('.action-previous'); + const actionNext = document.querySelector('.action-next'); + const navigationHeader = document.querySelector('.navigation-header'); + + this.persistentEventListeners.addEventListener(document, 'keydown', this.onKeyDown.bind(this), false); + this.persistentEventListeners.addEventListener(document, 'wheel', this.onWheel.bind(this), {passive: false}); + if (actionPrevious !== null) { + this.persistentEventListeners.addEventListener(actionPrevious, 'click', this.onSourceTermView.bind(this)); + } + if (actionNext !== null) { + this.persistentEventListeners.addEventListener(actionNext, 'click', this.onNextTermView.bind(this)); + } + if (navigationHeader !== null) { + this.persistentEventListeners.addEventListener(navigationHeader, 'wheel', this.onHistoryWheel.bind(this), {passive: false}); + } } else { - Display.clearEventListeners(this.persistentEventListeners); + this.persistentEventListeners.removeAllEventListeners(); } this.setEventListenersActive(this.eventListenersActive); } @@ -318,23 +328,23 @@ class Display { this.eventListenersActive = active; if (active) { - this.addEventListeners('.action-add-note', 'click', this.onNoteAdd.bind(this)); - this.addEventListeners('.action-view-note', 'click', this.onNoteView.bind(this)); - this.addEventListeners('.action-play-audio', 'click', this.onAudioPlay.bind(this)); - this.addEventListeners('.kanji-link', 'click', this.onKanjiLookup.bind(this)); + this.addMultipleEventListeners('.action-add-note', 'click', this.onNoteAdd.bind(this)); + this.addMultipleEventListeners('.action-view-note', 'click', this.onNoteView.bind(this)); + this.addMultipleEventListeners('.action-play-audio', 'click', this.onAudioPlay.bind(this)); + this.addMultipleEventListeners('.kanji-link', 'click', this.onKanjiLookup.bind(this)); if (this.options.scanning.enablePopupSearch) { - this.addEventListeners('.term-glossary-item, .tag', 'mouseup', this.onGlossaryMouseUp.bind(this)); - this.addEventListeners('.term-glossary-item, .tag', 'mousedown', this.onGlossaryMouseDown.bind(this)); - this.addEventListeners('.term-glossary-item, .tag', 'mousemove', this.onGlossaryMouseMove.bind(this)); + this.addMultipleEventListeners('.term-glossary-item, .tag', 'mouseup', this.onGlossaryMouseUp.bind(this)); + this.addMultipleEventListeners('.term-glossary-item, .tag', 'mousedown', this.onGlossaryMouseDown.bind(this)); + this.addMultipleEventListeners('.term-glossary-item, .tag', 'mousemove', this.onGlossaryMouseMove.bind(this)); } } else { - Display.clearEventListeners(this.eventListeners); + this.eventListeners.removeAllEventListeners(); } } - addEventListeners(selector, type, listener, options) { + addMultipleEventListeners(selector, type, listener, options) { for (const node of this.container.querySelectorAll(selector)) { - Display.addEventListener(this.eventListeners, node, type, listener, options); + this.eventListeners.addEventListener(node, type, listener, options); } } @@ -793,19 +803,6 @@ class Display { return -1; } - static addEventListener(eventListeners, object, type, listener, options) { - if (object === null) { return; } - object.addEventListener(type, listener, options); - eventListeners.push([object, type, listener, options]); - } - - static clearEventListeners(eventListeners) { - for (const [object, type, listener, options] of eventListeners) { - object.removeEventListener(type, listener, options); - } - eventListeners.length = 0; - } - static getElementTop(element) { const elementRect = element.getBoundingClientRect(); const documentRect = document.documentElement.getBoundingClientRect(); diff --git a/ext/mixed/js/text-scanner.js b/ext/mixed/js/text-scanner.js index e6da1e5e..aa10bbaf 100644 --- a/ext/mixed/js/text-scanner.js +++ b/ext/mixed/js/text-scanner.js @@ -31,7 +31,7 @@ class TextScanner { this.options = null; this.enabled = false; - this.eventListeners = []; + this.eventListeners = new EventListenerCollection(); this.primaryTouchIdentifier = null; this.preventNextContextMenu = false; @@ -229,7 +229,7 @@ class TextScanner { } } else { if (this.enabled) { - this.clearEventListeners(); + this.eventListeners.removeAllEventListeners(); this.enabled = false; } this.onSearchClear(false); @@ -237,13 +237,13 @@ class TextScanner { } hookEvents() { - let eventListeners = this.getMouseEventListeners(); + let eventListenerInfos = this.getMouseEventListeners(); if (this.options.scanning.touchInputEnabled) { - eventListeners = eventListeners.concat(this.getTouchEventListeners()); + eventListenerInfos = eventListenerInfos.concat(this.getTouchEventListeners()); } - for (const [node, type, listener, options] of eventListeners) { - this.addEventListener(node, type, listener, options); + for (const [node, type, listener, options] of eventListenerInfos) { + this.eventListeners.addEventListener(node, type, listener, options); } } @@ -268,18 +268,6 @@ class TextScanner { ]; } - addEventListener(node, type, listener, options) { - node.addEventListener(type, listener, options); - this.eventListeners.push([node, type, listener, options]); - } - - clearEventListeners() { - for (const [node, type, listener, options] of this.eventListeners) { - node.removeEventListener(type, listener, options); - } - this.eventListeners = []; - } - setOptions(options) { this.options = options; this.setEnabled(this.options.general.enable);