Something went wrong on our end
-
Sebastian Pongratz authoredSebastian Pongratz authored
contentProcess.js 14.49 KiB
import("system.db");
import("system.translate");
import("system.result");
import("system.vars");
import("ObjectRelation_lib");
import("Context_lib");
import("Sql_lib");
import("Contact_lib");
/**
* Rough functioning of the code:
* - get parameters
* - load data via _loadObjectRelationTree
* * _loadObjectRelationTree calls itself recursively
* - data is insertet into the tree,
* -> this.push in _loadObjectRelationTree changes tree
* - the "tree" is returned
*/
//TODO: Refactoring in this process. It's rather hard to understand and uses more sql queries than necessary.
//uid array structure
var UID = {
objectId: 0,
layer: 1,
objectRelationTypeId: 2,
otherObjectType: 3,
relationTypeData: 4,
myObjectType: 5,
objectRelationId: 6,
hierarchy: 7
}
var tree = [];
// uidParam: if only one row should be loaded
var uidParam;
if (vars.exists("$param.Uid_param") && vars.get("$param.Uid_param"))
uidParam = vars.getString("$param.Uid_param");
else if(vars.exists("$local.idvalues") && vars.get("$local.idvalues") && vars.get("$local.idvalues").length > 0)
uidParam = vars.get("$local.idvalues")[0];
if (uidParam && uidParam.includes("[")) // "[" -> is JSON
{
// Load one by uid. Basically the data to return is also encoded in the uid itself -> no extra data loading is needed.
var uid = JSON.parse(uidParam);
// if objectRelationTypeId is a string it is a relation node and no Grouping
if (uid != null && typeof uid[UID.objectRelationTypeId] == "string")
{
var relationTypeData = ObjectRelationUtils.getRelationType(uid[UID.objectRelationTypeId]);
_insertEntry(tree, _getEntryData(uid[UID.objectId], relationTypeData[3], relationTypeData[7], relationTypeData[8], undefined, false,
uid[UID.objectRelationId]), "", 0, uid[UID.otherObjectType], relationTypeData[10], relationTypeData[12], relationTypeData[4]);
}
}
else
{
// load all
var filter = vars.get("$local.filter")
var selectedRelationType = null;
// filter for the object relation type
if (filter && filter.filter)
{
filter = filter.filter;
if (filter.childs.length > 0)
selectedRelationType = filter.childs[0].key;
}
// get the base object types / ids to load the tree fo
if (vars.exists("$param.ObjectIds_param") && vars.get("$param.ObjectIds_param") && vars.get("$param.ObjectTypes_param"))
{
var originalObjectIds = JSON.parse(vars.getString("$param.ObjectIds_param"));
var originalObjectTypes = JSON.parse(vars.getString("$param.ObjectTypes_param"));
if (originalObjectIds.length != originalObjectTypes.length)
throw "the parameters ObjectIds_param and ObjectTypes_param do not contain a json array of the same length";
// load the object relations for each given objectId / Type
for (let i = 0; i < originalObjectIds.length; i++)
{
//.call, because tree is used as 'this' to prevent accidentally overwriting tree
_loadObjectRelationTree.call(tree, originalObjectIds[i], originalObjectTypes[i], selectedRelationType);
}
}
if (uidParam) //workaround!
tree = tree.filter(function (row) {return JSON.parse(row[0])[UID.objectRelationId] == uidParam});
}
result.object(tree);
/**
* This function loads the whole tree and calls itself recursively
* @param {String} pObjectId The id of the object to load the tree for (e.g. a ContactId)
* @param {String} pObjectType The type of the object to load the tree for (e.g. "Person")
* @param {String} [pObjectRelationTypeId=undefined] if given: the tree is filtered by this relation type and only nodes with this type are added
* @param {String} [pNodeId=null] the current nodeid is the node for which the next childrens are loaded. Needed for Recursion.
* @param {Integer} [pLayer=0] this is the current layer to load. Needed for Recursion.
* @param {String[][]} [pRelationTypeData=undefined] NOT ESSENTIAL it is just needed to not load the type data every time the function is called.
* If it is missing, it's loaded via the id encoded inside of the uid
* It only exists for better performance
*/
function _loadObjectRelationTree(pObjectId, pObjectType, pObjectRelationTypeId, pNodeId, pLayer, pRelationTypeData)
{
// prevent stack overflows
if (pLayer > 30 || !pObjectId || !pObjectType)
return;
if (pLayer == undefined)
pLayer = 0;
if (pNodeId === undefined)
pNodeId = null;
var currentObjectId = pObjectId;
if (pLayer == 0)
{
if (pObjectRelationTypeId)
{
let relationTypeData = ObjectRelationUtils.getRelationType(pObjectRelationTypeId);
// if hirachy: get most top id else use the current currentObjectId
if (relationTypeData[4] == "1")
{ // use always reverse-type
relationTypeData = ObjectRelationUtils.getRelationType(relationTypeData[8]);
currentObjectId = _getRootID(currentObjectId, relationTypeData);
}
var parentTmpTree = [];
var childsTmpTree = [];
// add as group to parentTmpTree but not yet to the tree itself
// true to enable the insert button always --v
let uids = _insertEntry(parentTmpTree, [[currentObjectId, "", "", "", "", relationTypeData[7]]], pNodeId, pLayer, pObjectType, pObjectRelationTypeId, relationTypeData[12], true)
for (let i = 0; i < uids.length; i++)
{ // recursive call
_loadObjectRelationTree.call(childsTmpTree, uids[i][UID.objectId], uids[i][UID.otherObjectType], relationTypeData[0], uids[i], pLayer+1, relationTypeData);
}
// only add parent if childs exist
if (childsTmpTree.length > 0)
this.push.apply(this, parentTmpTree.concat(childsTmpTree)); //use push since you can't overwrite this
}
else // no ObjectType chosen
{
// load all ObjectRelationTypes
var relationTypes = _getPossibleRelationTypes(pObjectType);
relationTypes.forEach(function (relationType, i)
{
var [relationTypeId, title,, direction,,,, relationType1, relationTye2,,,, icon] = relationType;
var data = _getEntryData(currentObjectId, direction, relationType1, relationTye2);
// if any subentry: show objectType
if (data.length > 0)
{
// TODO: Icons, BINDATA
// var icon = getIcon...
let uid = [currentObjectId, i, relationType];
// add the relationtype as grouping
this.push([JSON.stringify(uid), null, translate.text(title), JSON.stringify(pNodeId), true, null, null, "", relationTypeId, icon]);
_loadObjectRelationTree.call(this, pObjectId, pObjectType, pObjectRelationTypeId, uid, pLayer+1, relationTypes[i]);
}
}, this);
}
}
else if (pLayer >= 1)
{
// if no relationType given, load from nodeId
if (!pRelationTypeData)
pRelationTypeData = pNodeId[UID.objectRelationTypeId];
// if it's only the id, load via function
if (typeof pRelationTypeData == "string")
pRelationTypeData = ObjectRelationUtils.getRelationType(pRelationTypeData);
var [thisRelationTypeId,,, direction, hierarchy,, destObjectType, relationType1, relationType2,, otherRelationTypeId,, icon] = pRelationTypeData;
var relationTypeIdForNew = otherRelationTypeId;
if (hierarchy == "1")
{
var myData = _getEntryData(pNodeId[0], direction, relationType1, relationType2)
// if hierarchy and selected RelationType -> use the selected one
relationTypeIdForNew = pObjectRelationTypeId || thisRelationTypeId;
let uids = _insertEntry(this, myData, pNodeId, pLayer, destObjectType, relationTypeIdForNew, icon, hierarchy)
for (let i = 0; i < uids.length; i++)
{ // recursive call
_loadObjectRelationTree.call(this, uids[i][UID.objectId], uids[i][UID.otherObjectType], pObjectRelationTypeId, uids[i], pLayer+1, pRelationTypeData);
}
}
else
{
// pNodeId[4] is the previous NodeId and pNodeId[4][0] the previous ObjectId
var prevObjectId;
if (pNodeId[4] != undefined)
prevObjectId = pNodeId[UID.relationTypeData][0];
var entryData = _getEntryData(pNodeId[UID.objectId], direction, relationType1, relationType2, prevObjectId, true);
if (direction == "same")
relationTypeIdForNew = thisRelationTypeId
// add both sides. Only one will succeed, because the prevObjectId will be filtered
_insertEntry(this, entryData, pNodeId, pLayer, destObjectType, thisRelationTypeId, icon, hierarchy, 0);
if (direction == "same")
{
var otherEntryData = _getEntryData(pNodeId[UID.objectId], "normal", relationType1, relationType2, prevObjectId, true);
_insertEntry(this, otherEntryData, pNodeId, pLayer, destObjectType, thisRelationTypeId, icon, hierarchy, 1);
}
}
}
}
/**
* load data for a relation.
* OBJECT_ROWID, AB_OBJECTRELATIONID, OBJECT_TYPE, RELATION_TITLE, AB_OBJECTRELATIONTYPEID
*
* @param {String} pObjectId
* @param {String} pDirection
* @param {String} pRelationType1
* @param {String} pRelationType2
* @param {String} [pPrevId=undefined] Id of the previous node to exclude it
* @param {Boolean} [pNoRecursion=false] if false: select for direction "same" the other direction, if result is empty.
* @param {String} [pObjectRelationId] provide if only one special node is needed
*
* @return {[][]}
*/
function _getEntryData(pObjectId, pDirection, pRelationType1, pRelationType2, pPrevId, pNoRecursion, pObjectRelationId)
{
if (pRelationType1 == undefined || pRelationType2 == undefined)
return [];
var [myNum, otherNum] = pDirection == "normal" ? [2, 1] : [1, 2];
onConditionForRelationTypeJoin = newWhere("AB_OBJECTRELATIONTYPEID = AB_OBJECTRELATIONTYPE" + myNum)
.and("AB_OBJECTRELATION.AB_OBJECTRELATIONTYPE1", pRelationType1)
.and("AB_OBJECTRELATION.AB_OBJECTRELATIONTYPE2", pRelationType2)
.and("AB_OBJECTRELATION.OBJECT" + myNum + "_ROWID", pObjectId)
.andIfSet("AB_OBJECTRELATION.AB_OBJECTRELATIONID", pObjectRelationId || null); // set id to null, as only null works with .andIfSet
// exclude previous node
if (!pPrevId)
onConditionForRelationTypeJoin.and("AB_OBJECTRELATION.OBJECT" + otherNum + "_ROWID is not null");
else
onConditionForRelationTypeJoin.and("AB_OBJECTRELATION.OBJECT" + otherNum + "_ROWID", pPrevId, SqlBuilder.NOT_EQUAL());
// TODO: BINDATA?
// var image = getImageObject("Beziehung");
var data = newSelect("OBJECT" + (pObjectRelationId ? myNum : otherNum) + "_ROWID, AB_OBJECTRELATIONID, OBJECT_TYPE, RELATION_TITLE, INFO, AB_OBJECTRELATIONTYPEID")
.from("AB_OBJECTRELATION")
.join("AB_OBJECTRELATIONTYPE", onConditionForRelationTypeJoin)
.table();
// try again with other side for "same"
if (data.length == 0 && pDirection == "same" && !pNoRecursion || pObjectRelationId && data.length > 0 && !data[0][0])
return _getEntryData(pObjectId, "normal", pRelationType1, pRelationType2, pPrevId, true, pObjectRelationId)
// TODO: BINDATA?
//for ( var i = 0; i < data.length; i++) data[i][2] = image[data[i][2]] == undefined ? "" : image[data[i][2]];
return data;
}
function _getPossibleRelationTypes(pObjectType)
{
// TODO: load from entity when possible
return ObjectRelationUtils.getPossibleRelationTypes([pObjectType], true);
}
/**
* insert a new Entry
*
* @param {Array} pTree
* @param {Array[][]} pEntryData
* @param {Array[][]} pNodeId id of the parent
* @param {Integer} pLayer layernumber
* @param {String} pObjectType
* @param {String} pNewRelationTypeId the RelationType, a new relation should have, if this node is selected.
* @param {String} pIcon the icon which should be added to the entry
* @param {Boolean} pHierarchy add if hierarchy is enabled or not for this entry
* @param {Integer} [pNum=undefined] optional number added to the key. Needed, if the key would not be unique.
*
* @return {Array[][]} the uids of the inserted data. Consists of [ObjectId, pEntryData-Index, AB_OBJECTRELATIONTYPEID, pObjectType (from param), pNodeId, objecttype (from entryId), objectrelationid, hierarchy]
*/
function _insertEntry(pTree, pEntryData, pNodeId, pLayer, pObjectType, pNewRelationTypeId, pIcon, pHierarchy, pNum)
{
var expanded = pLayer <= 10;
// TODO: display address (tooltip wird denke ich nicht benötigt, da preview vorhanden)
var uids = [];
pEntryData.forEach(function ([objectId, objectRelationId, objectType, relationTitle, info, objectRelationTypeId], i)
{
//TODO: entities.getRow, check if this is possible with fewer queries
var display = db.cell(ContextUtils.getNameSql(pObjectType, objectId));
// TODO: Icon
var uid = [objectId, i, objectRelationTypeId, pObjectType, pNodeId, objectType, objectRelationId, pHierarchy];
if (pNum)
uid.push(pNum);
uids.push(uid);
pTree.push([JSON.stringify(uid), objectRelationId, display, JSON.stringify(pNodeId), expanded, objectId, pObjectType, info, pNewRelationTypeId, pIcon]);
});
return uids;
}
/*
* get most top root of a node
*
* @param {String} pObjectId
* @param {String[]} pObjectRelationTypeData
*
* @return {String} RootObjectId
*/
function _getRootID(pObjectId, pObjectRelationTypeData)
{
var sourceid = pObjectId;
var max = 100;
var rootid = sourceid;
for (let max = 100; sourceid && max > 0; max--)
{
//TODO: refactor for less queries
sourceid = newSelect("OBJECT1_ROWID")
.from("AB_OBJECTRELATION")
.where("AB_OBJECTRELATION.OBJECT2_ROWID", sourceid)
.and("AB_OBJECTRELATION.AB_OBJECTRELATIONTYPE1", pObjectRelationTypeData[7])
.and("AB_OBJECTRELATION.AB_OBJECTRELATIONTYPE2", pObjectRelationTypeData[8])
.cell();
}
return rootid;
}