From 98f180b3304dbb8756f670b12601cc02171162d8 Mon Sep 17 00:00:00 2001 From: Rintim Date: Mon, 27 Nov 2023 19:15:32 +0800 Subject: [PATCH 1/3] pref: choose rxjs-like style to write `lib.announce`. --- game/src/lib/announce.js | 133 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 game/src/lib/announce.js diff --git a/game/src/lib/announce.js b/game/src/lib/announce.js new file mode 100644 index 000000000..1960aae2b --- /dev/null +++ b/game/src/lib/announce.js @@ -0,0 +1,133 @@ +// TODO: 补充一点描述 + +/** + * @type {WeakMap} + */ +const vm = new WeakMap(); + +/** + * + */ +export class Announce { + /** + * @type {EventTarget} + */ + #handler; + + /** + * @type {WeakMap} + */ + #records; + + constructor() { + this.#handler = new EventTarget(); + this.#records = new WeakMap(); + } + + /** + * 推送任意数据给所有监听了指定事件的订阅者,并返回给定的数据 + * + * 若不存在订阅指定事件的订阅者,则推送的数据将无意义 + * + * @template T + * @param {string} name - 要推送事件的名称 + * @param {T} values - 要推送的数据 + * @returns {T} + */ + publish(name, values) { + this.#handler.dispatchEvent(new CustomEvent(name, { + detail: [values, name] + })); + return values; + } + + /** + * 订阅给定名字的事件,并返回给定的函数 + * + * 在事件触发时执行给定的函数 + * + * 给定的函数将被存储至当前实例中,用于取消订阅时获取 + * + * @template T + * @param {string} name - 要订阅事件的名称 + * @param {(values: T) => void} method - 事件触发时执行的函数 + * @returns {(values: T) => void} + */ + subscribe(name, method) { + let subscriber; + if (this.#records.has(method)) + subscriber = this.#records.get(method); + else { + subscriber = new AnnounceSubscriber(method, this.#handler); + this.#records.set(method, subscriber); + } + subscriber.subscribe(name); + return method; + } + + /** + * 取消指定事件某一个函数的订阅,并返回该函数 + * + * 给定的函数将不再于事件触发时执行,其余同事件需触发的函数不受限制 + * + * @template T + * @param {string} name - 要取消订阅事件的名称 + * @param {(values: T) => void} method - 订阅指定事件的函数 + * @returns {(values: T) => void} + */ + unsubscribe(name, method) { + if (this.#records.has(method)) { + const subscriber = this.#records.get(method); + subscriber.unsubscribe(name); + if (subscriber.isEmpty) + this.#records.delete(method); + } + return method; + } +} + +/** + * @template T + */ +class AnnounceSubscriber { + /** + * @type {function(CustomEvent): void} + */ + #content; + + /** + * @type {string[]} + */ + #listening + + /** + * + * @param {function(T, string): void} content + * @param {EventTarget} target + */ + constructor(content, target) { + this.#content = function (event) { + content(event.detail[0], event.detail[1]); + } + this.#listening = []; + + vm.set(this, target); + } + + get isEmpty() { + return this.#listening.length <= 0; + } + + /** + * @param {string} name + */ + subscribe(name) { + vm.get(this).addEventListener(name, this.#content); + this.#listening.add(name); + } + + unsubscribe() { + vm.get(this).removeEventListener(name, this.#content); + this.#listening.remove(name); + } +} From e050c8b1667e08be1b8e8aaef118a990933c9c06 Mon Sep 17 00:00:00 2001 From: Rintim Date: Mon, 27 Nov 2023 19:16:35 +0800 Subject: [PATCH 2/3] feat: provide announce time for theme change. --- game/game.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/game/game.js b/game/game.js index b9215318e..8bf10a89e 100644 --- a/game/game.js +++ b/game/game.js @@ -1563,25 +1563,30 @@ new Promise(resolve=>{ node.menu=ui.create.div(node,'','
'); } }, - onclick:function(theme){ + onclick:gnc.of(function*(theme){ game.saveConfig('theme',theme); ui.arena.hide(); lib.init.background(); if(lib.config.autostyle){ - if(theme=='simple'){ - lib.configMenu.appearence.config.player_border.onclick('slim'); + if(theme === "simple"){ + lib.configMenu.appearence.config.player_border.onclick("slim"); } else{ - lib.configMenu.appearence.config.player_border.onclick('normal'); + lib.configMenu.appearence.config.player_border.onclick("normal"); } } - setTimeout(function(){ - var theme=ui.css.theme; - ui.css.theme=lib.init.css(lib.assetURL+'theme/'+lib.config.theme,'style'); - theme.remove(); - setTimeout(function(){ui.arena.show();},100); - },500); - } + lib.announce.publish("Noname.Apperaence.Theme.onChanging", theme); + yield new Promise(resolve => setTimeout(resolve, 500)); + + const deletingTheme = ui.css.theme; + ui.css.theme=lib.init.css(lib.assetURL+'theme/'+lib.config.theme,'style'); + deletingTheme.remove(); + lib.announce.publish("Noname.Apperaence.Theme.onChanged", theme); + yield new Promise(resolve => setTimeout(resolve, 100)); + + ui.arena.show(); + lib.announce.publish("Noname.Apperaence.Theme.onChangeFinished", theme); + }) }, layout:{ name:'布局', From dd74345242ed7bc6e47d2eb8217b03f030eddab1 Mon Sep 17 00:00:00 2001 From: Ansolve Date: Mon, 27 Nov 2023 19:27:55 +0800 Subject: [PATCH 3/3] refactor: use dependency inject. --- game/src/lib/announce.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/game/src/lib/announce.js b/game/src/lib/announce.js index 1960aae2b..a3e8e17f6 100644 --- a/game/src/lib/announce.js +++ b/game/src/lib/announce.js @@ -12,16 +12,28 @@ export class Announce { /** * @type {EventTarget} */ - #handler; + #eventTarget; /** * @type {WeakMap} */ #records; - constructor() { - this.#handler = new EventTarget(); - this.#records = new WeakMap(); + /** + * @type {FunctionConstructor} + */ + #SubscriberType; + + /** + * + * @param {EventTarget} eventTarget + * @param {WeakMap} records + * @param {FunctionConstructor} [SubscriberType] + */ + constructor(eventTarget, records, SubscriberType = AnnounceSubscriber) { + this.#eventTarget = eventTarget; + this.#records = records; + this.#SubscriberType = SubscriberType; } /** @@ -35,7 +47,7 @@ export class Announce { * @returns {T} */ publish(name, values) { - this.#handler.dispatchEvent(new CustomEvent(name, { + this.#eventTarget.dispatchEvent(new CustomEvent(name, { detail: [values, name] })); return values; @@ -58,7 +70,7 @@ export class Announce { if (this.#records.has(method)) subscriber = this.#records.get(method); else { - subscriber = new AnnounceSubscriber(method, this.#handler); + subscriber = new this.#SubscriberType(method, this.#eventTarget); this.#records.set(method, subscriber); } subscriber.subscribe(name);