diff --git a/src/settings/WatchManager.js b/src/settings/WatchManager.ts similarity index 56% rename from src/settings/WatchManager.js rename to src/settings/WatchManager.ts index 3f54ca929e..560f5956b7 100644 --- a/src/settings/WatchManager.js +++ b/src/settings/WatchManager.ts @@ -14,41 +14,52 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { SettingLevel } from "./SettingLevel"; + +export type CallbackFn = (changedInRoomId: string, atLevel: SettingLevel, newValAtLevel: any) => void; + +const IRRELEVANT_ROOM: symbol = Symbol("any room"); + +interface RoomWatcherMap { + // @ts-ignore - TS wants string-only keys but we know better - https://github.com/Microsoft/TypeScript/issues/1863 + [roomId: string | symbol]: CallbackFn[]; +} + /** * Generalized management class for dealing with watchers on a per-handler (per-level) * basis without duplicating code. Handlers are expected to push updates through this * class, which are then proxied outwards to any applicable watchers. */ export class WatchManager { - _watchers = {}; // { settingName: { roomId: callbackFns[] } } + private watchers: {[settingName: string]: RoomWatcherMap} = {}; // Proxy for handlers to delegate changes to this manager - watchSetting(settingName, roomId, cb) { - if (!this._watchers[settingName]) this._watchers[settingName] = {}; - if (!this._watchers[settingName][roomId]) this._watchers[settingName][roomId] = []; - this._watchers[settingName][roomId].push(cb); + public watchSetting(settingName: string, roomId: string | null, cb: CallbackFn) { + if (!this.watchers[settingName]) this.watchers[settingName] = {}; + if (!this.watchers[settingName][roomId]) this.watchers[settingName][roomId] = []; + this.watchers[settingName][roomId].push(cb); } // Proxy for handlers to delegate changes to this manager - unwatchSetting(cb) { - for (const settingName of Object.keys(this._watchers)) { - for (const roomId of Object.keys(this._watchers[settingName])) { + public unwatchSetting(cb: CallbackFn) { + for (const settingName of Object.keys(this.watchers)) { + for (const roomId of Object.keys(this.watchers[settingName])) { let idx; - while ((idx = this._watchers[settingName][roomId].indexOf(cb)) !== -1) { - this._watchers[settingName][roomId].splice(idx, 1); + while ((idx = this.watchers[settingName][roomId].indexOf(cb)) !== -1) { + this.watchers[settingName][roomId].splice(idx, 1); } } } } - notifyUpdate(settingName, inRoomId, atLevel, newValueAtLevel) { + public notifyUpdate(settingName: string, inRoomId: string, atLevel: SettingLevel, newValueAtLevel: any) { // Dev note: We could avoid raising changes for ultimately inconsequential changes, but // we also don't have a reliable way to get the old value of a setting. Instead, we'll just // let it fall through regardless and let the receiver dedupe if they want to. - if (!this._watchers[settingName]) return; + if (!this.watchers[settingName]) return; - const roomWatchers = this._watchers[settingName]; + const roomWatchers = this.watchers[settingName]; const callbacks = []; if (inRoomId !== null && roomWatchers[inRoomId]) { @@ -59,8 +70,8 @@ export class WatchManager { // Fire updates to all the individual room watchers too, as they probably // care about the change higher up. callbacks.push(...Object.values(roomWatchers).reduce((r, a) => [...r, ...a], [])); - } else if (roomWatchers[null]) { - callbacks.push(...roomWatchers[null]); + } else if (roomWatchers[IRRELEVANT_ROOM]) { + callbacks.push(...roomWatchers[IRRELEVANT_ROOM]); } for (const callback of callbacks) {