@itwin/presentation-frontend
Version:
Frontend of iModel.js Presentation library
643 lines • 30.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.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Core
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFieldOrderInfos = exports.getFieldInfos = exports.FavoritePropertiesManager = exports.FavoritePropertiesScope = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const IModelConnectionInitialization_js_1 = require("../IModelConnectionInitialization.js");
/**
* Scopes that favorite properties can be stored in.
* @public
*/
var FavoritePropertiesScope;
(function (FavoritePropertiesScope) {
FavoritePropertiesScope[FavoritePropertiesScope["Global"] = 0] = "Global";
FavoritePropertiesScope[FavoritePropertiesScope["ITwin"] = 1] = "ITwin";
FavoritePropertiesScope[FavoritePropertiesScope["IModel"] = 2] = "IModel";
})(FavoritePropertiesScope || (exports.FavoritePropertiesScope = FavoritePropertiesScope = {}));
/**
* The favorite property manager which lets to store favorite properties
* and check if field contains favorite properties.
*
* @public
*/
class FavoritePropertiesManager {
/** Event raised after favorite properties have changed. */
onFavoritesChanged = new core_bentley_1.BeEvent();
storage;
_globalProperties;
_iTwinProperties;
_imodelProperties;
_imodelBaseClassesByClass;
_imodelInitializationPromises;
_imodelInitializationHandler;
/** Property order is saved only in iModel scope */
_propertiesOrder;
constructor(props) {
this.storage = props.storage;
this._iTwinProperties = new Map();
this._imodelProperties = new Map();
this._propertiesOrder = new Map();
this._imodelBaseClassesByClass = new Map();
this._imodelInitializationPromises = new Map();
IModelConnectionInitialization_js_1.imodelInitializationHandlers.add((this._imodelInitializationHandler = {
startInitialization: (imodel) => this.startConnectionInitialization(imodel),
ensureInitialized: async (imodel) => this.ensureInitialized(imodel),
}));
}
[Symbol.dispose]() {
IModelConnectionInitialization_js_1.imodelInitializationHandlers.delete(this._imodelInitializationHandler);
if ((0, core_bentley_1.isDisposable)(this.storage)) {
this.storage[Symbol.dispose]();
/* c8 ignore next 4 */
/* eslint-disable-next-line @typescript-eslint/no-deprecated */
}
else if ((0, core_bentley_1.isIDisposable)(this.storage)) {
this.storage.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]();
}
/**
* Initialize favorite properties for the provided IModelConnection.
* @deprecated in 4.5 - will not be removed until after 2026-06-13. Initialization is performed automatically by all async methods and only needed for deprecated [[FavoritePropertiesManager.has]] and [[FavoritePropertiesManager.sortFields]].
*/
initializeConnection = async (imodel) => {
const imodelId = imodel.iModelId;
const iTwinId = imodel.iTwinId;
if (this._globalProperties === undefined) {
this._globalProperties = (await this.storage.loadProperties()) || new Set();
}
if (!this._iTwinProperties.has(iTwinId)) {
const iTwinProperties = (await this.storage.loadProperties(iTwinId)) || new Set();
this._iTwinProperties.set(iTwinId, iTwinProperties);
}
if (!this._imodelProperties.has(getiModelInfo(iTwinId, imodelId))) {
const imodelProperties = (await this.storage.loadProperties(iTwinId, imodelId)) || new Set();
this._imodelProperties.set(getiModelInfo(iTwinId, imodelId), imodelProperties);
}
const propertiesOrder = (await this.storage.loadPropertiesOrder(iTwinId, imodelId)) || [];
this._propertiesOrder.set(getiModelInfo(iTwinId, imodelId), propertiesOrder);
await this._adjustPropertyOrderInfos(iTwinId, imodelId);
};
/**
* Function that removes order information of properties that are no longer
* favorited and adds missing order information for favorited properties.
*/
_adjustPropertyOrderInfos = async (iTwinId, imodelId) => {
const propertiesOrder = this._propertiesOrder.get(getiModelInfo(iTwinId, imodelId));
const globalProperties = this._globalProperties;
const iTwinProperties = this._iTwinProperties.get(iTwinId);
const imodelProperties = this._imodelProperties.get(getiModelInfo(iTwinId, imodelId));
// favorite property infos that need to be added to the propertiesOrder array
const infosToAdd = new Set([...globalProperties, ...iTwinProperties, ...imodelProperties]);
for (let i = propertiesOrder.length - 1; i >= 0; i--) {
if (infosToAdd.has(propertiesOrder[i].name)) {
infosToAdd.delete(propertiesOrder[i].name);
}
else {
propertiesOrder.splice(i, 1);
}
}
infosToAdd.forEach((info) => propertiesOrder.push({
name: info,
parentClassName: getPropertyClassName(info),
orderedTimestamp: new Date(),
priority: 0,
}));
let priority = propertiesOrder.length;
propertiesOrder.forEach((oi) => (oi.priority = priority--));
};
isInitialized(imodel) {
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
return this._imodelProperties.has(getiModelInfo(iTwinId, imodelId));
}
/**
* Checks if [[FavoritePropertiesManager.initializeConnection]] has been called for a given imodel.
* Can be removed when [[FavoritePropertiesManager.has]] and [[FavoritePropertiesManager.sortFields]] are removed.
*/
validateInitialization(imodel) {
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
if (!this.isInitialized(imodel)) {
throw Error(`Favorite properties are not initialized for iModel: '${imodelId}', in iTwin: '${iTwinId}'. Call initializeConnection() with an IModelConnection to initialize.`);
}
}
startConnectionInitialization(imodel) {
if (!this.isInitialized(imodel) && !this._imodelInitializationPromises.has(imodel)) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
this._imodelInitializationPromises.set(imodel, this.initializeConnection(imodel));
}
}
async ensureInitialized(imodel) {
if (this.isInitialized(imodel)) {
return;
}
let promise = this._imodelInitializationPromises.get(imodel);
if (!promise) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
promise = this.initializeConnection(imodel);
// Put the promise in the map to avoid possible multiple initializations from different promises.
this._imodelInitializationPromises.set(imodel, promise);
}
await promise;
// Remove this promise from the map, because the next time this method is called, `this.isInitialized` should return true.
this._imodelInitializationPromises.delete(imodel);
}
/**
* Adds favorite properties into a certain scope.
* @param field Field that contains properties. If field contains multiple properties, all of them will be favorited.
* @param imodel IModelConnection.
* @param scope FavoritePropertiesScope to put the favorite properties into.
*/
async add(field, imodel, scope) {
await this.ensureInitialized(imodel);
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
let favoriteProperties;
let saveProperties;
switch (scope) {
case FavoritePropertiesScope.Global:
favoriteProperties = this._globalProperties;
saveProperties = async (properties) => this.storage.saveProperties(properties);
break;
case FavoritePropertiesScope.ITwin:
favoriteProperties = this._iTwinProperties.get(iTwinId);
saveProperties = async (properties) => this.storage.saveProperties(properties, iTwinId);
break;
default:
favoriteProperties = this._imodelProperties.get(getiModelInfo(iTwinId, imodelId));
saveProperties = async (properties) => this.storage.saveProperties(properties, iTwinId, imodelId);
}
const countBefore = favoriteProperties.size;
const fieldInfos = (0, exports.getFieldInfos)(field);
fieldInfos.forEach((info) => favoriteProperties.add(info));
if (favoriteProperties.size !== countBefore) {
const saves = [];
saves.push(saveProperties(favoriteProperties));
const propertiesOrder = this._propertiesOrder.get(getiModelInfo(iTwinId, imodelId));
addOrderInfos(propertiesOrder, (0, exports.createFieldOrderInfos)(field));
saves.push(this.storage.savePropertiesOrder(propertiesOrder, iTwinId, imodelId));
await Promise.all(saves);
this.onFavoritesChanged.raiseEvent();
}
}
/**
* Removes favorite properties from a scope specified and all the more general scopes.
* @param field Field that contains properties. If field contains multiple properties, all of them will be un-favorited.
* @param imodel IModelConnection.
* @param scope FavoritePropertiesScope to remove the favorite properties from. It also removes from more general scopes.
*/
async remove(field, imodel, scope) {
await this.ensureInitialized(imodel);
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
const fieldInfos = (0, exports.getFieldInfos)(field);
const workingScopes = [];
workingScopes.push({
properties: this._globalProperties,
save: async (properties) => this.storage.saveProperties(properties),
});
if (scope === FavoritePropertiesScope.ITwin || scope === FavoritePropertiesScope.IModel) {
workingScopes.push({
properties: this._iTwinProperties.get(iTwinId),
save: async (properties) => this.storage.saveProperties(properties, iTwinId),
});
}
if (scope === FavoritePropertiesScope.IModel) {
workingScopes.push({
properties: this._imodelProperties.get(getiModelInfo(iTwinId, imodelId)),
save: async (properties) => this.storage.saveProperties(properties, iTwinId, imodelId),
});
}
const saves = [];
let favoritesChanged = false;
for (const { properties, save } of workingScopes) {
const countBefore = properties.size;
fieldInfos.forEach((info) => properties.delete(info));
if (properties.size !== countBefore) {
saves.push(save(properties));
favoritesChanged = true;
}
}
if (!favoritesChanged) {
return;
}
const propertiesOrder = this._propertiesOrder.get(getiModelInfo(iTwinId, imodelId));
removeOrderInfos(propertiesOrder, (0, exports.createFieldOrderInfos)(field));
saves.push(this.storage.savePropertiesOrder(propertiesOrder, iTwinId, imodelId));
await Promise.all(saves);
this.onFavoritesChanged.raiseEvent();
}
/**
* Removes all favorite properties from a certain scope.
* @param imodel IModelConnection.
* @param scope FavoritePropertiesScope to remove the favorite properties from.
*/
async clear(imodel, scope) {
await this.ensureInitialized(imodel);
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
let favoriteProperties;
let saveProperties;
switch (scope) {
case FavoritePropertiesScope.Global:
favoriteProperties = this._globalProperties;
saveProperties = async () => this.storage.saveProperties(new Set());
break;
case FavoritePropertiesScope.ITwin:
favoriteProperties = this._iTwinProperties.get(iTwinId);
saveProperties = async () => this.storage.saveProperties(new Set(), iTwinId);
break;
default:
favoriteProperties = this._imodelProperties.get(getiModelInfo(iTwinId, imodelId));
saveProperties = async () => this.storage.saveProperties(new Set(), iTwinId, imodelId);
}
if (favoriteProperties.size === 0) {
return;
}
favoriteProperties.clear();
const saves = [];
saves.push(saveProperties());
saves.push(this._adjustPropertyOrderInfos(iTwinId, imodelId));
await Promise.all(saves);
this.onFavoritesChanged.raiseEvent();
}
/**
* Check if field contains at least one favorite property.
* @param field Field that contains properties.
* @param imodel IModelConnection.
* @param scope FavoritePropertiesScope to check for favorite properties. It also checks the more general scopes.
* @note `initializeConnection` must be called with the `imodel` before calling this function.
* @deprecated in 4.5 - will not be removed until after 2026-06-13. Use [[FavoritePropertiesManager.hasAsync]] instead. This method is not async, therefore it requires early initialization by calling [[FavoritePropertiesManager.initializeConnection]].
*/
has(field, imodel, scope) {
this.validateInitialization(imodel);
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
const fieldInfos = (0, exports.getFieldInfos)(field);
return (setHasAny(this._globalProperties, fieldInfos) ||
(scope !== FavoritePropertiesScope.Global && setHasAny(this._iTwinProperties.get(iTwinId), fieldInfos)) ||
(scope === FavoritePropertiesScope.IModel && setHasAny(this._imodelProperties.get(getiModelInfo(iTwinId, imodelId)), fieldInfos)));
}
/**
* Check if field contains at least one favorite property.
* @param field Field that contains properties.
* @param imodel IModelConnection.
* @param scope FavoritePropertiesScope to check for favorite properties. It also checks the more general scopes.
*/
async hasAsync(field, imodel, scope) {
await this.ensureInitialized(imodel);
// eslint-disable-next-line @typescript-eslint/no-deprecated
return this.has(field, imodel, scope);
}
/**
* Sorts an array of fields with respect to favorite property order.
* Non-favorited fields get sorted by their default priority and always have lower priority than favorited fields.
* @param imodel IModelConnection.
* @param fields Array of Field's that needs to be sorted.
* @note `initializeConnection` must be called with the `imodel` before calling this function.
* @deprecated in 4.5 - will not be removed until after 2026-06-13. Use [[FavoritePropertiesManager.sortFieldsAsync]] instead. This method is not async, therefore it requires early initialization by calling [[FavoritePropertiesManager.initializeConnection]].
*/
sortFields = (imodel, fields) => {
this.validateInitialization(imodel);
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
const fieldPriority = new Map();
fields.forEach((field) => fieldPriority.set(field, this.getFieldPriority(field, iTwinId, imodelId)));
const sortFunction = (left, right) => {
const lp = fieldPriority.get(left);
const rp = fieldPriority.get(right);
return lp < rp
? 1
: lp > rp
? -1
: left.priority < right.priority
? 1 // if favorite fields have equal priorities, sort by field priority
: left.priority > right.priority
? -1
: left.name.localeCompare(right.name);
};
return fields.sort(sortFunction);
};
/**
* Sorts an array of fields with respect to favorite property order.
* Non-favorited fields get sorted by their default priority and always have lower priority than favorited fields.
* @param imodel IModelConnection.
* @param fields Array of Field's that needs to be sorted.
*/
async sortFieldsAsync(imodel, fields) {
await this.ensureInitialized(imodel);
// eslint-disable-next-line @typescript-eslint/no-deprecated
return this.sortFields(imodel, fields);
}
getFieldPriority(field, iTwinId, imodelId) {
const orderInfos = this._propertiesOrder.get(getiModelInfo(iTwinId, imodelId));
const fieldOrderInfos = getFieldOrderInfos(field, orderInfos);
if (fieldOrderInfos.length === 0) {
return -1;
}
const mostRecent = getMostRecentOrderInfo(fieldOrderInfos);
return mostRecent.priority;
}
_getBaseClassesByClass = async (imodel, neededClasses) => {
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
const imodelInfo = getiModelInfo(iTwinId, imodelId);
let baseClasses;
if (this._imodelBaseClassesByClass.has(imodelInfo)) {
baseClasses = this._imodelBaseClassesByClass.get(imodelInfo);
}
else {
this._imodelBaseClassesByClass.set(imodelInfo, (baseClasses = {}));
}
const missingClasses = new Set();
neededClasses.forEach((className) => {
if (!baseClasses.hasOwnProperty(className)) {
missingClasses.add(className);
}
});
if (missingClasses.size === 0) {
return baseClasses;
}
const query = `
SELECT (derivedSchema.Name || ':' || derivedClass.Name) AS "ClassFullName", (baseSchema.Name || ':' || baseClass.Name) AS "BaseClassFullName"
FROM ECDbMeta.ClassHasAllBaseClasses baseClassRels
INNER JOIN ECDbMeta.ECClassDef derivedClass ON derivedClass.ECInstanceId = baseClassRels.SourceECInstanceId
INNER JOIN ECDbMeta.ECSchemaDef derivedSchema ON derivedSchema.ECInstanceId = derivedClass.Schema.Id
INNER JOIN ECDbMeta.ECClassDef baseClass ON baseClass.ECInstanceId = baseClassRels.TargetECInstanceId
INNER JOIN ECDbMeta.ECSchemaDef baseSchema ON baseSchema.ECInstanceId = baseClass.Schema.Id
WHERE (derivedSchema.Name || ':' || derivedClass.Name) IN (${[...missingClasses].map((className) => `'${className}'`).join(",")})`;
const reader = imodel.createQueryReader(query, undefined, { rowFormat: core_common_1.QueryRowFormat.UseJsPropertyNames });
while (await reader.step()) {
const row = reader.current.toRow();
if (!(row.classFullName in baseClasses)) {
baseClasses[row.classFullName] = [];
}
baseClasses[row.classFullName].push(row.baseClassFullName);
}
return baseClasses;
};
/** Changes field properties priorities to lower than another fields priority
* @param imodel IModelConnection.
* @param field Field that priority is being changed.
* @param afterField Field that goes before the moved field. If undefined the moving field is changed to the highest priority (to the top).
* @param visibleFields Array of fields to move the field in.
*/
async changeFieldPriority(imodel, field, afterField, visibleFields) {
/**
* How it works:
* 1. Gets the orderInfo's for `field` (`orderInfo`) and `afterField` (`afterOrderInfo`) by selecting the most recent order informations for each field
* 2. Iterates all orderInfo's that are in between `afterOrderInfo` and `orderInfo` when sorted by priority
* 3. For each iterated orderInfo it checks if it is relevant:
* 3.1. If orderInfo belongs to a primitive property, orderInfo is relevant
* 3.2. If orderInfo's field is visible, orderInfo is relevant
* 3.3. If orderInfo's class has a base class or itself in previously labeled relevant orderInfo's, orderInfo is relevant
* 3.4. If 3.1 - 3.3 don't pass, orderInfo is irrelevant
* 4. Irrelevant orderInfos's get moved after `orderInfo` (depends on the direction)
* 5. All `field` orderInfo's get moved after `afterOrderInfo`
*/
await this.ensureInitialized(imodel);
const iTwinId = imodel.iTwinId;
const imodelId = imodel.iModelId;
if (field === afterField) {
throw Error("`field` can not be the same as `afterField`.");
}
const allOrderInfos = this._propertiesOrder.get(getiModelInfo(iTwinId, imodelId));
const findFieldOrderInfoData = (f) => {
if (!visibleFields.includes(f)) {
throw Error("Field is not contained in visible fields.");
}
const infos = getFieldOrderInfos(f, allOrderInfos);
if (infos.length === 0) {
throw Error("Field has no property order information.");
}
const info = getMostRecentOrderInfo(infos);
const index = allOrderInfos.indexOf(info);
return { infos, mostRecent: { info, index } };
};
const { infos: movingOrderInfos, mostRecent: { index: orderInfoIndex }, } = findFieldOrderInfoData(field);
let afterOrderInfo;
let afterOrderInfoIndex;
if (afterField === undefined) {
afterOrderInfo = undefined;
afterOrderInfoIndex = -1;
}
else {
({
mostRecent: { info: afterOrderInfo, index: afterOrderInfoIndex },
} = findFieldOrderInfoData(afterField));
}
let direction; // where to go from `afterOrderInfo` to `orderInfo`
let startIndex;
if (orderInfoIndex < afterOrderInfoIndex) {
direction = Direction.Up;
startIndex = afterOrderInfoIndex;
}
else {
direction = Direction.Down;
startIndex = afterOrderInfoIndex + 1;
}
const neededClassNames = allOrderInfos.reduce((classNames, oi) => {
if (oi.parentClassName) {
classNames.add(oi.parentClassName);
}
return classNames;
}, new Set());
const baseClassesByClass = await this._getBaseClassesByClass(imodel, neededClassNames);
const visibleOrderInfos = visibleFields.reduce((union, currField) => union.concat(getFieldOrderInfos(currField, allOrderInfos)), []);
const irrelevantOrderInfos = []; // orderInfos's that won't change their logical order in respect to other properties
const relevantClasses = new Set(); // currently relevant classes
for (let i = startIndex; i !== orderInfoIndex; i += direction) {
const currOrderInfo = allOrderInfos[i];
// primitive properties are always relevant, because we can't determine their relevance based on the class hierarchy
if (currOrderInfo.parentClassName === undefined) {
continue;
}
const visible = visibleOrderInfos.includes(currOrderInfo);
if (visible) {
relevantClasses.add(currOrderInfo.parentClassName);
continue;
}
const hasBaseClasses = baseClassesByClass[currOrderInfo.parentClassName].some((classId) => relevantClasses.has(classId));
if (hasBaseClasses) {
continue;
}
if (direction === Direction.Down) {
irrelevantOrderInfos.push(currOrderInfo);
}
else {
irrelevantOrderInfos.unshift(currOrderInfo);
}
}
// remove irrelevantOrderInfo's to add them after the `orderInfo`
irrelevantOrderInfos.forEach((foi) => {
const index = allOrderInfos.findIndex((oi) => oi.parentClassName === foi.parentClassName && oi.name === foi.name);
allOrderInfos.splice(index, 1);
});
// remove movingOrderInfos's to add them after the `afterOrderInfo`
movingOrderInfos.forEach((foi) => {
const index = allOrderInfos.findIndex((oi) => oi.parentClassName === foi.parentClassName && oi.name === foi.name);
allOrderInfos.splice(index, 1);
});
movingOrderInfos.forEach((oi) => (oi.orderedTimestamp = new Date()));
afterOrderInfoIndex = afterOrderInfo === undefined ? -1 : allOrderInfos.indexOf(afterOrderInfo);
allOrderInfos.splice(afterOrderInfoIndex + 1, 0, ...movingOrderInfos);
allOrderInfos.splice(afterOrderInfoIndex + 1 + (direction === Direction.Up ? movingOrderInfos.length : 0), 0, ...irrelevantOrderInfos);
// reassign priority numbers
let priority = allOrderInfos.length;
allOrderInfos.forEach((oi) => (oi.priority = priority--));
await this.storage.savePropertiesOrder(allOrderInfos, iTwinId, imodelId);
this.onFavoritesChanged.raiseEvent();
}
}
exports.FavoritePropertiesManager = FavoritePropertiesManager;
var Direction;
(function (Direction) {
Direction[Direction["Up"] = -1] = "Up";
Direction[Direction["Down"] = 1] = "Down";
})(Direction || (Direction = {}));
const getiModelInfo = (iTwinId, imodelId) => `${iTwinId}/${imodelId}`;
const getPropertiesFieldPropertyNames = (field) => {
const nestingPrefix = getNestingPrefix(field.parent);
return field.properties.map((property) => `${nestingPrefix}${property.property.classInfo.name}:${property.property.name}`);
};
const getNestedContentFieldPropertyName = (field) => {
const nestingPrefix = getNestingPrefix(field);
return `${nestingPrefix}${field.contentClassInfo.name}`;
};
const getNestingPrefix = (field) => {
const path = [];
let curr = field;
while (curr !== undefined) {
curr.pathToPrimaryClass.forEach((rel) => {
// Relationship directions are reversed, because we are generating a relationship list starting from the parent
path.push(`${rel.isForwardRelationship ? "B" : "F"}:${rel.relationshipInfo.name}`);
path.push(rel.targetClassInfo.name);
});
curr = curr.parent;
}
if (path.length === 0) {
return "";
}
path.reverse();
return `${path.join("-")}-`;
};
const getPropertyClassName = (propertyName) => {
const propertyNameStart = propertyName.split("-")[0];
const parts = propertyNameStart.split(":").length;
if (parts === 1) {
// primitive
return undefined;
}
if (parts === 2) {
// nested property OR nested property parent class OR regular property parent class
return propertyNameStart;
}
// regular property without parent class
return propertyNameStart.substring(0, propertyName.lastIndexOf(":"));
};
/** @internal */
const getFieldInfos = (field) => {
const fieldInfos = new Set();
if (field.isPropertiesField()) {
getPropertiesFieldPropertyNames(field).forEach((info) => fieldInfos.add(info));
}
else if (field.isNestedContentField()) {
fieldInfos.add(getNestedContentFieldPropertyName(field));
}
else {
fieldInfos.add(field.name);
}
return fieldInfos;
};
exports.getFieldInfos = getFieldInfos;
const setHasAny = (set, lookup) => {
for (const key of lookup) {
if (set.has(key)) {
return true;
}
}
return false;
};
const addOrderInfos = (dest, source) => {
source.forEach((si) => {
const index = dest.findIndex((di) => di.name === si.name);
if (index === -1) {
si.orderedTimestamp = new Date();
dest.push(si);
}
});
let priority = dest.length;
dest.forEach((info) => (info.priority = priority--));
};
const removeOrderInfos = (container, toRemove) => {
toRemove.forEach((roi) => {
const index = container.findIndex((oi) => oi.name === roi.name);
if (index >= 0) {
container.splice(index, 1);
}
});
};
/** @internal */
const createFieldOrderInfos = (field) => {
if (field.isNestedContentField()) {
const propertyName = getNestedContentFieldPropertyName(field);
return [
{
parentClassName: getPropertyClassName(propertyName),
name: propertyName,
priority: 0,
orderedTimestamp: new Date(),
},
];
}
if (field.isPropertiesField()) {
return getPropertiesFieldPropertyNames(field).map((propertyName) => ({
parentClassName: getPropertyClassName(propertyName),
name: propertyName,
priority: 0,
orderedTimestamp: new Date(),
}));
}
return [
{
parentClassName: undefined,
name: field.name,
priority: 0,
orderedTimestamp: new Date(),
},
];
};
exports.createFieldOrderInfos = createFieldOrderInfos;
const getFieldOrderInfos = (field, orderInfos) => {
const fieldOrderInfos = [];
const tryAddOrderInfo = (name) => {
const fieldOrderInfo = orderInfos.find((oi) => oi.name === name);
if (fieldOrderInfo !== undefined) {
fieldOrderInfos.push(fieldOrderInfo);
}
};
if (field.isPropertiesField()) {
getPropertiesFieldPropertyNames(field).forEach(tryAddOrderInfo);
}
else if (field.isNestedContentField()) {
tryAddOrderInfo(getNestedContentFieldPropertyName(field));
}
else {
tryAddOrderInfo(field.name);
}
return fieldOrderInfos;
};
const getMostRecentOrderInfo = (orderInfos) => orderInfos.reduce((recent, curr) => (recent && recent.orderedTimestamp >= curr.orderedTimestamp ? recent : curr));
//# sourceMappingURL=FavoritePropertiesManager.js.map