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 * Represents a Node 91 * 92 * @name NodeAPI 93 * @class 94 * @augments Chainback 95 * 96 * @param {number|string} 97 * id of the file to be loaded 98 * @param {function(ContentObjectAPI))=} 99 * success Optional success callback that will receive this 100 * object as its only argument. 101 * @param {function(GCNError):boolean=} 102 * error Optional custom error handler. 103 * @param {object} 104 * settings currently there are no additional settings to be used 105 */ 106 var NodeAPI = GCN.defineChainback({ 107 /** @lends NodeAPI */ 108 109 __chainbacktype__: 'NodeAPI', 110 _extends: GCN.ContentObjectAPI, 111 _type: 'node', 112 113 _data: { 114 folderId: null 115 }, 116 117 /** 118 * @private 119 * @type {object<string, number} Constructs for this node are cached 120 * here so that we only need to fetch 121 * this once. 122 */ 123 _constructs: null, 124 125 /** 126 * @private 127 * @type {object<string, object} Constructs categories for this node. 128 * Cached here so that we only need to 129 * fetch this once. 130 */ 131 _constructCategories: null, 132 133 /** 134 * Retrieves a list of constructs and constructs categories that are 135 * assigned to this node and passes it as the only argument into the 136 * the `success()' callback. 137 * 138 * @param {function(Array.<object>)=} success Callback to receive an 139 * array of constructs. 140 * @param {function(GCNError):boolean=} error Custom error handler. 141 * @return undefined 142 * @throws INVALID_ARGUMENTS 143 */ 144 constructs: function (success, error) { 145 if (!success) { 146 return; 147 } 148 var node = this; 149 if (node._constructs) { 150 node._invoke(success, [node._constructs]); 151 return; 152 } 153 node._read(function () { 154 node._authAjax({ 155 url: GCN.settings.BACKEND_PATH + 156 '/rest/construct/list.json?nodeId=' + node.id(), 157 type: 'GET', 158 error: function (xhr, status, msg) { 159 GCN.handleHttpError(xhr, msg, error); 160 }, 161 success: function (response) { 162 if (GCN.getResponseCode(response) === 'OK') { 163 node._constructs = mapConstructs(response.constructs); 164 node._invoke(success, [node._constructs]); 165 } else { 166 GCN.handleResponseError(response, error); 167 } 168 } 169 }); 170 }, error); 171 }, 172 173 /** 174 * Removes this node object. 175 * 176 * @ignore 177 * @param {function=} success Callback function to be invoked when 178 * this operation has completed 179 * successfully. 180 * @param {function(GCNError):boolean=} error Custom error handler. 181 */ 182 remove: function (success, error) { 183 GCN.handleError( 184 GCN.createError( 185 'NOT_YET_IMPLEMENTED', 186 'This method is not yet implemented', 187 this 188 ), 189 error 190 ); 191 }, 192 193 /** 194 * Saves the locally modified changes back to the system. 195 * This is currently not yet implemented. 196 * 197 * @ignore 198 * @param {function=} success Callback function to be invoked when 199 * this operation has completed 200 * successfully. 201 * @param {function(GCNError):boolean=} error Custom error handler. 202 */ 203 save: function (success, error) { 204 GCN.handleError( 205 GCN.createError( 206 'NOT_YET_IMPLEMENTED', 207 'This method is not yet implemented', 208 this 209 ), 210 error 211 ); 212 }, 213 214 /** 215 * Retrieves the top-level folders of this node's root folder. 216 * 217 * @function 218 * @name folders 219 * @memberOf NodeAPI 220 * @param {function(FolderAPI)=} success 221 * @param {function(GCNError):boolean=} error Custom error handler. 222 */ 223 '!folders': function (success, error) { 224 return this.folder(null, error).folders(success, error); 225 }, 226 227 /** 228 * Helper method that will load the constructs of this node. 229 * @ignore 230 * @private 231 * @this {NodeAPI} 232 * @param {function(Array.<object>)} success callback 233 * @param {function(GCNError):boolean=} error callback 234 */ 235 constructCategories: function (success, error) { 236 if (!success) { 237 return; 238 } 239 var node = this; 240 if (node._constructCategories) { 241 node._invoke(success, [node._constructCategories]); 242 } else { 243 node._read(function () { 244 node._data.id = node._chain._data.nodeId; 245 node.constructs(function (constructs) { 246 node._constructCategories = 247 mapConstructCategories(constructs); 248 node._invoke(success, [node._constructCategories]); 249 }, error); 250 }, error); 251 } 252 } 253 }); 254 255 /** 256 * Creates a new instance of NodeAPI. See the {@link NodeAPI} constructor for detailed information. 257 * 258 * @function 259 * @name node 260 * @memberOf GCN 261 * @see NodeAPI 262 */ 263 GCN.node = GCN.exposeAPI(NodeAPI); 264 GCN.NodeAPI = NodeAPI; 265 266 }(GCN)); 267