@itwin/presentation-frontend
Version:
Frontend of iModel.js Presentation library
746 lines • 31.6 kB
JavaScript
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/* eslint-disable @typescript-eslint/no-deprecated */
/** @packageDocumentation
* @module UnifiedSelection
*/
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose, inner;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
if (async) inner = dispose;
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
var r, s = 0;
function next() {
while (r = env.stack.pop()) {
try {
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
if (r.dispose) {
var result = r.dispose.call(r.value);
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
else s |= 1;
}
catch (e) {
fail(e);
}
}
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToolSelectionSyncHandler = exports.SelectionManager = void 0;
const rxjs_1 = require("rxjs");
const core_bentley_1 = require("@itwin/core-bentley");
const core_frontend_1 = require("@itwin/core-frontend");
const presentation_common_1 = require("@itwin/presentation-common");
const internal_1 = require("@itwin/presentation-common/internal");
const unified_selection_1 = require("@itwin/unified-selection");
const Presentation_js_1 = require("../Presentation.js");
const HiliteSetProvider_js_1 = require("./HiliteSetProvider.js");
const SelectionChangeEvent_js_1 = require("./SelectionChangeEvent.js");
const SelectionScopesManager_js_1 = require("./SelectionScopesManager.js");
/**
* The selection manager which stores the overall selection.
* @public
* @deprecated in 5.0 - will not be removed until after 2026-06-13. Use `SelectionStorage` from [@itwin/unified-selection](https://github.com/iTwin/presentation/blob/master/packages/unified-selection/README.md) package instead.
*/
class SelectionManager {
_imodelKeyFactory;
_imodelToolSelectionSyncHandlers = new Map();
_hiliteSetProviders = new Map();
_ownsStorage;
_knownIModels = new Set();
_currentSelection = new CurrentSelectionStorage();
_selectionChanges = new rxjs_1.Subject();
_selectionEventsSubscription;
_listeners = [];
/**
* Underlying selection storage used by this selection manager. Ideally, consumers should use
* the storage directly instead of using this manager to manipulate selection.
*/
selectionStorage;
/** An event which gets broadcasted on selection changes */
selectionChange;
/** Manager for [selection scopes]($docs/presentation/unified-selection/index#selection-scopes) */
scopes;
/**
* Creates an instance of SelectionManager.
*/
constructor(props) {
this.selectionChange = new SelectionChangeEvent_js_1.SelectionChangeEvent();
this.scopes = props.scopes;
this.selectionStorage = props.selectionStorage ?? (0, unified_selection_1.createStorage)();
this._imodelKeyFactory = props.imodelKeyFactory ?? ((imodel) => (imodel.key.length ? imodel.key : imodel.name));
this._ownsStorage = props.selectionStorage === undefined;
this.selectionStorage.selectionChangeEvent.addListener((args) => this._selectionChanges.next(args));
this._selectionEventsSubscription = this.streamSelectionEvents();
this._listeners.push(core_frontend_1.IModelConnection.onOpen.addListener((imodel) => {
this._knownIModels.add(imodel);
}));
this._listeners.push(core_frontend_1.IModelConnection.onClose.addListener((imodel) => {
this.onConnectionClose(imodel);
}));
}
[Symbol.dispose]() {
this._selectionEventsSubscription.unsubscribe();
this._listeners.forEach((dispose) => dispose());
}
/** @deprecated in 5.0 - will not be removed until after 2026-06-13. Use [Symbol.dispose] instead. */
/* c8 ignore next 3 */
dispose() {
this[Symbol.dispose]();
}
onConnectionClose(imodel) {
const imodelKey = this._imodelKeyFactory(imodel);
this._hiliteSetProviders.delete(imodel);
this._knownIModels.delete(imodel);
this._currentSelection.clear(imodelKey);
if (this._ownsStorage) {
this.clearSelection("Connection Close Event", imodel);
this.selectionStorage.clearStorage({ imodelKey });
}
}
/**
* Request the manager to sync with imodel's tool selection (see `IModelConnection.selectionSet`).
*/
setSyncWithIModelToolSelection(imodel, sync = true) {
const registration = this._imodelToolSelectionSyncHandlers.get(imodel);
if (sync) {
if (!registration || registration.requestorsCount === 0) {
this._imodelToolSelectionSyncHandlers.set(imodel, { requestorsCount: 1, handler: new ToolSelectionSyncHandler(imodel, this) });
}
else {
this._imodelToolSelectionSyncHandlers.set(imodel, { ...registration, requestorsCount: registration.requestorsCount + 1 });
}
}
else {
if (registration && registration.requestorsCount > 0) {
const requestorsCount = registration.requestorsCount - 1;
if (requestorsCount > 0) {
this._imodelToolSelectionSyncHandlers.set(imodel, { ...registration, requestorsCount });
}
else {
this._imodelToolSelectionSyncHandlers.delete(imodel);
registration.handler[Symbol.dispose]();
}
}
}
}
/**
* Temporarily suspends tool selection synchronization until the returned `Disposable`
* is disposed.
*/
suspendIModelToolSelectionSync(imodel) {
const registration = this._imodelToolSelectionSyncHandlers.get(imodel);
if (!registration) {
const noop = () => { };
return { [Symbol.dispose]: noop, dispose: noop };
}
const wasSuspended = registration.handler.isSuspended;
registration.handler.isSuspended = true;
const doDispose = () => (registration.handler.isSuspended = wasSuspended);
return { [Symbol.dispose]: doDispose, dispose: doDispose };
}
/** Get the selection levels currently stored in this manager for the specified imodel */
getSelectionLevels(imodel) {
const imodelKey = this._imodelKeyFactory(imodel);
return this.selectionStorage.getSelectionLevels({ imodelKey });
}
/**
* Get the selection currently stored in this manager
*
* @note Calling immediately after `add*`|`replace*`|`remove*`|`clear*` method call does not guarantee
* that returned `KeySet` will include latest changes. Listen for `selectionChange` event to get the
* latest selection after changes.
*/
getSelection(imodel, level = 0) {
const imodelKey = this._imodelKeyFactory(imodel);
return this._currentSelection.getSelection(imodelKey, level);
}
handleEvent(evt) {
const imodelKey = this._imodelKeyFactory(evt.imodel);
this._knownIModels.add(evt.imodel);
switch (evt.changeType) {
case SelectionChangeEvent_js_1.SelectionChangeType.Add:
this.selectionStorage.addToSelection({
imodelKey,
source: evt.source,
level: evt.level,
selectables: keysToSelectable(evt.imodel, evt.keys),
});
break;
case SelectionChangeEvent_js_1.SelectionChangeType.Remove:
this.selectionStorage.removeFromSelection({
imodelKey,
source: evt.source,
level: evt.level,
selectables: keysToSelectable(evt.imodel, evt.keys),
});
break;
case SelectionChangeEvent_js_1.SelectionChangeType.Replace:
this.selectionStorage.replaceSelection({
imodelKey,
source: evt.source,
level: evt.level,
selectables: keysToSelectable(evt.imodel, evt.keys),
});
break;
case SelectionChangeEvent_js_1.SelectionChangeType.Clear:
this.selectionStorage.clearSelection({ imodelKey, source: evt.source, level: evt.level });
break;
}
}
/**
* Add keys to the selection
* @param source Name of the selection source
* @param imodel iModel associated with the selection
* @param keys Keys to add
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
*/
addToSelection(source, imodel, keys, level = 0, rulesetId) {
const evt = {
source,
level,
imodel,
changeType: SelectionChangeEvent_js_1.SelectionChangeType.Add,
keys: new presentation_common_1.KeySet(keys),
timestamp: new Date(),
rulesetId,
};
this.handleEvent(evt);
}
/**
* Remove keys from current selection
* @param source Name of the selection source
* @param imodel iModel associated with the selection
* @param keys Keys to remove
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
*/
removeFromSelection(source, imodel, keys, level = 0, rulesetId) {
const evt = {
source,
level,
imodel,
changeType: SelectionChangeEvent_js_1.SelectionChangeType.Remove,
keys: new presentation_common_1.KeySet(keys),
timestamp: new Date(),
rulesetId,
};
this.handleEvent(evt);
}
/**
* Replace current selection
* @param source Name of the selection source
* @param imodel iModel associated with the selection
* @param keys Keys to add
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
*/
replaceSelection(source, imodel, keys, level = 0, rulesetId) {
const evt = {
source,
level,
imodel,
changeType: SelectionChangeEvent_js_1.SelectionChangeType.Replace,
keys: new presentation_common_1.KeySet(keys),
timestamp: new Date(),
rulesetId,
};
this.handleEvent(evt);
}
/**
* Clear current selection
* @param source Name of the selection source
* @param imodel iModel associated with the selection
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
*/
clearSelection(source, imodel, level = 0, rulesetId) {
const evt = {
source,
level,
imodel,
changeType: SelectionChangeEvent_js_1.SelectionChangeType.Clear,
keys: new presentation_common_1.KeySet(),
timestamp: new Date(),
rulesetId,
};
this.handleEvent(evt);
}
/**
* Add keys to selection after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
* @param source Name of the selection source
* @param imodel iModel associated with the selection
* @param ids Element IDs to add
* @param scope Selection scope to apply
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
*/
async addToSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
this.addToSelection(source, imodel, scopedKeys, level, rulesetId);
}
/**
* Remove keys from current selection after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
* @param source Name of the selection source
* @param imodel iModel associated with the selection
* @param ids Element IDs to remove
* @param scope Selection scope to apply
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
*/
async removeFromSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
this.removeFromSelection(source, imodel, scopedKeys, level, rulesetId);
}
/**
* Replace current selection with keys after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
* @param source Name of the selection source
* @param imodel iModel associated with the selection
* @param ids Element IDs to replace with
* @param scope Selection scope to apply
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
*/
async replaceSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
this.replaceSelection(source, imodel, scopedKeys, level, rulesetId);
}
/**
* Get the current hilite set for the specified imodel
* @public
*/
async getHiliteSet(imodel) {
return this.getHiliteSetProvider(imodel).getHiliteSet(this.getSelection(imodel));
}
/**
* Get the current hilite set iterator for the specified imodel.
* @public
*/
getHiliteSetIterator(imodel) {
return this.getHiliteSetProvider(imodel).getHiliteSetIterator(this.getSelection(imodel));
}
getHiliteSetProvider(imodel) {
let provider = this._hiliteSetProviders.get(imodel);
if (!provider) {
provider = HiliteSetProvider_js_1.HiliteSetProvider.create({ imodel });
this._hiliteSetProviders.set(imodel, provider);
}
return provider;
}
streamSelectionEvents() {
return this._selectionChanges
.pipe((0, rxjs_1.mergeMap)((args) => {
const currentSelectables = this.selectionStorage.getSelection({ imodelKey: args.imodelKey, level: args.level });
return this._currentSelection.computeSelection(args.imodelKey, args.level, currentSelectables, args.selectables).pipe((0, rxjs_1.mergeMap)(({ level, changedSelection }) => {
const imodel = findIModel(this._knownIModels, this._imodelKeyFactory, args.imodelKey);
/* c8 ignore next 3 */
if (!imodel) {
return rxjs_1.EMPTY;
}
return (0, rxjs_1.of)({
imodel,
keys: changedSelection,
level,
source: args.source,
timestamp: args.timestamp,
changeType: getChangeType(args.changeType),
});
}));
}))
.subscribe({
next: (args) => {
this.selectionChange.raiseEvent(args, this);
},
});
}
}
exports.SelectionManager = SelectionManager;
function findIModel(set, imodelKeyFactory, key) {
for (const imodel of set) {
if (imodelKeyFactory(imodel) === key) {
return imodel;
}
}
return undefined;
}
/** @internal */
class ToolSelectionSyncHandler {
_selectionSourceName = "Tool";
_logicalSelection;
_imodel;
_imodelToolSelectionListenerDisposeFunc;
_asyncsTracker = new internal_1.AsyncTasksTracker();
isSuspended;
constructor(imodel, logicalSelection) {
this._imodel = imodel;
this._logicalSelection = logicalSelection;
this._imodelToolSelectionListenerDisposeFunc = imodel.selectionSet.onChanged.addListener(this.onToolSelectionChanged);
}
[Symbol.dispose]() {
this._imodelToolSelectionListenerDisposeFunc();
}
/** note: used only it tests */
get pendingAsyncs() {
return this._asyncsTracker.pendingAsyncs;
}
onToolSelectionChanged = async (ev) => {
const env_1 = { stack: [], error: void 0, hasError: false };
try {
// ignore selection change event if the handler is suspended
if (this.isSuspended) {
return;
}
// this component only cares about its own imodel
const imodel = ev.set.iModel;
if (imodel !== this._imodel) {
return;
}
// determine the level of selection changes
// wip: may want to allow selecting at different levels?
const selectionLevel = 0;
let ids;
switch (ev.type) {
case core_frontend_1.SelectionSetEventType.Add:
ids = ev.additions;
break;
case core_frontend_1.SelectionSetEventType.Replace:
ids = ev.set.active;
break;
default:
ids = ev.removals;
break;
}
// we're always using scoped selection changer even if the scope is set to "element" - that
// makes sure we're adding to selection keys with concrete classes and not "BisCore:Element", which
// we can't because otherwise our keys compare fails (presentation components load data with
// concrete classes)
const changer = new ScopedSelectionChanger(this._selectionSourceName, this._imodel, this._logicalSelection, (0, SelectionScopesManager_js_1.createSelectionScopeProps)(this._logicalSelection.scopes.activeScope));
const _r = __addDisposableResource(env_1, this._asyncsTracker.trackAsyncTask(), false);
switch (ev.type) {
case core_frontend_1.SelectionSetEventType.Add:
await changer.add(ids, selectionLevel);
break;
case core_frontend_1.SelectionSetEventType.Replace:
await changer.replace(ids, selectionLevel);
break;
case core_frontend_1.SelectionSetEventType.Remove:
await changer.remove(ids, selectionLevel);
break;
case core_frontend_1.SelectionSetEventType.Clear:
await changer.clear(selectionLevel);
break;
}
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
__disposeResources(env_1);
}
};
}
exports.ToolSelectionSyncHandler = ToolSelectionSyncHandler;
const parseElementIds = (ids) => {
let allPersistent = true;
let allTransient = true;
for (const id of core_bentley_1.Id64.iterable(ids)) {
if (core_bentley_1.Id64.isTransient(id)) {
allPersistent = false;
}
else {
allTransient = false;
}
if (!allPersistent && !allTransient) {
break;
}
}
// avoid making a copy if ids are only persistent or only transient
if (allPersistent) {
return { persistent: ids, transient: [] };
}
else if (allTransient) {
return { persistent: [], transient: ids };
}
// if `ids` contain mixed ids, we have to copy.. use Array instead of
// a Set for performance
const persistentElementIds = [];
const transientElementIds = [];
for (const id of core_bentley_1.Id64.iterable(ids)) {
if (core_bentley_1.Id64.isTransient(id)) {
transientElementIds.push(id);
}
else {
persistentElementIds.push(id);
}
}
return { persistent: persistentElementIds, transient: transientElementIds };
};
function addKeys(target, className, ids) {
for (const id of core_bentley_1.Id64.iterable(ids)) {
target.add({ className, id });
}
}
class ScopedSelectionChanger {
name;
imodel;
manager;
scope;
constructor(name, imodel, manager, scope) {
this.name = name;
this.imodel = imodel;
this.manager = manager;
this.scope = scope;
}
async clear(level) {
this.manager.clearSelection(this.name, this.imodel, level);
}
async add(ids, level) {
const keys = await this.#computeSelection(ids);
this.manager.addToSelection(this.name, this.imodel, keys, level);
}
async remove(ids, level) {
const keys = await this.#computeSelection(ids);
this.manager.removeFromSelection(this.name, this.imodel, keys, level);
}
async replace(ids, level) {
const keys = await this.#computeSelection(ids);
this.manager.replaceSelection(this.name, this.imodel, keys, level);
}
async #computeSelection(ids) {
let keys = new presentation_common_1.KeySet();
if (ids.elements) {
const { persistent, transient } = parseElementIds(ids.elements);
keys = await this.manager.scopes.computeSelection(this.imodel, persistent, this.scope);
addKeys(keys, unified_selection_1.TRANSIENT_ELEMENT_CLASSNAME, transient);
}
if (ids.models) {
addKeys(keys, "BisCore.Model", ids.models);
}
if (ids.subcategories) {
addKeys(keys, "BisCore.SubCategory", ids.subcategories);
}
return keys;
}
}
/** Stores current selection in `KeySet` format per iModel. */
class CurrentSelectionStorage {
_currentSelection = new Map();
getCurrentSelectionStorage(imodelKey) {
let storage = this._currentSelection.get(imodelKey);
if (!storage) {
storage = new IModelSelectionStorage();
this._currentSelection.set(imodelKey, storage);
}
return storage;
}
getSelection(imodelKey, level) {
return this.getCurrentSelectionStorage(imodelKey).getSelection(level);
}
clear(imodelKey) {
this._currentSelection.delete(imodelKey);
}
computeSelection(imodelKey, level, currSelectables, changedSelectables) {
return this.getCurrentSelectionStorage(imodelKey).computeSelection(level, currSelectables, changedSelectables);
}
}
/**
* Computes and stores current selection in `KeySet` format.
* It always stores result of latest resolved call to `computeSelection`.
*/
class IModelSelectionStorage {
_currentSelection = new Map();
getSelection(level) {
let entry = this._currentSelection.get(level);
if (!entry) {
entry = { value: new presentation_common_1.KeySet(), ongoingComputationDisposers: new Set() };
this._currentSelection.set(level, entry);
}
return entry.value;
}
clearSelections(level) {
const clearedLevels = [];
for (const [storedLevel] of this._currentSelection.entries()) {
if (storedLevel > level) {
clearedLevels.push(storedLevel);
}
}
clearedLevels.forEach((storedLevel) => {
const entry = this._currentSelection.get(storedLevel);
/* c8 ignore next 3 */
if (!entry) {
return;
}
for (const disposer of entry.ongoingComputationDisposers) {
disposer.next();
}
this._currentSelection.delete(storedLevel);
});
}
addDisposer(level, disposer) {
const entry = this._currentSelection.get(level);
if (!entry) {
this._currentSelection.set(level, { value: new presentation_common_1.KeySet(), ongoingComputationDisposers: new Set([disposer]) });
return;
}
entry.ongoingComputationDisposers.add(disposer);
}
setSelection(level, keys, disposer) {
const currEntry = this._currentSelection.get(level);
if (currEntry) {
currEntry.ongoingComputationDisposers.delete(disposer);
}
this._currentSelection.set(level, {
value: keys,
ongoingComputationDisposers: currEntry?.ongoingComputationDisposers ?? /* c8 ignore next */ new Set(),
});
}
computeSelection(level, currSelectables, changedSelectables) {
this.clearSelections(level);
const prevComputationsDisposers = [...(this._currentSelection.get(level)?.ongoingComputationDisposers ?? [])];
const currDisposer = new rxjs_1.Subject();
this.addDisposer(level, currDisposer);
return (0, rxjs_1.defer)(async () => {
const convertedSelectables = [];
const [current, changed] = await Promise.all([
selectablesToKeys(currSelectables, convertedSelectables),
selectablesToKeys(changedSelectables, convertedSelectables),
]);
const currentSelection = new presentation_common_1.KeySet([...current.keys, ...current.selectableKeys.flatMap((selectable) => selectable.keys)]);
const changedSelection = new presentation_common_1.KeySet([...changed.keys, ...changed.selectableKeys.flatMap((selectable) => selectable.keys)]);
return {
level,
currentSelection,
changedSelection,
};
}).pipe((0, rxjs_1.takeUntil)(currDisposer), (0, rxjs_1.tap)({
next: (val) => {
prevComputationsDisposers.forEach((disposer) => disposer.next());
this.setSelection(val.level, val.currentSelection, currDisposer);
},
}));
}
}
function keysToSelectable(imodel, keys) {
const selectables = [];
keys.forEach((key) => {
if ("id" in key) {
selectables.push(key);
return;
}
const customSelectable = {
identifier: key.pathFromRoot.join("/"),
data: key,
loadInstanceKeys: () => createInstanceKeysIterator(imodel, key),
};
selectables.push(customSelectable);
});
return selectables;
}
async function selectablesToKeys(selectables, convertedList) {
const keys = [];
const selectableKeys = [];
for (const [className, ids] of selectables.instanceKeys) {
for (const id of ids) {
keys.push({ id, className });
}
}
for (const [_, selectable] of selectables.custom) {
if (isNodeKey(selectable.data)) {
selectableKeys.push({ identifier: selectable.identifier, keys: [selectable.data] });
continue;
}
const converted = convertedList.find((con) => con.identifier === selectable.identifier);
if (converted) {
selectableKeys.push(converted);
continue;
}
const newConverted = { identifier: selectable.identifier, keys: [] };
convertedList.push(newConverted);
for await (const instanceKey of selectable.loadInstanceKeys()) {
newConverted.keys.push(instanceKey);
}
selectableKeys.push(newConverted);
}
return { keys, selectableKeys };
}
async function* createInstanceKeysIterator(imodel, nodeKey) {
if (presentation_common_1.NodeKey.isInstancesNodeKey(nodeKey)) {
for (const key of nodeKey.instanceKeys) {
yield key;
}
return;
}
const content = await Presentation_js_1.Presentation.presentation.getContentInstanceKeys({
imodel,
keys: new presentation_common_1.KeySet([nodeKey]),
rulesetOrId: {
id: "grouped-instances",
rules: [
{
ruleType: "Content",
specifications: [
{
specType: "SelectedNodeInstances",
},
],
},
],
},
});
for await (const key of content.items()) {
yield key;
}
}
function isNodeKey(data) {
const key = data;
return key.pathFromRoot !== undefined && key.type !== undefined;
}
function getChangeType(type) {
switch (type) {
case "add":
return SelectionChangeEvent_js_1.SelectionChangeType.Add;
case "remove":
return SelectionChangeEvent_js_1.SelectionChangeType.Remove;
case "replace":
return SelectionChangeEvent_js_1.SelectionChangeType.Replace;
case "clear":
return SelectionChangeEvent_js_1.SelectionChangeType.Clear;
}
}
//# sourceMappingURL=SelectionManager.js.map