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