diff --git a/neonContext/Classification/Classification.aod b/neonContext/Classification/Classification.aod index 3b433677ca91713369452b7b8d7a5c198d8dfc2f..9319b3ed21f3f9da1f49d6b6c73d10c8595f8e7e 100644 --- a/neonContext/Classification/Classification.aod +++ b/neonContext/Classification/Classification.aod @@ -2,6 +2,7 @@ <neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.0"> <name>Classification</name> <majorModelMode>DISTRIBUTED</majorModelMode> + <documentation>%aditoprj%/neonContext/Classification/documentation.adoc</documentation> <editview>ClassificatonAdminEdit_view</editview> <entity>Classification_entity</entity> <references> diff --git a/neonContext/Classification/documentation.adoc b/neonContext/Classification/documentation.adoc new file mode 100644 index 0000000000000000000000000000000000000000..5bfeb1cf5037dc652a49359e3b9640ae030060a6 --- /dev/null +++ b/neonContext/Classification/documentation.adoc @@ -0,0 +1 @@ +This entity has two modes: normal mode and admin mode. If just called over #PROVIDER it is in admin mode. Use the respective views and providers. \ No newline at end of file diff --git a/others/guide/HowToDataLib.adoc b/others/guide/HowToDataLib.adoc deleted file mode 100644 index f16c4f8b74628f20c0a95c2799a747a8e7eb6cf0..0000000000000000000000000000000000000000 --- a/others/guide/HowToDataLib.adoc +++ /dev/null @@ -1,98 +0,0 @@ -How to use the DataLib (state: 21.01.2019) -========================================== -:toc2: left -:numbered: - -== What is the DataLib == -The data lib provides objects for a more easy data structure creation. - -Currently the lib provides - -* DataTree -** an object for building a tree structure -* ReferencingData -** a wrapper for DataTree -** the programmer doesn't have to decide if the tree is needed, or if a simple array is sufficient. This Class will use the tree only if needed. - -== DataTree == -See the library comments for further explanations. - -The purpose of this lib is - -* creating a tree object -* creating an array with uid and parent from the tree object (e.g. for treetables and charts) -* resolve problems with adding the same item multiple times (by creating new uuids) - -=== usage === -* import the lib: -[source,javascript] ----- -import("Data_lib"); ----- -* create an object -[source,javascript] ----- -var myDescriptiveNameOfTheTree = new DataTree(alias); -// or -var myDescriptiveNameOfTheTree = DataTree.begin(alias); ----- -* use the object, add conditions with add(uid, parent, itemArray) -[source,javascript] ----- -var myTree = myDescriptiveNameOfTheTree.add("1", "myRoot", ["itemId1", "value"]) - .add("2", "myRoot", ["itemId2", "value"]) - .add("3", "2", ["itemId3", "value"]) - .add("4", "2", ["itemId4", "value"]) - .add("5", "4", ["itemId5", "value"]) - .add("5", "3", ["itemId5", "value"]) // Now you added id "5" a second time, overrides previous entry with id 5 - .getTreeObject(); - -var myArray = myDescriptiveNameOfTheTree.toArray(); ----- - -Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one! - -== ReferencingData == -See the library comments for further explanations. - -The purpose of this lib is - -* creating an array with uid and parent from the tree object (e.g. for treetables and charts) -* resolve problems with adding the same item multiple times (by creating new uuids) - -It is a wrapper for DataTree, but only uses the tree if needed. Otherwise the data is just concatenated to an array. - -It does not provide getTreeObject() because the tree is not always built. - -=== usage === -* import the lib: -[source,javascript] ----- -import("Data_lib"); ----- -* create an object -[source,javascript] ----- -var myDescriptiveName = new ReferencingData(alias); -// or -var myDescriptiveName = ReferencingData.begin(alias); ----- -* use the object, add conditions -[source,javascript] ----- -var myTree = myDescriptiveName.add("1", "myRoot", ["itemId1", "value"]) - .add("2", "myRoot", ["itemId2", "value"]) - .add("3", "2", ["itemId3", "value"]) - .add("4", "2", ["itemId4", "value"]) - .add("5", "4", ["itemId5", "value"]) - .add("5", "3", ["itemId5", "value"]) // Now you added id "5" a seccond time. After this line the tree is used. - .toArray(); ----- - -Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one! - -== When to use which == -If you only need an array with parent - child - structure e.g. for the treetable or charts, use -ReferencingData - -If you need a tree object for your logic, use DataTree. \ No newline at end of file diff --git a/process/Classification_lib/process.js b/process/Classification_lib/process.js index e7bb5db9c2e8204942b311c2a28547f34f7caaa4..a3b74a2a54fc68a4df123cb29fef178db2f488c3 100644 --- a/process/Classification_lib/process.js +++ b/process/Classification_lib/process.js @@ -1,4 +1,3 @@ -import("system.logging"); import("system.vars"); import("system.db"); import("Sql_lib"); @@ -12,10 +11,14 @@ import("Sql_lib"); function ClassificationUtils() {} /** - * Get the id of the current context - * TODO: use a UUID of the current context which doesn't change + * Get the score of the classification. You can get all groups at once or only the score for one group. + * + * @param {String} pClassificationType the classification-type (usage) e.g. the Keyid from Keyord ClassificationType + * @param {String} pObjectType the object type + * @param {String} pObjectRowid the rowid + * @param {String} [pClassificationGroup=undefined] the classification group. If it is undefined, the classification for all groups are returned as Object(-map) * - * @return {String} Id of the current context + * @return {Object} return all scores as Object-map. E.g. {"scoreGroup1": "A", "scoreGroup2": "C"} */ ClassificationUtils.getScore = function(pClassificationType, pObjectType, pObjectRowid, pClassificationGroup) { @@ -31,10 +34,7 @@ ClassificationUtils.getScore = function(pClassificationType, pObjectType, pObjec left join CLASSIFICATIONSCORE on CLASSIFICATIONSCORE_ID = CLASSIFICATIONSCOREID", "1=2", "group by CLASSIFICATIONTYPE.CLASSIFICATIONGROUP order by CLASSIFICATIONTYPE.CLASSIFICATIONGROUP asc")); - - if (score.length == 1) - return score[0][1]; - + var scores = {}; score.forEach(function(pRow) { @@ -43,6 +43,15 @@ ClassificationUtils.getScore = function(pClassificationType, pObjectType, pObjec return scores; } +/** + * get all classifications for one dataset as String. Each char represents one classification. + * + * @param {String} pClassificationType the classification-type (usage) e.g. the Keyid from Keyord ClassificationType + * @param {String} pObjectType the object type + * @param {String} pObjectRowid the rowid + * + * @return {String} the resulting classification. E.g. "ACB" + */ ClassificationUtils.getClass = function(pClassificationType, pObjectType, pObjectRowid) { var score = ClassificationUtils.getScore(pClassificationType, pObjectType, pObjectRowid); @@ -52,9 +61,20 @@ ClassificationUtils.getClass = function(pClassificationType, pObjectType, pObjec }).join(""); } +/** + * get the classification for a score. + * The classes are hardcoded like this: + * >=0 to 25: D + * > 25 to 50: C + * > 50 to 75: B + * > 75 to 100: A + * < 0 || > 100: _ + * + * @return {String} + */ ClassificationUtils.mapToClass = function(pScore) { - if(pScore >= 0 && pScore <= 50) + if(pScore >= 0 && pScore <= 25) return "D"; if(pScore > 25 && pScore <= 50) return "C"; @@ -66,18 +86,31 @@ ClassificationUtils.mapToClass = function(pScore) return "_"; } -ClassificationUtils.getAllGroups = function(pClassificationtype, twoCol) +/** + * Get all possible groupnames for a classificationtype + * Either as [["group", "group"]] (for the possible items process) + * Or as [["group"]]. + * + * @param {String} pClassificationtype the classificationtype + * @param {Boolean} pTwoCol use two columns (for possible items process) + */ +ClassificationUtils.getAllGroups = function(pClassificationtype, pTwoCol) { var sql = SqlCondition.begin() .andPrepare("CLASSIFICATIONTYPE.CLASSIFICATIONTYPE", pClassificationtype) - .buildSql("select distinct CLASSIFICATIONGROUP" + (twoCol ? ", CLASSIFICATIONGROUP" : "") + " from CLASSIFICATIONTYPE", "", " order by CLASSIFICATIONGROUP") + .buildSql("select distinct CLASSIFICATIONGROUP" + (pTwoCol ? ", CLASSIFICATIONGROUP" : "") + " from CLASSIFICATIONTYPE", "", " order by CLASSIFICATIONGROUP") - if (twoCol) + if (pTwoCol) return db.table(sql); else return db.array(db.COLUMN, sql); } +/** + * Load the classificationgroup for a classificaitonTypeId from the db. + * + * @param {String} pClassificationtypeId the id + */ ClassificationUtils.getGroupFromDb = function(pClassificationtypeId) { return db.cell(SqlCondition.begin() @@ -85,6 +118,14 @@ ClassificationUtils.getGroupFromDb = function(pClassificationtypeId) .buildSql("select CLASSIFICATIONGROUP from CLASSIFICATIONTYPE", "", " order by CLASSIFICATIONGROUP")) } +/** + * Update the groupname. Checks if it is already used and only updates it, if not. + * TODO: message to the user if it failed? (or return value - bool?) + * + * @param {String} pOldName the name it was before + * @param {String} pNewName the new name + * @param {String} pClassificationType the classificationtype + */ ClassificationUtils.changeGroupName = function(pOldName, pNewName, pClassificationType) { var groups = ClassificationUtils.getAllGroups(pClassificationType, false) @@ -95,6 +136,13 @@ ClassificationUtils.changeGroupName = function(pOldName, pNewName, pClassificati } } +/** + * get the classificationType for the current classification (either vom parameter or selection-variable) + * @param {String} pParamField the parameter field name. e.G. "$param.ClassificationType_param" + * @param {String} pSelectionField the parameter field name. e.G. "$sys.selectionRows" + * + * @return {String} the type (or undefined) + */ ClassificationUtils.getUsageType = function(pParamField, pSelectionField) { if (vars.exists(pParamField) && vars.get(pParamField)) @@ -111,10 +159,13 @@ ClassificationUtils.getUsageType = function(pParamField, pSelectionField) return classificationType; } +/** + * Update the coreName of a type + * + * @param {String} pNewScoreName + * @param {String} pClassificationTypeId + */ ClassificationUtils.changeScoreName = function(pNewScoreName, pClassificationTypeId) { - logging.log(pNewScoreName) - logging.log(pClassificationTypeId) - db.updateData("CLASSIFICATIONTYPE", ["SCORETYPE"], null, [pNewScoreName], SqlCondition.equals("CLASSIFICATIONTYPE.CLASSIFICATIONTYPEID", pClassificationTypeId, "1=2")); } \ No newline at end of file diff --git a/process/Data_lib/process.js b/process/Data_lib/process.js index f104e2381fd2edec355dce026cb008f35a106c79..dcc6c00e814895b04de2777272240ecb8b78f696 100644 --- a/process/Data_lib/process.js +++ b/process/Data_lib/process.js @@ -1,428 +1,467 @@ -import("system.util"); - -/** - * This class is for data which is built in a children -> parent - way. Each "row" consists of one UID and one parentId.<br> - * The class makes sure that even if you add an child multiple times, the ID is corrected, so that the resulting array has only unique id's.<br> - * <br> - * Keep in mind for performance reasons that as soon, as you add a seccond item withe the same UID as an already added child, a tree-object is buiilt internally.<br> - * If you only add unique children, this class will just push them to a simple array.<br> - * <br> - * Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one!<br> - * <br> - * The UID's and parentID's in the generated array may not be the same as you added. If you need to know what you added, simply provide an ID also as data.<br> - * <br> - * When to use this class:<br> - * - you want to fill a Treetable or MultiDataChart<br> - * - and it should be possible to add the same children several times<br> - * <br> - * When NOT to use this class:<br> - * - you need a Tree-Object for your logic and / or want to do additional stuff with the tree -> use "DataTree" directly, because ReferencingData doesn't build always a tree.<br> - * - * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). - * - * @example - * var myResult = ReferencingData.begin("myRoot") - * .add("1", "myRoot", ["itemId1", "value"]) - * .add("2", "myRoot", ["itemId2", "value"]) - * .add("3", "2", ["itemId3", "value"]) - * .add("4", "2", ["itemId4", "value"]) - * .add("5", "4", ["itemId5", "value"]) - * .add("5", "3", ["itemId5", "value"]) // Now you added id "5" a seccond time. As soon as you do this, a tree will be generated internally to resolve the ID's. - * .toArray(); - * - * results in: - * [ - * [ - * "eb2c88a3-ba9d-4991-acf5-7476e7dc5628", // note that the IDs are now new UUIDs - * "", // note that the parentId is now "" - * "itemId1", - * "value" - * ], - * [ - * "f245bfdf-6e3b-4c83-8c4b-14225acce7b3", - * "", - * "itemId2", - * "value" - * ], - * [ - * "054e605e-6224-4cc5-8f02-04c6a6d7965d", - * "f245bfdf-6e3b-4c83-8c4b-14225acce7b3", - * "itemId3", - * "value" - * ], - * [ - * "818641ca-bcf3-415b-8c0e-e2e55430d4d8", - * "054e605e-6224-4cc5-8f02-04c6a6d7965d", - * "itemId5", - * "value" - * ], - * [ - * "c8e81040-c9e1-4f74-bd0f-fb4615ae6bec", - * "f245bfdf-6e3b-4c83-8c4b-14225acce7b3", - * "itemId4", - * "value" - * ], - * [ - * "55eeb384-e5dd-4759-b70d-c2a289762168", - * "c8e81040-c9e1-4f74-bd0f-fb4615ae6bec", - * "itemId5", - * "value" - * ] - * ] - * - * @class - */ -function ReferencingData(pRootId) -{ - this._data = []; - this._uids = {}; - this._rootId = pRootId; -} - -/** - * creates a new ReferencingData-object - * - * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). - * @return {ReferencingData} the new instance - */ -ReferencingData.begin = function(pRootId) -{ var referencingData = new ReferencingData(pRootId); - return referencingData; -} - -/** - * Add an array of data. It will be added row by row to the already added data. - * - * @param {Array} pData the data in the form: [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] - * @return {ReferencingData} this - */ -ReferencingData.prototype.addArray = function(pData) -{ - pData.forEach(function(pRow) - { - this.add(pRow[0], pRow[1], pRow.splice(2)); - }, this); // make "this" also available inside of the forEach - - return this; -} - -/** - * Add one row. If the uid already exists, the data is converted internally to a tree to resolve the ids. - * - * @param {String} pUid the id of the row - * @param {String} pParentId the parentId of the row - * @param {Array} pData the data - * @return {ReferencingData} this - */ -ReferencingData.prototype.add = function(pUid, pParentId, pData) -{ - if (this._dataTree == undefined && this._uids[pUid] == undefined) - { - this._uids[pUid] = true; - this._data.push([pUid, pParentId].concat(pData)); - } else { - this._convertToTree(); // convert to tree if not already a tree - this._dataTree.add(pUid, pParentId, pData); - } - return this; -} - -/** - * Get an array of the added data with already resolved, unique uid's. - * @param {Integer} [pMaxDepth=undefined] If it is set AND if the internal tree-object is used, this option can limit the depth of the tree. - * This is especially to prevent stack overflows if a children-parent-loop exists. - * If you only added unique items, this parameter is ignored! - * @return {Array} [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] - */ -ReferencingData.prototype.toArray = function(pMaxDepth) -{ - if (this._dataTree == undefined) - { - return this._data; - } - else - { - return this._dataTree.toArray(pMaxDepth); - } -} - -/** - * switch to tree if the tree is not already used. - * - * @ignore - */ -ReferencingData.prototype._convertToTree = function() -{ - if (this._dataTree == undefined) - { - this._dataTree = DataTree.begin(this._rootId) - .addArray(this._data); - this._data = undefined; - } -} - -/** - * This class is for creating a tree structure. - * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). - * - * @example - * - * var myResult = DataTree.begin("myRoot") - * .add("1", "myRoot", ["itemId1", "value"]) - * .add("2", "myRoot", ["itemId2", "value"]) - * .add("3", "2", ["itemId3", "value"]) - * .add("4", "2", ["itemId4", "value"]) - * .add("5", "4", ["itemId5", "value"]) - * .add("5", "3", ["itemId5", "value"]) // Now you added id "5" a seccond time. - * .getTreeObject(); - * results in: - * - * ({ - * 1:{ - * data:[ - * "itemId1", - * "value" - * ], - * parent:"myRoot", - * ids:[ - * - * ] - * }, - * 2:{ - * data:[ - * "itemId2", - * "value" - * ], - * parent:"myRoot", - * ids:[ - * "3", - * "4" - * ] - * }, - * 3:{ - * data:[ - * "itemId3", - * "value" - * ], - * parent:"2", - * ids:[ - * "5" - * ] - * }, - * 4:{ - * data:[ - * "itemId4", - * "value" - * ], - * parent:"2", - * ids:[ - * "5" - * ] - * }, - * 5:{ - * data:[ - * "itemId5", - * "value" - * ], - * parent:"3", - * ids:[ - * - * ] - * }, - * myRoot:{ - * ids:[ - * "1", - * "2" - * ], - * parent:"9f034e84-39a8-4239-ba06-ccc604654477" - * } - *}) - * - * TODO: evtl check-funktion anbieten - * - * @class - */ -function DataTree(pRootId) -{ - this._dataTree = { - - }; - - this._resultData = []; - this.rootId = pRootId; - this.baseId = util.getNewUUID(); -} - -/** - * creates a new DataTree-object - * - * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). - * @return {DataTree} the new instance - */ -DataTree.begin = function(pRootId) -{ - return new DataTree(pRootId); -} - -/** - * Get the tree object. See the example of the class. - * @return {Object} the tree-object - * ({ - * GENERATED_UUID:{ - * data:[ - * ... - * ... - * ], - * parent:"parentId", - * ids:[ - * "childid1", - * "childid2", - * .... - * ] - * }, - * ... - * ) - */ -DataTree.prototype.getTreeObject = function() -{ - return this._dataTree; -} - -/** - * Add one row. - * Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one! - * - * @param {String} pUid the id of the row - * @param {String} pParentId the parentId of the row - * @param {Array} pData the data - * @param {DataTree~manipulateNode} [pManipulateNodeFn=undefined] callback for manipulating the Node. Attention: Use with caution. You can corrupt the tree. - * @return {DataTree} this - */ -DataTree.prototype.add = function(pUid, pParentId, pData, pManipulateNodeFn) -{ - if (this._dataTree[pParentId] == undefined) - { - // create parent node. It will be replaced later, if the actual parent is added. - this._dataTree[pParentId] = { - ids: [], - parent: this.baseId - } - } - this._dataTree[pParentId].ids.push(pUid); - - if (pManipulateNodeFn != undefined) - pManipulateNodeFn(pParentId, this._dataTree[pParentId]); - - var tmpIds = []; - // node already created as parent by a childNode. - if (this._dataTree[pUid] != undefined && this._dataTree[pUid].parent == this.baseId) - { - // tmp-save already added ids of the node - tmpIds = this._dataTree[pUid].ids; - } - - this._dataTree[pUid] = { - data: pData, - parent: pParentId - } - - if (this._dataTree[pUid].ids == undefined) - { - this._dataTree[pUid].ids = tmpIds; - } - - // callback to provide a hook for manipulating the node. (e.g. for adding additional node data) - if (pManipulateNodeFn != undefined) - pManipulateNodeFn(pUid, this._dataTree[pUid]); - - return this; -} - -/** - * Add an array of data. It will be added row by row to the already added data. - * Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one! - * - * @param {Array} pData the data in the form: [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] - * @param {DataTree~manipulateNode} [pManipulateNodeFn=undefined] callback for manipulating the Node. Attention: Use with caution. You can corrupt the tree. - * - * @return {DataTree} this - */ -DataTree.prototype.addArray = function(pData, pManipulateNodeFn) -{ - pData.forEach(function(pRow) - { - this.add(pRow[0], pRow[1], pRow.splice(2), pManipulateNodeFn); - }, this); - - return this; -} - -/** - * Get an array of the added data with already resolved, unique uid's. - * @param {Integer} [pMaxDepth=undefined] If it is set, this option can limit the depth of the tree. - * This is especially to prevent stack overflows if a children-parent-loop exists. - * @return {Array} [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] - */ -DataTree.prototype.toArray = function(pMaxDepth) -{ - var that = this; - // TODO: maybe implement without recursion to prevent stack overflow even on deep milestones... - var treeArray = []; - var tree = this._dataTree; - - // in this function Ids are just concatenated. This is bad, because it results in very long strings. - // Because of this the concatenated id's are maped to new uids in the resulting array - var uidMap = {}; - __push(this.rootId, tree[this.rootId], 0); - - function __push(pParent, pNode, pDepth) { - if (pNode != undefined) - { - for (var i = 0; i < pNode.ids.length; i++) { - if (pNode.parent == that.baseId) - { - // set UUID to "" if it is a root-node - pParent = ""; - } - - var nextUid = pParent + pNode.ids[i]; - __addRow(nextUid, pParent, tree[pNode.ids[i]].data); - - if (pMaxDepth == undefined || pDepth < pMaxDepth) - __push(nextUid, tree[pNode.ids[i]], pDepth+1); - } - } - } - - function __addRow(pUid, pParentId, pRowdata) - { - uidMap[pUid] = util.getNewUUID(); - if (uidMap[pParentId] == undefined) { - // The root node has "" as ID. - if (pParentId == "") - { - uidMap[pParentId] = ""; - } - else - { - uidMap[pParentId] = util.getNewUUID(); - } - } - - treeArray.push([uidMap[pUid], uidMap[pParentId]].concat(pRowdata)); - } - - return treeArray; -} - -/** - * Manipulate a node with this callback - * You get the uid of the node and the node. - * You can do anything you want, with the node. - * - * But if you modify parent or ids, the tree may corrupt. - * - * @callback DataTree~manipulateNode - * @param {String} pUid - * @param {Object} pNode +import("system.util"); + +/** + * This class is for data which is built in a children -> parent - way. Each "row" consists of one UID and one parentId.<br> + * The class makes sure that even if you add an child multiple times, the ID is corrected, so that the resulting array has only unique id's.<br> + * <br> + * Keep in mind for performance reasons that as soon, as you add a seccond item withe the same UID as an already added child, a tree-object is buiilt internally.<br> + * If you only add unique children, this class will just push them to a simple array.<br> + * <br> + * Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one!<br> + * <br> + * The UID's and parentID's in the generated array may not be the same as you added. If you need to know what you added, simply provide an ID also as data.<br> + * <br> + * When to use this class:<br> + * - you want to fill a Treetable or MultiDataChart<br> + * - and it should be possible to add the same children several times<br> + * <br> + * When NOT to use this class:<br> + * - you need a Tree-Object for your logic and / or want to do additional stuff with the tree -> use "DataTree" directly, because ReferencingData doesn't build always a tree.<br> + * + * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). + * + * @example + * var myResult = ReferencingData.begin("myRoot") + * .add("1", "myRoot", ["itemId1", "value"]) + * .add("2", "myRoot", ["itemId2", "value"]) + * .add("3", "2", ["itemId3", "value"]) + * .add("4", "2", ["itemId4", "value"]) + * .add("5", "4", ["itemId5", "value"]) + * .add("5", "3", ["itemId5", "value"]) // Now you added id "5" a seccond time. As soon as you do this, a tree will be generated internally to resolve the ID's. + * .toArray(); + * + * results in: + * [ + * [ + * "eb2c88a3-ba9d-4991-acf5-7476e7dc5628", // note that the IDs are now new UUIDs + * "", // note that the parentId is now "" + * "itemId1", + * "value" + * ], + * [ + * "f245bfdf-6e3b-4c83-8c4b-14225acce7b3", + * "", + * "itemId2", + * "value" + * ], + * [ + * "054e605e-6224-4cc5-8f02-04c6a6d7965d", + * "f245bfdf-6e3b-4c83-8c4b-14225acce7b3", + * "itemId3", + * "value" + * ], + * [ + * "818641ca-bcf3-415b-8c0e-e2e55430d4d8", + * "054e605e-6224-4cc5-8f02-04c6a6d7965d", + * "itemId5", + * "value" + * ], + * [ + * "c8e81040-c9e1-4f74-bd0f-fb4615ae6bec", + * "f245bfdf-6e3b-4c83-8c4b-14225acce7b3", + * "itemId4", + * "value" + * ], + * [ + * "55eeb384-e5dd-4759-b70d-c2a289762168", + * "c8e81040-c9e1-4f74-bd0f-fb4615ae6bec", + * "itemId5", + * "value" + * ] + * ] + * + * @class + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +function ReferencingData(pRootId) +{ + this._data = []; + this._uids = {}; + this._rootId = pRootId; +} + +/** + * creates a new ReferencingData-object + * + * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). + * @return {ReferencingData} the new instance + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +ReferencingData.begin = function(pRootId) +{ var referencingData = new ReferencingData(pRootId); + return referencingData; +} + +/** + * Add an array of data. It will be added row by row to the already added data. + * + * @param {Array} pData the data in the form: [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] + * @return {ReferencingData} this + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +ReferencingData.prototype.addArray = function(pData) +{ + pData.forEach(function(pRow) + { + this.add(pRow[0], pRow[1], pRow.splice(2)); + }, this); // make "this" also available inside of the forEach + + return this; +} + +/** + * Add one row. If the uid already exists, the data is converted internally to a tree to resolve the ids. + * + * @param {String} pUid the id of the row + * @param {String} pParentId the parentId of the row + * @param {Array} pData the data + * @return {ReferencingData} this + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +ReferencingData.prototype.add = function(pUid, pParentId, pData) +{ + if (this._dataTree == undefined && this._uids[pUid] == undefined) + { + this._uids[pUid] = true; + this._data.push([pUid, pParentId].concat(pData)); + } else { + this._convertToTree(); // convert to tree if not already a tree + this._dataTree.add(pUid, pParentId, pData); + } + return this; +} + +/** + * Get an array of the added data with already resolved, unique uid's. + * @param {Integer} [pMaxDepth=undefined] If it is set AND if the internal tree-object is used, this option can limit the depth of the tree. + * This is especially to prevent stack overflows if a children-parent-loop exists. + * If you only added unique items, this parameter is ignored! + * @return {Array} [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +ReferencingData.prototype.toArray = function(pMaxDepth) +{ + if (this._dataTree == undefined) + { + return this._data; + } + else + { + return this._dataTree.toArray(pMaxDepth); + } +} + +/** + * switch to tree if the tree is not already used. + * + * @ignore + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +ReferencingData.prototype._convertToTree = function() +{ + if (this._dataTree == undefined) + { + this._dataTree = DataTree.begin(this._rootId) + .addArray(this._data); + this._data = undefined; + } +} + +/** + * This class is for creating a tree structure. + * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). + * + * @example + * + * var myResult = DataTree.begin("myRoot") + * .add("1", "myRoot", ["itemId1", "value"]) + * .add("2", "myRoot", ["itemId2", "value"]) + * .add("3", "2", ["itemId3", "value"]) + * .add("4", "2", ["itemId4", "value"]) + * .add("5", "4", ["itemId5", "value"]) + * .add("5", "3", ["itemId5", "value"]) // Now you added id "5" a seccond time. + * .getTreeObject(); + * results in: + * + * ({ + * 1:{ + * data:[ + * "itemId1", + * "value" + * ], + * parent:"myRoot", + * ids:[ + * + * ] + * }, + * 2:{ + * data:[ + * "itemId2", + * "value" + * ], + * parent:"myRoot", + * ids:[ + * "3", + * "4" + * ] + * }, + * 3:{ + * data:[ + * "itemId3", + * "value" + * ], + * parent:"2", + * ids:[ + * "5" + * ] + * }, + * 4:{ + * data:[ + * "itemId4", + * "value" + * ], + * parent:"2", + * ids:[ + * "5" + * ] + * }, + * 5:{ + * data:[ + * "itemId5", + * "value" + * ], + * parent:"3", + * ids:[ + * + * ] + * }, + * myRoot:{ + * ids:[ + * "1", + * "2" + * ], + * parent:"9f034e84-39a8-4239-ba06-ccc604654477" + * } + *}) + * + * TODO: evtl check-funktion anbieten + * + * @class + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +function DataTree(pRootId) +{ + this._dataTree = { + + }; + + this._resultData = []; + this.rootId = pRootId; + this.baseId = util.getNewUUID(); +} + +/** + * creates a new DataTree-object + * + * @param {String} pRootId the Id you use as parentId for the root elements. The parentId for base elements will be changed to "" when using toArray(). + * @return {DataTree} the new instance + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +DataTree.begin = function(pRootId) +{ + return new DataTree(pRootId); +} + +/** + * Get the tree object. See the example of the class. + * @return {Object} the tree-object + * ({ + * GENERATED_UUID:{ + * data:[ + * ... + * ... + * ], + * parent:"parentId", + * ids:[ + * "childid1", + * "childid2", + * .... + * ] + * }, + * ... + * ) + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +DataTree.prototype.getTreeObject = function() +{ + return this._dataTree; +} + +/** + * Add one row. + * Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one! + * + * @param {String} pUid the id of the row + * @param {String} pParentId the parentId of the row + * @param {Array} pData the data + * @param {DataTree~manipulateNode} [pManipulateNodeFn=undefined] callback for manipulating the Node. Attention: Use with caution. You can corrupt the tree. + * @return {DataTree} this + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +DataTree.prototype.add = function(pUid, pParentId, pData, pManipulateNodeFn) +{ + if (this._dataTree[pParentId] == undefined) + { + // create parent node. It will be replaced later, if the actual parent is added. + this._dataTree[pParentId] = { + ids: [], + parent: this.baseId + } + } + this._dataTree[pParentId].ids.push(pUid); + + if (pManipulateNodeFn != undefined) + pManipulateNodeFn(pParentId, this._dataTree[pParentId]); + + var tmpIds = []; + // node already created as parent by a childNode. + if (this._dataTree[pUid] != undefined && this._dataTree[pUid].parent == this.baseId) + { + // tmp-save already added ids of the node + tmpIds = this._dataTree[pUid].ids; + } + + this._dataTree[pUid] = { + data: pData, + parent: pParentId + } + + if (this._dataTree[pUid].ids == undefined) + { + this._dataTree[pUid].ids = tmpIds; + } + + // callback to provide a hook for manipulating the node. (e.g. for adding additional node data) + if (pManipulateNodeFn != undefined) + pManipulateNodeFn(pUid, this._dataTree[pUid]); + + return this; +} + +/** + * Add an array of data. It will be added row by row to the already added data. + * Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one! + * + * @param {Array} pData the data in the form: [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] + * @param {DataTree~manipulateNode} [pManipulateNodeFn=undefined] callback for manipulating the Node. Attention: Use with caution. You can corrupt the tree. + * + * @return {DataTree} this + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +DataTree.prototype.addArray = function(pData, pManipulateNodeFn) +{ + pData.forEach(function(pRow) + { + this.add(pRow[0], pRow[1], pRow.splice(2), pManipulateNodeFn); + }, this); + + return this; +} + +/** + * Get an array of the added data with already resolved, unique uid's. + * @param {Integer} [pMaxDepth=undefined] If it is set, this option can limit the depth of the tree. + * This is especially to prevent stack overflows if a children-parent-loop exists. + * @return {Array} [ [uid, parentId, [data...], [uid2, parentId2, [data2...] ] + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. + */ +DataTree.prototype.toArray = function(pMaxDepth) +{ + var that = this; + // TODO: maybe implement without recursion to prevent stack overflow even on deep milestones... + var treeArray = []; + var tree = this._dataTree; + + // in this function Ids are just concatenated. This is bad, because it results in very long strings. + // Because of this the concatenated id's are maped to new uids in the resulting array + var uidMap = {}; + __push(this.rootId, tree[this.rootId], 0); + + function __push(pParent, pNode, pDepth) { + if (pNode != undefined) + { + for (var i = 0; i < pNode.ids.length; i++) { + if (pNode.parent == that.baseId) + { + // set UUID to "" if it is a root-node + pParent = ""; + } + + var nextUid = pParent + pNode.ids[i]; + __addRow(nextUid, pParent, tree[pNode.ids[i]].data); + + if (pMaxDepth == undefined || pDepth < pMaxDepth) + __push(nextUid, tree[pNode.ids[i]], pDepth+1); + } + } + } + + function __addRow(pUid, pParentId, pRowdata) + { + uidMap[pUid] = util.getNewUUID(); + if (uidMap[pParentId] == undefined) { + // The root node has "" as ID. + if (pParentId == "") + { + uidMap[pParentId] = ""; + } + else + { + uidMap[pParentId] = util.getNewUUID(); + } + } + + treeArray.push([uidMap[pUid], uidMap[pParentId]].concat(pRowdata)); + } + + return treeArray; +} + +/** + * Manipulate a node with this callback + * You get the uid of the node and the node. + * You can do anything you want, with the node. + * + * But if you modify parent or ids, the tree may corrupt. + * + * @callback DataTree~manipulateNode + * @param {String} pUid + * @param {Object} pNode + * + * @deprecated better use a own object or array, which fits better to your case, as this lib has some problems. + * The biggest problem: if you add an item two times, only the data-array of the second item is used. It will overwrite the data from the first one. */ \ No newline at end of file