1 /*global GCN: true */ 2 (function (GCN) { 3 'use strict'; 4 5 /** 6 * Maps constructcategories that were fetched via the Rest API into a 7 * sorted nested array of constructs. 8 * 9 * @param {object<string, object>} constructs 10 * @return {object<string, object>} 11 */ 12 function mapConstructCategories(constructs) { 13 var constructKeyword; 14 var categoryMap = { 15 categories: {}, 16 categorySortorder: [] 17 }; 18 var constructCategoryArray = []; 19 for (constructKeyword in constructs) { 20 if (constructs.hasOwnProperty(constructKeyword)) { 21 var construct = constructs[constructKeyword]; 22 var constructCategoryName = construct.category; 23 var categorySortorder = construct.categorySortorder; 24 25 // Use a custom name for constructs that have not been assigned 26 // to a category. 27 if (!constructCategoryName) { 28 constructCategoryName = 'GCN_UNCATEGORIZED'; 29 categorySortorder = -1; 30 } 31 32 // Initialize the inner array of constructs. 33 if (!categoryMap.categories[constructCategoryName]) { 34 var newCategory = {}; 35 newCategory.constructs = {}; 36 newCategory.sortorder = categorySortorder; 37 newCategory.name = constructCategoryName; 38 categoryMap.categories[constructCategoryName] = newCategory; 39 constructCategoryArray.push(newCategory); 40 } 41 42 // Add the construct to the category. 43 categoryMap.categories[constructCategoryName] 44 .constructs[constructKeyword] = construct; 45 } 46 } 47 48 // Sort the categories by the sortorder. 49 constructCategoryArray.sort(function (a, b) { 50 return a.sortorder - b.sortorder; 51 }); 52 53 // Add the sorted category names to the sortorder field. 54 var k; 55 for (k in constructCategoryArray) { 56 if (constructCategoryArray.hasOwnProperty(k)) { 57 var category = constructCategoryArray[k]; 58 if (typeof category.sortorder !== 'undefined' && category.sortorder !== -1) { 59 categoryMap.categorySortorder.push(category.name); 60 } 61 } 62 } 63 64 return categoryMap; 65 } 66 67 /** 68 * Maps constructs, that were fetched via the Rest API, using their keyword 69 * as the keys. 70 * 71 * @param {object<string, object>} constructs Consturcts mapped against 72 * their id. 73 * @return {object<string, object>} Constructs mapped against their keys. 74 */ 75 function mapConstructs(constructs) { 76 if (!constructs) { 77 return {}; 78 } 79 var map = {}; 80 var constructId; 81 for (constructId in constructs) { 82 if (constructs.hasOwnProperty(constructId)) { 83 map[constructs[constructId].keyword] = constructs[constructId]; 84 } 85 } 86 return map; 87 } 88 89 /** 90 * Node object. 91 * 92 * @name NodeAPI 93 * @class 94 * @augments Chainback 95 */ 96 var NodeAPI = GCN.defineChainback({ 97 /** @lends NodeAPI */ 98 99 __chainbacktype__: 'NodeAPI', 100 _extends: GCN.ContentObjectAPI, 101 _type: 'node', 102 103 _data: { 104 folderId: null 105 }, 106 107 /** 108 * @private 109 * @type {object<string, number} Constructs for this node are cached 110 * here so that we only need to fetch 111 * this once. 112 */ 113 _constructs: null, 114 115 /** 116 * @private 117 * @type {object<string, object} Constructs categories for this node. 118 * Cached here so that we only need to 119 * fetch this once. 120 */ 121 _constructCategories: null, 122 123 /** 124 * Retrieves a list of constructs and constructs categories that are 125 * assigned to this node and passes it as the only argument into the 126 * the `success()' callback. 127 * 128 * @param {function(Array.<object>)=} success Callback to receive an 129 * array of constructs. 130 * @param {function(GCNError):boolean=} error Custom error handler. 131 * @return undefined 132 * @throws INVALID_ARGUMENTS 133 */ 134 constructs: function (success, error) { 135 if (!success) { 136 return; 137 } 138 var node = this; 139 if (node._constructs) { 140 node._invoke(success, [node._constructs]); 141 return; 142 } 143 node._read(function () { 144 node._authAjax({ 145 url: GCN.settings.BACKEND_PATH + 146 '/rest/construct/list.json?nodeId=' + node.id(), 147 type: 'GET', 148 error: function (xhr, status, msg) { 149 GCN.handleHttpError(xhr, msg, error); 150 }, 151 success: function (response) { 152 if (GCN.getResponseCode(response) === 'OK') { 153 node._constructs = mapConstructs(response.constructs); 154 node._invoke(success, [node._constructs]); 155 } else { 156 GCN.handleResponseError(response, error); 157 } 158 } 159 }); 160 }, error); 161 }, 162 163 /** 164 * Removes this node object. 165 * 166 * @param {function=} success Callback function to be invoked when 167 * this operation has completed 168 * successfully. 169 * @param {function(GCNError):boolean=} error Custom error handler. 170 */ 171 remove: function (success, error) { 172 GCN.handleError( 173 GCN.error('NOT_YET_IMPLEMENTED', 174 'This method is not yet implemented', this), 175 error 176 ); 177 }, 178 179 /** 180 * Saves the locally modified changes back to the system. 181 * This is currently not yet implemented. 182 * 183 * @param {function=} success Callback function to be invoked when 184 * this operation has completed 185 * successfully. 186 * @param {function(GCNError):boolean=} error Custom error handler. 187 */ 188 save: function (success, error) { 189 GCN.handleError( 190 GCN.error('NOT_YET_IMPLEMENTED', 191 'This method is not yet implemented', this), 192 error 193 ); 194 }, 195 196 /** 197 * Retrieves the top-level folders of this node's root folder. 198 * 199 * @param {function(FolderAPI)=} success 200 * @param {function(GCNError):boolean=} error Custom error handler. 201 */ 202 '!folders': function (success, error) { 203 return this.folder(null, error).folders(success, error); 204 }, 205 206 /** 207 * Helper method that will load the constructs of this node. 208 * 209 * @private 210 * @this {NodeAPI} 211 * @param {function(Array.<object>)} success callback 212 * @param {function(GCNError):boolean=} error callback 213 */ 214 constructCategories: function (success, error) { 215 if (!success) { 216 return; 217 } 218 var node = this; 219 if (node._constructCategories) { 220 node._invoke(success, [node._constructCategories]); 221 } else { 222 node._read(function () { 223 node._data.id = node._chain._data.nodeId; 224 node.constructs(function (constructs) { 225 node._constructCategories = 226 mapConstructCategories(constructs); 227 node._invoke(success, [node._constructCategories]); 228 }, error); 229 }, error); 230 } 231 } 232 }); 233 234 GCN.node = GCN.exposeAPI(NodeAPI); 235 GCN.NodeAPI = NodeAPI; 236 237 }(GCN)); 238