@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
108 lines (107 loc) • 3.65 kB
JavaScript
import { getPropertyByPath, setPropertyByPath } from '../utils/pathUtils';
/**
* Manages the toggling of state properties based on specified paths.
* Every paths leading to boolean value will be initially set to false,
* then activities one will deactivate the others.
*/
export default class StateToggleManager {
constructor(togglePaths, stateManager) {
Object.defineProperty(this, "stateManager", {
enumerable: true,
configurable: true,
writable: true,
value: stateManager
});
Object.defineProperty(this, "eventsCallbacks", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "togglePaths", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.togglePaths = StateToggleManager.filterValidTogglePaths(this.stateManager, togglePaths);
this.initToggle();
this.watchToggle();
}
get state() {
return this.stateManager.state;
}
/**
* To call to destroy properly the component.
*/
destroy() {
this.stateManager.unsubscribe(this.eventsCallbacks);
}
/**
* Set to false every state leaded by toggle paths except the specified one.
* Use the given value on the specified one.
*/
toggle(setPath, newValue) {
this.togglePaths
.filter((path) => path !== setPath)
.forEach((path) => {
setPropertyByPath(this.state, path, false);
});
setPropertyByPath(this.state, setPath, newValue);
}
/**
* Set to false every state leaded by toggle paths.
*/
deactivateAll() {
this.toggle(this.togglePaths[0], false);
}
/**
* Initializes the toggle for the given paths.
* If any of the paths has a truthy value in the state, sets all other paths to false.
* @private
*/
initToggle() {
let oneActive = false;
this.togglePaths.forEach((path) => {
const result = getPropertyByPath(this.state, path);
if (oneActive) {
setPropertyByPath(this.state, path, false);
}
if (result.object === true) {
oneActive = true;
}
});
}
/**
* Watches for changes in togglePaths and invokes the toggle method when a change is detected.
* @private
**/
watchToggle() {
this.togglePaths.forEach((path) => {
this.eventsCallbacks.push(this.stateManager.subscribe(path, (oldValue, newValue) => {
if (oldValue == null) {
// Don't toggle initial value, needed in tests.
return;
}
if (oldValue !== newValue) {
this.toggle(path, newValue);
}
}));
});
}
/**
* Filters out invalid toggle paths from the given array of paths.
* Invalid path are path not leading to object in the state, or not leading to boolean value.
* @static
*/
static filterValidTogglePaths(stateManager, paths) {
return paths.filter((path) => {
const result = getPropertyByPath(stateManager.state, path);
if (result.found && (result.object === true || result.object === false)) {
return true;
}
console.warn(`Configured state toggle path "${path}" doesn't lead to a boolean property. Skip it.`);
return false;
});
}
}