@gmetrixr/rjson
Version:
(R)ecursive Json
245 lines (244 loc) • 11.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ElementUtils = exports.ElementFactory = void 0;
const elements_1 = require("../definitions/elements");
const ElementDefinition_1 = require("../definitions/elements/ElementDefinition");
const RecordFactory_1 = require("../R/RecordFactory");
const RecordNode_1 = require("../R/RecordNode");
const RecordTypes_1 = require("../R/RecordTypes");
const definitions_1 = require("../definitions");
const gdash_1 = require("@gmetrixr/gdash");
const { generateId } = gdash_1.jsUtils;
const deepClone = gdash_1.jsUtils.deepClone;
class ElementFactory extends RecordFactory_1.RecordFactory {
constructor(json) {
super(json);
const element_type = json.props.element_type;
if (element_type !== undefined && (0, ElementDefinition_1.isElementType)(element_type)) {
this.elementType = element_type;
}
else {
throw Error(`The type ${element_type} of this ElementJson isn't a known ElementType`);
}
}
/**
* ISSUE : We were facing issue when we copy element from root to group, id for that element was duplicated and that was causing an issue. Below id fix for that
* this function will add record with new element id to prevent duplicate issue.
*/
pasteFromClipboardObject({ obj, position }) {
if (obj.parentType !== this._type) {
console.error(`Can't paste this object into a RecordNode of type of ${this._type}`);
return [];
}
const addedRecords = [];
for (const rn of obj.nodes) {
// * if position is passed, then keep incrementing to insert in order, else add at the end of the list
rn.id = generateId();
// * generate new ids if required for child elements. ex: group children
new ElementFactory(rn).dedupeChildElementIds();
const addedRecord = super.addRecord(rn, position ? position++ : position);
if (addedRecord !== undefined) {
addedRecords.push(addedRecord);
}
}
return addedRecords;
}
/**
* Regenerate new element_id for all children recursively
*/
dedupeChildElementIds() {
if (this.elementType === definitions_1.en.ElementType.group) {
// change ids of all children
const children = this.getRecords(RecordTypes_1.RT.element);
for (const c of children) {
this.changeRecordId(RecordTypes_1.RT.element, c.id);
if (c.props.element_type === definitions_1.en.ElementType.group) {
new ElementFactory(c).dedupeChildElementIds();
}
}
}
}
getElementType() {
return this.elementType;
}
set(property, value) {
super.set(property, value);
if (property === RecordTypes_1.rtp.element.element_type && (typeof value === "string") && (0, ElementDefinition_1.isElementType)(value)) {
this.elementType = value;
}
return this;
}
/**
* Returns the default value of a property. If no default is found, returns undefined
* This is already defined in RecordFactory and is being overridden in ElementFactory
*/
getDefault(property) {
var _a, _b;
const elementDefaultValues = (_b = (_a = elements_1.eTypeToDefn[this.elementType]) === null || _a === void 0 ? void 0 : _a.defaultOverrides) !== null && _b !== void 0 ? _b : {};
if (elementDefaultValues[property] !== undefined)
return deepClone(elementDefaultValues[property]);
const defaultValues = RecordTypes_1.recordTypeDefinitions[RecordTypes_1.RT.element].defaultValues;
if (defaultValues[property] !== undefined)
return deepClone(defaultValues[property]);
}
//ELEMENT RELATED FUNCTIONS
/**
* Used by the right bar to list down properties
*/
getJsonPropsAndDefaultProps() {
const jsonProps = this.getProps();
const elementProps = ElementUtils.getElementDefinition(this.elementType).properties;
return Array.from(new Set(jsonProps.concat(elementProps)));
}
//FILE RELATED FUNCTIONS
/**
* Gets all file ids from an element structure
* file ids are stored in properties of type "source"
* Properties of type "source" are generally in properties ending with "source" (Eg: "background_source")
* sources
*/
getFileIdsFromElement() {
const fileIds = [];
const elementProps = this.getJsonPropsAndDefaultProps();
//Get file ids form element properties
for (const sourceProp of definitions_1.en.sourcePropertyNames.elementProperties) { //Iterating over sourceElementProperties instead of elementProps to reduce number of iterations
if (elementProps.includes(sourceProp)) {
fileIds.push(...ElementUtils.getFileIdsFromValue(this.get(sourceProp)));
}
}
//Get file ids form element array properties
for (const sourceProp of definitions_1.en.sourcePropertyNames.elementArrayProperties) {
if (elementProps.includes(sourceProp)) {
fileIds.push(...ElementUtils.getFileIdsFromElementArrayPropertyValue(this.get(sourceProp)));
}
}
//Get file ids from item properties
for (const sourceProp of definitions_1.en.sourcePropertyNames.itemProperties) {
for (const item of this.getRecords(RecordTypes_1.RT.item)) {
const itemProps = Object.keys(item.props);
if (itemProps.includes(sourceProp)) { //Not checking for image_source, as it isn't used in items
fileIds.push(...ElementUtils.getFileIdsFromValue(item.props[sourceProp]));
}
}
}
//return _.uniq(fileIds); Unique not needed here, done at project level
return fileIds;
}
/**
* Inject the given sources into the element
*/
injectSourceIntoElement(sourceMap) {
const elementProps = this.getJsonPropsAndDefaultProps();
//Get file ids form element properties
for (const sourceProp of definitions_1.en.sourcePropertyNames.elementProperties) { //Iterating over sourceElementProperties instead of elementProps to reduce number of iterations
if (elementProps.includes(sourceProp)) {
const currentValue = this.get(sourceProp);
const newValue = ElementUtils.getNewSourceValue(currentValue, sourceMap);
if (newValue !== undefined) {
this.set(sourceProp, deepClone(newValue));
}
}
}
for (const sourceProp of definitions_1.en.sourcePropertyNames.elementArrayProperties) {
if (elementProps.includes(sourceProp)) {
const currentValue = this.get(sourceProp);
const newValue = ElementUtils.getNewSourceValueArray(currentValue, sourceMap);
if (newValue !== undefined && newValue.length !== 0) {
this.set(sourceProp, deepClone(newValue));
}
}
}
//Get file ids from item properties
for (const sourceProp of definitions_1.en.sourcePropertyNames.itemProperties) {
for (const item of this.getRecords(RecordTypes_1.RT.item)) {
const itemProps = Object.keys(item.props);
if (itemProps.includes(sourceProp)) { //Not checking for image_source, as it isn't used in items
const currentValue = item.props[sourceProp];
const newValue = ElementUtils.getNewSourceValue(currentValue, sourceMap);
if (newValue !== undefined) {
item.props[sourceProp] = deepClone(newValue);
}
}
}
}
}
addElementOfType(elementType, position) {
const defaultName = ElementUtils.getElementDefinition(elementType).elementDefaultName;
const newElement = (0, RecordNode_1.createRecord)(RecordTypes_1.RT.element, undefined, defaultName);
newElement.props = ElementUtils.getElementTypeDefaults(elementType);
newElement.props.element_type = elementType;
this.addRecord(newElement, position);
return newElement;
}
}
exports.ElementFactory = ElementFactory;
class ElementUtils {
}
exports.ElementUtils = ElementUtils;
/**
* Get the element definition of a specific element_type
* ElementDefinition can be used to get element_type, properties, propertyDefaults, events, actions
*
* In case its an unknown element_type, returns BasicElement's Definition
*/
ElementUtils.getElementDefinition = (elementType) => {
const defn = elements_1.eTypeToDefn[elementType];
if (defn !== undefined) {
return defn;
}
else {
return ElementDefinition_1.BasicElement;
}
};
/** Get a list of all defaults for the given elementType */
ElementUtils.getElementTypeDefaults = (elementType) => {
var _a, _b, _c, _d;
const allElementDefaults = RecordTypes_1.recordTypeDefinitions[RecordTypes_1.RT.element].defaultValues;
const elementOverrides = (_b = (_a = elements_1.eTypeToDefn[elementType]) === null || _a === void 0 ? void 0 : _a.defaultOverrides) !== null && _b !== void 0 ? _b : {};
const props = (_d = (_c = elements_1.eTypeToDefn[elementType]) === null || _c === void 0 ? void 0 : _c.properties) !== null && _d !== void 0 ? _d : [];
const defaultValues = {};
for (const prop of props) {
let value = elementOverrides[prop];
if (value === undefined)
value = allElementDefaults[prop];
defaultValues[prop] = value;
}
return defaultValues;
};
/**
* Given a property of type Array<Source>, takes file id out of it in an array and returns it
*/
ElementUtils.getFileIdsFromElementArrayPropertyValue = (value) => {
const imageSources = value;
return imageSources.map(source => source === null || source === void 0 ? void 0 : source.id).filter(s => s); // filter out undefined and null values
};
/**
* Given a property value (of type source), takes file id out of it and returns it as an array
*/
ElementUtils.getFileIdsFromValue = (value) => {
const source = value;
if ((source === null || source === void 0 ? void 0 : source.id) !== undefined) { //Because we don't want to return default source paths which don't have ids
return [source === null || source === void 0 ? void 0 : source.id];
}
else {
return [];
}
};
/**
* Given a property value and sourceMap, returns a new value with the replaced sources
* Can return undefined or a Source or a Source[], depending on the propertyName
* The multiple returns type don't matter, because the logic of the calling function doesn't care about return type
*/
ElementUtils.getNewSourceValueArray = (value, sourceMap) => {
const originalSources = value;
return originalSources.map(source => sourceMap[source === null || source === void 0 ? void 0 : source.id]);
};
ElementUtils.getNewSourceValue = (value, sourceMap) => {
const source = value;
if ((source === null || source === void 0 ? void 0 : source.id) !== undefined && sourceMap[source === null || source === void 0 ? void 0 : source.id] !== undefined) { //Because we don't want to return default source paths which don't have ids
return sourceMap[source === null || source === void 0 ? void 0 : source.id];
}
else {
return undefined;
}
};