mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
132 lines
4.6 KiB
JavaScript
132 lines
4.6 KiB
JavaScript
/*
|
|
* Copyright (C) 2023-2025 Yomitan Authors
|
|
* Copyright (C) 2019-2022 Yomichan Authors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import {EventDispatcher} from './event-dispatcher.js';
|
|
import {generateId} from './utilities.js';
|
|
|
|
/**
|
|
* Class representing a generic value with an override stack.
|
|
* Changes can be observed by listening to the 'change' event.
|
|
* @template [T=unknown]
|
|
* @augments EventDispatcher<import('dynamic-property').Events<T>>
|
|
*/
|
|
export class DynamicProperty extends EventDispatcher {
|
|
/**
|
|
* Creates a new instance with the specified value.
|
|
* @param {T} value The value to assign.
|
|
*/
|
|
constructor(value) {
|
|
super();
|
|
/** @type {T} */
|
|
this._value = value;
|
|
/** @type {T} */
|
|
this._defaultValue = value;
|
|
/** @type {{value: T, priority: number, token: string}[]} */
|
|
this._overrides = [];
|
|
}
|
|
|
|
/**
|
|
* Gets the default value for the property, which is assigned to the
|
|
* public value property when no overrides are present.
|
|
* @type {T}
|
|
*/
|
|
get defaultValue() {
|
|
return this._defaultValue;
|
|
}
|
|
|
|
/**
|
|
* Assigns the default value for the property. If no overrides are present
|
|
* and if the value is different than the current default value,
|
|
* the 'change' event will be triggered.
|
|
* @param {T} value The value to assign.
|
|
*/
|
|
set defaultValue(value) {
|
|
this._defaultValue = value;
|
|
if (this._overrides.length === 0) { this._updateValue(); }
|
|
}
|
|
|
|
/**
|
|
* Gets the current value for the property, taking any overrides into account.
|
|
* @type {T}
|
|
*/
|
|
get value() {
|
|
return this._value;
|
|
}
|
|
|
|
/**
|
|
* Gets the number of overrides added to the property.
|
|
* @type {number}
|
|
*/
|
|
get overrideCount() {
|
|
return this._overrides.length;
|
|
}
|
|
|
|
/**
|
|
* Adds an override value with the specified priority to the override stack.
|
|
* Values with higher priority will take precedence over those with lower.
|
|
* For tie breaks, the override value added first will take precedence.
|
|
* If the newly added override has the highest priority of all overrides
|
|
* and if the override value is different from the current value,
|
|
* the 'change' event will be fired.
|
|
* @param {T} value The override value to assign.
|
|
* @param {number} [priority] The priority value to use, as a number.
|
|
* @returns {import('core').TokenString} A string token which can be passed to the clearOverride function
|
|
* to remove the override.
|
|
*/
|
|
setOverride(value, priority = 0) {
|
|
const overridesCount = this._overrides.length;
|
|
let i = 0;
|
|
for (; i < overridesCount; ++i) {
|
|
if (priority > this._overrides[i].priority) { break; }
|
|
}
|
|
const token = generateId(16);
|
|
this._overrides.splice(i, 0, {value, priority, token});
|
|
if (i === 0) { this._updateValue(); }
|
|
return token;
|
|
}
|
|
|
|
/**
|
|
* Removes a specific override value. If the removed override
|
|
* had the highest priority, and the new value is different from
|
|
* the previous value, the 'change' event will be fired.
|
|
* @param {import('core').TokenString} token The token for the corresponding override which is to be removed.
|
|
* @returns {boolean} `true` if an override was returned, `false` otherwise.
|
|
*/
|
|
clearOverride(token) {
|
|
for (let i = 0, ii = this._overrides.length; i < ii; ++i) {
|
|
if (this._overrides[i].token === token) {
|
|
this._overrides.splice(i, 1);
|
|
if (i === 0) { this._updateValue(); }
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Updates the current value using the current overrides and default value.
|
|
* If the new value differs from the previous value, the 'change' event will be fired.
|
|
*/
|
|
_updateValue() {
|
|
const value = this._overrides.length > 0 ? this._overrides[0].value : this._defaultValue;
|
|
if (this._value === value) { return; }
|
|
this._value = value;
|
|
this.trigger('change', {value});
|
|
}
|
|
}
|