From 60cb09077f24a9c02b8dd08ad8e50566602a7a04 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Fri, 14 Jun 2024 01:01:19 -0700 Subject: [PATCH] Support multiple change event listeners --- .../stendhal/ui/dialog/settings/SoundTab.ts | 8 +-- .../stendhal/ui/dialog/settings/VisualsTab.ts | 12 ++--- src/js/stendhal/ui/toolkit/WidgetComponent.ts | 51 +++++++++++++++++-- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/js/stendhal/ui/dialog/settings/SoundTab.ts b/src/js/stendhal/ui/dialog/settings/SoundTab.ts index d83c98c960..e2bd9ac90c 100644 --- a/src/js/stendhal/ui/dialog/settings/SoundTab.ts +++ b/src/js/stendhal/ui/dialog/settings/SoundTab.ts @@ -39,12 +39,12 @@ export class SoundTab extends AbstractSettingsTab { // TODO: add DOM element creation to `SettingsDialog.createCheckBox` const chkSound = new SettingsComponent("chk_sound", "Enable sound"); chkSound.setValue(soundEnabled); - chkSound.onchange = (evt: Event) => { + chkSound.addListener((evt: Event) => { soundEnabled = chkSound.getValue() as boolean; config.set("sound", soundEnabled); sound.onStateChanged(); this.setSlidersEnabled(soundEnabled); - }; + }); chkSound.addTo(col1); const layers = [ @@ -61,9 +61,9 @@ export class SoundTab extends AbstractSettingsTab { const label = group[1]; const slider = new SliderComponent("setting-vol-" + layer, label, 0, 100); slider.setValue(sound.getVolume(layer) * 100); - slider.onchange = function(evt: Event) { + slider.addListener(function(evt: Event) { sound.setVolume(layer, slider.getValue() / 100); - } + }); slider.addTo(col1); this.sliders.push(slider); } diff --git a/src/js/stendhal/ui/dialog/settings/VisualsTab.ts b/src/js/stendhal/ui/dialog/settings/VisualsTab.ts index e4973578c3..e3f15ca81f 100644 --- a/src/js/stendhal/ui/dialog/settings/VisualsTab.ts +++ b/src/js/stendhal/ui/dialog/settings/VisualsTab.ts @@ -56,24 +56,24 @@ export class VisualsTab extends AbstractSettingsTab { const chkAnimate = new SettingsComponent("chk_animate", "Animate"); chkAnimate.setValue(animate); chkAnimate.setEnabled(indicateActivity); - chkAnimate.onchange = (evt: Event) => { + chkAnimate.addListener((evt: Event) => { animate = chkAnimate.getValue() as boolean; config.set("activity-indicator.animate", animate); StandardMessages.changeNeedsRefresh(); parent.refresh(); - } + }); const chkActivityInd = new SettingsComponent("chk_activityindicator", "Object activity indicator"); chkActivityInd.setTooltip("Display an indictor over certain interactive objects and corpses" + " that aren't empty"); chkActivityInd.setValue(indicateActivity); - chkActivityInd.onchange = (evt: Event) => { + chkActivityInd.addListener((evt: Event) => { indicateActivity = chkActivityInd.getValue() as boolean; config.set("activity-indicator", indicateActivity); chkAnimate.setEnabled(indicateActivity); StandardMessages.changeNeedsRefresh(); parent.refresh(); - }; + }); chkActivityInd.addTo(col1); chkAnimate.addTo(col1); chkAnimate.componentElement.classList.add("indented"); @@ -81,12 +81,12 @@ export class VisualsTab extends AbstractSettingsTab { const chkParallax = new SettingsComponent("chk_parallax", "Parallax scrolling backgrounds"); chkParallax.setTooltip("Parallax scrolling enabled", "Parallax scrolling disabled"); chkParallax.setValue(config.getBoolean("effect.parallax")); - chkParallax.onchange = (evt: Event) => { + chkParallax.addListener((evt: Event) => { const enabled = chkParallax.getValue() as boolean; config.set("effect.parallax", enabled); StandardMessages.changeNeedsRefresh(); parent.refresh(); - } + }); chkParallax.addTo(col1); } } diff --git a/src/js/stendhal/ui/toolkit/WidgetComponent.ts b/src/js/stendhal/ui/toolkit/WidgetComponent.ts index 5444d3ec9e..d12a7a5ce8 100644 --- a/src/js/stendhal/ui/toolkit/WidgetComponent.ts +++ b/src/js/stendhal/ui/toolkit/WidgetComponent.ts @@ -25,7 +25,7 @@ export abstract class WidgetComponent extends ComponentBase { /** Setting type. */ protected readonly type: WidgetType; /** Called when the settings state or value changes. */ - public onchange?: Function; + private changeListeners: Function[]; private initialized = false; @@ -39,6 +39,7 @@ export abstract class WidgetComponent extends ComponentBase { constructor(type: WidgetType) { super(); this.type = type; + this.changeListeners = []; } /** @@ -56,13 +57,57 @@ export abstract class WidgetComponent extends ComponentBase { // listen for changes to component element this.componentElement.addEventListener("change", (evt: Event) => { - if (this.onchange) { - this.onchange(evt); + for (const listener of this.changeListeners) { + listener(evt); } this.refresh(); }); } + /** + * Adds listener for change event. + * + * @param {Function} listener + * Function to call when change event occurs. + * @return {Function} + */ + addListener(listener: Function): Function { + this.changeListeners.push(listener); + return listener; + } + + /** + * Adds listener for change event. + * + * @param {number} idx + * Insertion index in list of listeners. + * @param {Function} listener + * Function to call when change event occurs. + * @return {Function} + */ + insertListener(idx: number, listener: Function): Function { + this.changeListeners.splice(idx, 0, listener); + return listener; + } + + /** + * Removes change event listener. + * + * @param {number|Function} listener + * Listener function or index. + */ + removeListener(listener: number|Function) { + let idx: number; + if (typeof(listener) === "number") { + idx = listener as number; + } else { + idx = this.changeListeners.indexOf(listener as Function); + } + if (idx > -1 && idx < this.changeListeners.length) { + this.changeListeners.splice(idx, 1); + } + } + /** * Adds as child to DOM element. *