@gmetrixr/rjson
Version:
(R)ecursive Json
187 lines (186 loc) • 8.59 kB
JavaScript
import { RecordFactory } from "../R/RecordFactory";
import { RT, rtp } from "../R/RecordTypes";
import { ElementType } from "../definitions/elements";
import { ElementFactory } from "./ElementFactory";
import { jsUtils } from "@gmetrixr/gdash";
const { deepClone, generateId } = jsUtils;
export class SceneFactory extends RecordFactory {
constructor(json) {
super(json);
}
/** Overriding add rule: Sub record ids should be made unique after duplications - this helps keeping all ids in the tree unique */
addRecord(record, position) {
const addedRecord = super.addRecord(record, position);
if ((addedRecord === null || addedRecord === void 0 ? void 0 : addedRecord.type) === RT.rule) {
this.dedupeWeTaIds(addedRecord);
}
return addedRecord;
}
/**
* adds record into the group if groupElementId is present
* else adds record to the scene
*/
addDeepRecord({ record, position, groupElementId }) {
if (groupElementId) {
const group = this.getAllDeepChildrenWithFilter(RT.element, el => el.id === groupElementId);
if (group[0] !== undefined) {
const groupF = new ElementFactory(group[0]);
const addedRecord = groupF.addRecord(record, position);
return addedRecord;
}
}
else {
const addedRecord = this.addRecord(record, position);
if ((addedRecord === null || addedRecord === void 0 ? void 0 : addedRecord.type) === RT.rule) {
this.dedupeWeTaIds(addedRecord);
}
return addedRecord;
}
}
/** Overriding duplicate rule: Sub record ids should be made unique after duplications - this helps keeping all ids in the tree unique */
duplicateRecord(type, id) {
const addedRecord = super.duplicateRecord(type, id);
if ((addedRecord === null || addedRecord === void 0 ? void 0 : addedRecord.type) === RT.rule) {
this.dedupeWeTaIds(addedRecord);
}
if ((addedRecord === null || addedRecord === void 0 ? void 0 : addedRecord.type) === RT.element) {
this.dedupeGroupElements(addedRecord);
}
return addedRecord;
}
/**
* Overriding duplicate rule: Sub record ids should be made unique after duplications - this helps keeping all ids in the tree unique
*/
duplicateDeepRecord(type, id) {
const addedRecord = super.duplicateDeepRecord(type, id);
if ((addedRecord === null || addedRecord === void 0 ? void 0 : addedRecord.type) === RT.rule) {
this.dedupeWeTaIds(addedRecord);
}
if ((addedRecord === null || addedRecord === void 0 ? void 0 : addedRecord.type) === RT.element) {
this.dedupeGroupElements(addedRecord);
}
return addedRecord;
}
/** Overriding delete element: Deleting an element/variable (any CogObject) should also delete its rules */
deleteRecord(type, id) {
if (type === RT.element) {
this.deleteRulesForCoId(id);
}
return super.deleteRecord(type, id);
}
/** Overriding delete deep element: Deleting an element/variable (any CogObject) should also delete its rules */
deleteDeepRecord(type, id) {
if (type === RT.element) {
this.deleteRulesForCoId(id);
}
return super.deleteDeepRecord(type, id);
}
//ELEMENT SPECIFIC FUNCTIONS
/**
* Deleting an element/variable (any CogObject) should also delete its rules
*/
deleteRulesForCoId(id) {
for (const rule of this.getRecords(RT.rule)) {
const ruleF = new RecordFactory(rule);
ruleF.getRecords(RT.when_event)
.filter(we => (we.props.co_id === id))
.forEach(we => ruleF.deleteRecord(RT.when_event, we.id));
ruleF.getRecords(RT.then_action)
.filter(ta => (ta.props.co_id === id))
.forEach(ta => ruleF.deleteRecord(RT.then_action, ta.id));
if (ruleF.getRecordOrder(RT.when_event).length === 0 && ruleF.getRecordOrder(RT.then_action).length === 0) {
this.deleteRecord(RT.rule, rule.id);
}
}
}
//RULE SPECIFIC FUNCTIONS
/**
* Makes sure all event ids and action ids don't clash with any of the event/actions ids in the current scene
* This is useful when a rule is duplicated - we need to change the event_id's and action_id's of
* all the WhenEvents and ThenActions inside the rule to unique ones.
*/
dedupeWeTaIds(rule) {
const collectedIds = [];
for (const r of this.getRecords(RT.rule)) {
if (r.id === rule.id)
continue; //This means we are at the same rule
const rf = new RecordFactory(r);
collectedIds.push(...rf.getRecordOrder(RT.when_event));
collectedIds.push(...rf.getRecordOrder(RT.then_action));
}
const ruleFactory = new RecordFactory(rule);
ruleFactory.getRecords(RT.when_event).forEach(we => {
if (collectedIds.includes(we.id)) {
ruleFactory.changeRecordId(RT.when_event, we.id);
}
});
ruleFactory.getRecords(RT.then_action).forEach(ta => {
if (collectedIds.includes(ta.id)) {
ruleFactory.changeRecordId(RT.then_action, ta.id);
}
});
}
/**
* Makes sure that all elements in a single scene have unique ids. This function ensures that whenever a group is duplicated (at any depth),
* new ids are generated for all it's children
* @param group
*/
dedupeGroupElements(group) {
var _a, _b, _c, _d;
const elementF = new ElementFactory(group);
const elementType = elementF.get(rtp.element.element_type);
if (elementType === ElementType.group) {
// create new IDs for all elements
// make a clone to start operating on the new reference
const children = deepClone(elementF.getRecords(RT.element));
// reset the original order to empty
if ((_b = (_a = group.records) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.order) {
group.records.element.order = [];
}
// reset the original map to empty
if ((_d = (_c = group.records) === null || _c === void 0 ? void 0 : _c.element) === null || _d === void 0 ? void 0 : _d.map) {
group.records.element.map = {};
}
// children are already ordered, start inserting after creating new IDs
for (const child of children) {
child.id = generateId();
// * if the child is another group, dedupe again
if (child.props.element_type === ElementType.group) {
this.dedupeGroupElements(child);
}
elementF.addRecord(child);
}
}
}
/**
* 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, groupElementId }) {
if (obj.parentType !== this._type) {
console.error(`Can't paste this object into a RecordNode of type of ${this._type}`);
return [];
}
if (groupElementId !== undefined) {
const group = this.getAllDeepChildrenWithFilter(RT.element, el => el.id === groupElementId);
if (group[0] !== undefined) {
const groupF = new ElementFactory(group[0]);
return groupF.pasteFromClipboardObject({ obj, position });
}
}
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();
if (rn.type === RT.element) {
// * generate new ids if required for child elements. ex: group element children
new ElementFactory(rn).dedupeChildElementIds();
}
const addedRecord = this.addRecord(rn, position ? position++ : position);
if (addedRecord !== undefined) {
addedRecords.push(addedRecord);
}
}
return addedRecords;
}
}