@itwin/unified-selection
Version:
Package for managing unified selection in iTwin.js applications.
150 lines • 5.59 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.IMODEL_CLOSE_SELECTION_CLEAR_SOURCE = void 0;
exports.createStorage = createStorage;
const core_bentley_1 = require("@itwin/core-bentley");
const Selectable_js_1 = require("./Selectable.js");
/**
* Creates a selection storage which stores and allows managing application-level selection.
*
* **Note:** `clearSelection` should be called upon iModel close to free-up memory:
*
* ```ts
* import { IModelConnection } from "@itwin/core-frontend";
* import { createIModelKey } from "@itwin/presentation-core-interop";
*
* IModelConnection.onClose.addListener((imodel) => {
* storage.clearStorage(createIModelKey(imodel));
* });
* ```
*
* @public
*/
function createStorage() {
return new SelectionStorageImpl();
}
/** @internal */
exports.IMODEL_CLOSE_SELECTION_CLEAR_SOURCE = "Unified selection storage: clear";
class SelectionStorageImpl {
_storage = new Map();
selectionChangeEvent;
constructor() {
this.selectionChangeEvent = new core_bentley_1.BeEvent();
}
getSelectionLevels(props) {
return this.getContainer(getIModelKey(props)).getSelectionLevels();
}
getSelection(props) {
return this.getContainer(getIModelKey(props)).getSelection(props.level ?? 0);
}
addToSelection(props) {
this.handleChange({ ...props, changeType: "add" });
}
removeFromSelection(props) {
this.handleChange({ ...props, changeType: "remove" });
}
replaceSelection(props) {
this.handleChange({ ...props, changeType: "replace" });
}
clearSelection(props) {
this.handleChange({ ...props, changeType: "clear", selectables: [] });
}
clearStorage(props) {
const imodelKey = getIModelKey(props);
this.clearSelection({ source: exports.IMODEL_CLOSE_SELECTION_CLEAR_SOURCE, imodelKey });
this._storage.delete(imodelKey);
}
getContainer(imodelKey) {
let selectionContainer = this._storage.get(imodelKey);
if (!selectionContainer) {
selectionContainer = new MultiLevelSelectablesContainer();
this._storage.set(imodelKey, selectionContainer);
}
return selectionContainer;
}
handleChange(props) {
const { source, level: inLevel, changeType, selectables: change } = props;
const imodelKey = getIModelKey(props);
const container = this.getContainer(imodelKey);
const level = inLevel ?? 0;
const selectables = container.getSelection(level);
const selected = Selectable_js_1.Selectables.create(change);
switch (changeType) {
case "add":
if (!Selectable_js_1.Selectables.add(selectables, change)) {
return;
}
break;
case "remove":
if (!Selectable_js_1.Selectables.remove(selectables, change)) {
return;
}
break;
case "replace":
if (Selectable_js_1.Selectables.size(selectables) === Selectable_js_1.Selectables.size(selected) && Selectable_js_1.Selectables.hasAll(selectables, change)) {
return;
}
Selectable_js_1.Selectables.clear(selectables);
Selectable_js_1.Selectables.add(selectables, change);
break;
case "clear":
if (!Selectable_js_1.Selectables.clear(selectables)) {
return;
}
break;
}
container.clear(level + 1);
const event = {
source,
level,
imodelKey,
iModelKey: imodelKey,
changeType,
selectables: selected,
timestamp: new Date(),
storage: this,
};
this.selectionChangeEvent.raiseEvent(event, this);
}
}
function getIModelKey(props) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
return ("imodelKey" in props ? props.imodelKey : props.iModelKey) ?? "";
}
class MultiLevelSelectablesContainer {
_selectablesContainers;
constructor() {
this._selectablesContainers = new Map();
}
getSelection(level) {
let selectables = this._selectablesContainers.get(level);
if (!selectables) {
selectables = Selectable_js_1.Selectables.create([]);
this._selectablesContainers.set(level, selectables);
}
return selectables;
}
getSelectionLevels() {
const levels = new Array();
for (const entry of this._selectablesContainers.entries()) {
if (!Selectable_js_1.Selectables.isEmpty(entry[1])) {
levels.push(entry[0]);
}
}
return levels.sort();
}
clear(level) {
const storedLevels = this._selectablesContainers.keys();
for (const storedLevel of storedLevels) {
if (storedLevel >= level) {
const selectables = this._selectablesContainers.get(storedLevel);
Selectable_js_1.Selectables.clear(selectables);
}
}
}
}
//# sourceMappingURL=SelectionStorage.js.map