1 (function (GCN) { 2 3 'use strict'; 4 5 /** 6 * @private 7 * @const 8 * @type {number} 9 */ 10 //var TYPE_ID = 10002; 11 12 /** 13 * @const 14 * @private 15 * @type {object<string, *>} Default folder settings. 16 */ 17 var DEFAULT_SETTINGS = { 18 // Load folder privileges as well 19 loadFolderPrivileges: true 20 }; 21 22 /** 23 * @class 24 * @name FolderAPI 25 * @extends ContentObjectAPI 26 * @extends TagContainerAPI 27 */ 28 var FolderAPI = GCN.defineChainback({ 29 /** @lends FolderAPI */ 30 31 __chainbacktype__: 'FolderAPI', 32 _extends: [ GCN.ContentObjectAPI, GCN.TagContainerAPI ], 33 _type: 'folder', 34 35 /** 36 * @public 37 * @type {Array.<string>} Writable properties for the folder object. 38 */ 39 WRITEABLE_PROPS: [ 'description', 40 'motherId', 41 'name', 42 'publishDir' ], 43 44 /** 45 * Persist changes made to the page object in Gentics Content.Node . 46 * 47 * @public 48 * @param {function(FolderAPI)=} success Optional callback that will 49 * receive this object as its 50 * only argument. 51 * @param {function(GCNError):boolean} error Optional custom error 52 * handler. 53 */ 54 save: function (success, error) { 55 this._save(null, success, error); 56 }, 57 58 /** 59 * Removes the folder and all its parent objects 60 * 61 * @public 62 * @param {function(FolderAPI)=} success Optional callback that will 63 * receive this object as its 64 * only argument. 65 * @param {function(GCNError):boolean} error Optional custom error 66 * handler. 67 */ 68 remove: function (success, error) { 69 this._remove(success, error); 70 }, 71 72 /** 73 * Gets this folder's parent folder. If this folder does not have a 74 * parent, then the returned object will be an API to an object that 75 * does not exists. Only when attempting to perform read/write 76 * operations on this object on the server will a `NOTFOUND' error be 77 * encountered. We recognize that this is relatively late for the use 78 * to find out that this folder has no parent; if the use need to 79 * guarentee that a parent folder exists before further operations, 80 * they are simply to pass a callback into this function. 81 * 82 * @name parent 83 * @memberOf FolderAPI 84 * @public 85 * @param {function(FolderAPI)=} success Optional callback that will 86 * receive this object as its 87 * only argument. 88 * @param {function(GCNError):boolean} error Optional custom error 89 * handler. 90 * @return {FolderAPI} The parent folder 91 */ 92 '!parent': function (success, error) { 93 this._continue(GCN.FolderAPI, this.id(), success, error); 94 }, 95 96 /** 97 * Check if a given permission is available for a folder. If no 98 * name is provided an array of available permissions is returned. 99 * 100 * @name perm 101 * @memberOf FolderAPI 102 * @public 103 * @param {name} optional Privilege name to be checked. possible 104 * values are: 105 * "viewfolder" 106 * "createfolder" 107 * "updatefolder" 108 * "deletefolder" 109 * "viewpage" 110 * "createpage" 111 * "updatepage" 112 * "deletepage" 113 * "publishpage" 114 * "viewtemplate" 115 * "createtemplate" 116 * "linktemplate" 117 * "updatetemplate" 118 * "deletetemplate" 119 * @return {boolean|Array.<string>} Permission value for the given name 120 * or an array of permissions 121 */ 122 '!perm': function (name) { 123 var i; 124 125 if (!name) { 126 return this._data.privileges; 127 } 128 129 for (i in this._data.privileges) { 130 if (this._data.privileges.hasOwnProperty(i) && 131 this._data.privileges[i] === name) { 132 return true; 133 } 134 } 135 136 return false; 137 }, 138 139 // ==================================================================== 140 // Pages 141 // ==================================================================== 142 143 /** 144 * Returns page of the given id which resides in this folder. 145 * 146 * @public 147 * @name page 148 * @memberOf FolderAPI 149 * @param {number} id 150 * @param {function(PageAPI)=} success Optional callback that will 151 * receive a {@link PageAPI} object 152 * as its only argument. 153 * @param {function(GCNError):boolean=} error Optional custom error 154 * handler. 155 * @return {PageAPI} 156 */ 157 '!page': function (id, success, error) { 158 return this._continue(GCN.PageAPI, id, success, error); 159 }, 160 161 /** 162 * Retreive a list of all pages this folder. 163 * 164 * @param {function(Array.PageAPI)=} success Optional callback that 165 * will receive an array of 166 * {@link PageAPI} objects as 167 * its only argument. 168 * @param {function(GCNError):boolean=} error Optional custom error 169 * handler. 170 */ 171 pages: function (success, error) { 172 this._getItems('page', success, error); 173 }, 174 175 /** 176 * Creates a new page inside this folder. 177 * 178 * @param {number} templateId The id of the template to be used for 179 * the page. 180 * @param {object} options Set all the options to create a page the 181 * following options are allowed: 182 * <pre> 183 * GCN.folder(4711).createPage(13, { 184 * // set a language code for the new page like 'en', 'de', ... 185 * // if you don't supply a language code the page will have 186 * // no language assigned 187 * language: 'en', 188 * // id of the page this page should be a variant of 189 * variantId: 42 190 * }); 191 * </pre> 192 * @param {function(PageAPI)=} success Optional callback that will 193 * receive a {@link PageAPI} object 194 * as its only argument. 195 * @param {function(GCNError):boolean=} error Optional custom error 196 * handler. 197 * @return {PageAPI} The newly created page. 198 */ 199 createPage: function () { 200 var args = Array.prototype.slice.call(arguments); 201 var templateId = args[0]; 202 var options; 203 var success; 204 var error; 205 var j = args.length; 206 var i; 207 208 // Determine `options', `success', `error' 209 for (i = 1; i < j; ++i) { 210 switch (jQuery.type(args[i])) { 211 case 'function': 212 if (success) { 213 error = args[i]; 214 } else { 215 success = args[i]; 216 } 217 break; 218 case 'object': 219 options = args[i]; 220 break; 221 } 222 } 223 224 var that = this; 225 var page = that._continue(GCN.PageAPI)._procure(); 226 227 this._read(function () { 228 if (!options) { 229 options = {}; 230 } 231 232 // default settings 233 options.folderId = that.id(); 234 options.templateId = templateId; 235 236 that._authAjax({ 237 url : GCN.settings.BACKEND_PATH + '/rest/page/create/', 238 type : 'POST', 239 json : options, 240 error : function (xhr, status, msg) { 241 GCN.handleHttpError(xhr, msg, error); 242 }, 243 success : function (response) { 244 if (GCN.getResponseCode(response) === 'OK') { 245 var data = response.page; 246 247 page._data = data; 248 page._fetched = true; 249 250 if (success) { 251 success(page); 252 } 253 } else { 254 page._die(GCN.getResponseCode(response)); 255 GCN.handleResponseError(response, error); 256 } 257 258 // Halt the call chain until this object has been fully 259 // realized. 260 page._vacate(); 261 } 262 }, error); 263 }, error); 264 }, 265 266 // ==================================================================== 267 // Templates 268 // ==================================================================== 269 270 // '!template': function (id, success, error) { 271 // return this._continue(GCN.TemplateAPI, id, success, error); 272 // }, 273 // 274 // '!templates': function (ids, success, error) { 275 // //FIXME: Not implemented 276 // }, 277 // 278 // createTemplate: function (settings, success, error) { 279 // //FIXME: Not implemented 280 // }, 281 282 /** 283 * Retreive a list of all files in this folder. 284 * 285 * @param {function(Array.FileAPI)=} success Optional callback that 286 * will receive an array of 287 * {@link FileAPI} objects as 288 * its only argument. 289 * @param {function(GCNError):boolean=} error Optional custom error 290 * handler. 291 */ 292 files: function (success, error) { 293 this._getItems('file', success, error); 294 }, 295 296 /** 297 * Retreive a list of all images in this folder. 298 * 299 * @param {function(Array.ImageAPI)=} success Optional callback that 300 * will receive an array of 301 * {@link ImageAPI} objects 302 * as its only argument. 303 * @param {function(GCNError):boolean=} error Optional custom error 304 * handler. 305 */ 306 images: function (success, error) { 307 this._getItems('image', success, error); 308 }, 309 310 // ==================================================================== 311 // Folders 312 // ==================================================================== 313 314 /** 315 * @override 316 * @see ContentObjectAPI._loadParams 317 */ 318 '!_loadParams': function () { 319 // Folder will be loaded including the privileges information 320 if (DEFAULT_SETTINGS.loadFolderPrivileges === true) { 321 return { privileges: true }; 322 } 323 324 return {}; 325 }, 326 327 /** 328 * @FIXME(petro) Why on do we need this method inside FolderAPI? 329 */ 330 '!folder': function (id, success, error) { 331 return this._continue(GCN.FolderAPI, id, success, error); 332 }, 333 334 /** 335 * Retreive a list of all sub folders of this folder. 336 * 337 * @param {function(Array.FolderAPI)=} success Optional callback that 338 * will receive an array of 339 * {@link FolderAPI} 340 * objects as its only 341 * argument. 342 * @param {function(GCNError):boolean=} error Optional custom error 343 * handler. 344 */ 345 folders: function (success, error) { 346 this._getItems('folder', success, error); 347 }, 348 349 /** 350 * Create a sub folder within this folder, with the option of also 351 * automatically creating a startpage for this folder. 352 * 353 * @param {string} name the folder name 354 * @param {object} settings pass in an optional settings object 355 * possible options are: 356 * <pre> 357 * { 358 * // optional description for the folder 359 * description: 'this is my folder', 360 * // set a publish directory for the folder 361 * publishDir: '/this/is/my/folder/', 362 * // adding a template id will automatically create a new 363 * // startpage for the folder 364 * templateId: 5, 365 * // provide a language code for the start page. optional. 366 * language: 'en', 367 * // when true creating the folder will fail if a folder with 368 * // that name exists. otherwise conflicting names will be 369 * // postfixed with an increasing number. defaults to false. 370 * failOnDuplicate: false 371 * } 372 * </pre> 373 * @param {function(FolderAPI)=} success Optional callback that 374 * will receive a 375 * {@link FolderAPI} object as 376 * its only argument. 377 * @param {function(GCNError):boolean=} error Optional custom error 378 * handler. 379 * @throws UNKNOWN_ARGUMENT Thrown when unexpected arguments are 380 * provided. 381 */ 382 createFolder: function () { 383 var that = this; 384 var success; 385 var error; 386 var settings; 387 var name; 388 var i; 389 var j = arguments.length; 390 391 // parse arguments 392 for (i = 0; i < j; ++i) { 393 switch (jQuery.type(arguments[i])) { 394 case 'function': 395 if (!success) { 396 success = arguments[i]; 397 } else if (success && !error) { 398 error = arguments[i]; 399 } else { 400 GCN.error('UNKNOWN_ARGUMENT', 401 'success and error handler already set. Don\'t ' + 402 'know what to do with arguments[' + i + ']'); 403 } 404 break; 405 case 'object': 406 if (!settings) { 407 settings = arguments[i]; 408 } else { 409 GCN.error('UNKNOWN_ARGUMENT', 410 'settings already set. Don\'t know what to do ' + 411 'with arguments[' + i + '] value ' + arguments[i]); 412 } 413 break; 414 case 'string': 415 if (!name) { 416 name = arguments[i]; 417 } else { 418 GCN.error('UNKNOWN_ARGUMENT', 419 'name already set. Don\'t know what to do with ' + 420 'arguments[' + i + '] value ' + arguments[i]); 421 } 422 break; 423 default: 424 GCN.error('UNKNOWN_ARGUMENT', 425 'Don\'t know what to do with arguments[' + i + '] ' + 426 'value ' + arguments[i]); 427 } 428 } 429 430 // initialize basic settings object 431 if (!settings) { 432 settings = {}; 433 } 434 435 // set default parameters 436 settings.name = name; 437 settings.motherId = this._data.id; 438 439 // automatically enable startpage generation if a template is set 440 if (settings.templateId) { 441 settings.startpage = true; 442 } 443 444 this._authAjax({ 445 url : GCN.settings.BACKEND_PATH + '/rest/folder/create/', 446 type : 'POST', 447 error : error, 448 json : settings, 449 success : function (response) { 450 that._continue(GCN.FolderAPI, response.folder, success, 451 error); 452 } 453 }); 454 }, 455 456 /** 457 * Get a URL for uploading files into this folder. 458 * 459 * @public 460 * @name uploadURL 461 * @memberOf FolderAPI 462 * @return {string} Rest API url for file uploading. 463 */ 464 '!uploadURL': function () { 465 return GCN.settings.BACKEND_PATH + 466 '/rest/file/createSimple.json?sid=' + GCN.sid + 467 '&folderId=' + this.id(); 468 }, 469 470 /** 471 * This method will inspect the json and decide whether the onSuccess 472 * or onError should be called. A file or image api object will be 473 * passed to the success handler. 474 * @TODO(petro): The success callback should not receive a second 475 * argument containing messages. It is not consitanct 476 * with out API. 477 * 478 * @public 479 * @name handleUploadResponse 480 * @memberOf FolderAPI 481 * @param {object} response The REST-API reponse object that was given 482 * in response to the upload request. 483 * @param {function(FileAPI, Array.string)=} success Optional callback 484 * that will receive 485 * as its first 486 * argument, a 487 * {@link FileAPI} 488 * object of the 489 * uploaded file. The 490 * second argument is 491 * an array of 492 * message strings 493 * returned in 494 * response to the 495 * upload request. 496 * @param {function(GCNError):boolean=} error Optional custom error 497 * handler. 498 */ 499 '!handleUploadResponse': function (response, success, error) { 500 if (GCN.getResponseCode(response) === 'OK') { 501 if (success) { 502 GCN.file(response.file, function (file) { 503 success(file, response.messages); 504 }, error); 505 } 506 } else { 507 GCN.handleResponseError(response, error); 508 } 509 }, 510 511 /** 512 * Fetch items inside this folder. 513 * 514 * @param {string} type One of: "file" 515 * "folder" 516 * "page" 517 * "image" 518 * "template" 519 * @param {function(Array.<ContentObjectAPI>)} success Callback that 520 * will receive an array 521 * of the requested items. 522 * @param {function(GCNError):boolean=} success Custom error handler. 523 */ 524 '!_getItems': function (type, success, error) { 525 var that = this; 526 527 if (!this._fetched) { 528 this._read(function () { 529 that._getItems(type, success, error); 530 }, error); 531 532 return; 533 } 534 535 var api; 536 var url = GCN.settings.BACKEND_PATH + '/rest/' + this._type + 537 '/getItems/' + this.id() + '?type=' + type; 538 539 switch (type) { 540 case 'page': 541 api = GCN.PageAPI; 542 break; 543 case 'file': 544 api = GCN.FileAPI; 545 break; 546 case 'image': 547 api = GCN.ImageAPI; 548 break; 549 case 'folder': 550 api = GCN.FolderAPI; 551 url = GCN.settings.BACKEND_PATH + '/rest/' + this._type + 552 '/getFolders/' + this.id(); 553 break; 554 default: 555 var err = GCN.createError('UNEXPECTED_TYPE', 556 'Unknown object type ' + type, this); 557 558 GCN.handleError(err, error); 559 return; 560 } 561 562 this._authAjax({ 563 url : url, 564 type : 'GET', 565 error : error, 566 success : function (response) { 567 var items = []; 568 var i; 569 var j = response.numItems; 570 571 for (i = 0; i < j; i++) { 572 items.push(that._continue(api, 573 (type === 'folder') ? response.folders[i] : 574 response.items[i], 575 null, error)); 576 } 577 578 success(items); 579 } 580 }); 581 } 582 583 }); 584 585 GCN.folder = GCN.exposeAPI(FolderAPI); 586 GCN.FolderAPI = FolderAPI; 587 588 }(GCN)); 589