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 i; 52 for (i in constructCategoryArray) { 53 if (constructCategoryArray.hasOwnProperty(i)) { 54 var category = constructCategoryArray[i]; 55 if (category.sortorder && 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 into a flat hash map. 66 * 67 * @param {object<string, object>} constructs 68 * @return {object<string, object>} 69 */ 70 function mapConstructs(constructs) { 71 72 var map = {}; 73 74 if (!constructs) { 75 return map; 76 } 77 78 var constructId; 79 for (constructId in constructs) { 80 if (constructs.hasOwnProperty(constructId)) { 81 var construct = constructs[constructId]; 82 map[construct.keyword] = construct; 83 } 84 } 85 return map; 86 } 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: 'folder', 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 Returns the constructs / categories 132 * @throws INVALID_ARGUMENTS 133 */ 134 constructs: function (success, error) { 135 if (!success) { 136 GCN.error('INVALID_ARGUMENTS', 'the `constructs()\' method ' + 137 'requires at least a success callback to be given'); 138 } 139 140 if (this._constructs) { 141 success(this._constructs); 142 } else { 143 var that = this; 144 this._authAjax({ 145 url : GCN.settings.BACKEND_PATH + 146 '/rest/construct/list.json', 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 that._constructs = mapConstructs(response.constructs); 154 //console.dir(that._constructs); 155 success(that._constructs); 156 } else { 157 GCN.handleResponseError(response, error); 158 } 159 } 160 }); 161 } 162 }, 163 164 /** 165 * Removes this node object. 166 * 167 * @param {function=} success Callback. 168 * @param {function(GCNError):boolean=} error Custom error handler. 169 * @param {function} success callback 170 */ 171 remove: function (success, error) { 172 173 }, 174 175 /** 176 * @FIXME: Is it really possible to save changes to a node? If not, 177 * then we should not surface this method. 178 */ 179 save: function () {}, 180 181 /** 182 * Retreives the top-level folders of this node's root folder. 183 * 184 * @param {function(FolderAPI)=} success 185 * @param {function(GCNError):boolean=} error Custom error handler. 186 */ 187 '!folders': function (success, error) { 188 return this.folder(null, error).folders(success, error); 189 }, 190 191 /** 192 * Helper method that will load the constructs of this node. 193 * 194 * @private 195 * @this {NodeAPI} 196 * @param {function(Array.<object>)} success callback 197 * @param {function(GCNError):boolean=} error callback 198 */ 199 constructCategories: function (success, error) { 200 if (this._constructCategories) { 201 success(this._constructCategories); 202 } else { 203 var that = this; 204 this._continueWith(function (child) { 205 that._data.id = child._data.nodeId; 206 207 that.constructs(function (constructs) { 208 that._constructCategories = mapConstructCategories(constructs); 209 success(that._constructCategories); 210 }, error); 211 }, error); 212 213 /* 214 this._authAjax({ 215 url : GCN.settings.BACKEND_PATH + 216 '/rest/construct/load.json', 217 type : 'GET', 218 error : function (xhr, status, msg) { 219 GCN.handleHttpError(xhr, msg, error); 220 }, 221 success: function (response) { 222 if (GCN.getResponseCode(response) === 'OK') { 223 that._constructCategories = 224 response.constructCategories; 225 success(response.constructCategories); 226 } else { 227 GCN.handleResponseError(response, error); 228 } 229 } 230 }); 231 */ 232 } 233 } 234 235 }); 236 237 GCN.node = GCN.exposeAPI(NodeAPI); 238 GCN.NodeAPI = NodeAPI; 239 240 }(GCN)); 241