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 * Get this content object's node. 141 * 142 * @override 143 * @param {funtion(NodeAPI)=} success Optional callback to receive a 144 * {@link NodeAPI} object as the 145 * only argument. 146 * @param {function(GCNError):boolean=} error Optional custom error 147 * handler. 148 * @return {NodeAPI} This object's node. 149 */ 150 '!node': function (success, error) { 151 return this._continue(GCN.NodeAPI, null, success, error); 152 }, 153 154 // ==================================================================== 155 // Pages 156 // ==================================================================== 157 158 /** 159 * Returns page of the given id which resides in this folder. 160 * 161 * @public 162 * @name page 163 * @memberOf FolderAPI 164 * @param {number} id 165 * @param {function(PageAPI)=} success Optional callback that will 166 * receive a {@link PageAPI} object 167 * as its only argument. 168 * @param {function(GCNError):boolean=} error Optional custom error 169 * handler. 170 * @return {PageAPI} 171 */ 172 '!page': function (id, success, error) { 173 return this._continue(GCN.PageAPI, id, success, error); 174 }, 175 176 /** 177 * Retreive a list of all pages this folder. 178 * 179 * @param {function(Array.PageAPI)=} success Optional callback that 180 * will receive an array of 181 * {@link PageAPI} objects as 182 * its only argument. 183 * @param {function(GCNError):boolean=} error Optional custom error 184 * handler. 185 */ 186 pages: function (success, error) { 187 this._getItems('page', success, error); 188 }, 189 190 /** 191 * Creates a new page inside this folder. 192 * 193 * @param {number} templateId The id of the template to be used for 194 * the page. 195 * @param {object} options Set all the options to create a page the 196 * following options are allowed: 197 * <pre> 198 * GCN.folder(4711).createPage(13, { 199 * // set a language code for the new page like 'en', 'de', ... 200 * // if you don't supply a language code the page will have 201 * // no language assigned 202 * language: 'en', 203 * // id of the page this page should be a variant of 204 * variantId: 42 205 * }); 206 * </pre> 207 * @param {function(PageAPI)=} success Optional callback that will 208 * receive a {@link PageAPI} object 209 * as its only argument. 210 * @param {function(GCNError):boolean=} error Optional custom error 211 * handler. 212 * @return {PageAPI} The newly created page. 213 */ 214 createPage: function () { 215 var args = Array.prototype.slice.call(arguments); 216 var templateId = args[0]; 217 var options; 218 var success; 219 var error; 220 var j = args.length; 221 var i; 222 223 // Determine `options', `success', `error' 224 for (i = 1; i < j; ++i) { 225 switch (jQuery.type(args[i])) { 226 case 'function': 227 if (success) { 228 error = args[i]; 229 } else { 230 success = args[i]; 231 } 232 break; 233 case 'object': 234 options = args[i]; 235 break; 236 } 237 } 238 239 var that = this; 240 var page = that._continue(GCN.PageAPI)._procure(); 241 242 this._read(function () { 243 if (!options) { 244 options = {}; 245 } 246 247 // default settings 248 options.folderId = that.id(); 249 options.templateId = templateId; 250 251 that._authAjax({ 252 url : GCN.settings.BACKEND_PATH + '/rest/page/create/', 253 type : 'POST', 254 json : options, 255 error : function (xhr, status, msg) { 256 GCN.handleHttpError(xhr, msg, error); 257 }, 258 success : function (response) { 259 if (GCN.getResponseCode(response) === 'OK') { 260 var data = response.page; 261 262 page._data = data; 263 page._fetched = true; 264 265 if (success) { 266 that._invoke(success, [page]); 267 } 268 } else { 269 page._die(GCN.getResponseCode(response)); 270 GCN.handleResponseError(response, error); 271 } 272 273 // Halt the call chain until this object has been fully 274 // realized. 275 page._vacate(); 276 } 277 }, error); 278 }, error); 279 }, 280 281 // ==================================================================== 282 // Templates 283 // ==================================================================== 284 285 // '!template': function (id, success, error) { 286 // return this._continue(GCN.TemplateAPI, id, success, error); 287 // }, 288 // 289 // '!templates': function (ids, success, error) { 290 // //FIXME: Not implemented 291 // }, 292 // 293 // createTemplate: function (settings, success, error) { 294 // //FIXME: Not implemented 295 // }, 296 297 /** 298 * Retreive a list of all files in this folder. 299 * 300 * @param {function(Array.FileAPI)=} success Optional callback that 301 * will receive an array of 302 * {@link FileAPI} objects as 303 * its only argument. 304 * @param {function(GCNError):boolean=} error Optional custom error 305 * handler. 306 */ 307 files: function (success, error) { 308 this._getItems('file', success, error); 309 }, 310 311 /** 312 * Retreive a list of all images in this folder. 313 * 314 * @param {function(Array.ImageAPI)=} success Optional callback that 315 * will receive an array of 316 * {@link ImageAPI} objects 317 * as its only argument. 318 * @param {function(GCNError):boolean=} error Optional custom error 319 * handler. 320 */ 321 images: function (success, error) { 322 this._getItems('image', success, error); 323 }, 324 325 // ==================================================================== 326 // Folders 327 // ==================================================================== 328 329 /** 330 * @override 331 * @see ContentObjectAPI._loadParams 332 */ 333 '!_loadParams': function () { 334 // Folder will be loaded including the privileges information 335 if (DEFAULT_SETTINGS.loadFolderPrivileges === true) { 336 return { privileges: true }; 337 } 338 339 return {}; 340 }, 341 342 /** 343 * @FIXME(petro) Why on do we need this method inside FolderAPI? 344 */ 345 '!folder': function (id, success, error) { 346 return this._continue(GCN.FolderAPI, id, success, error); 347 }, 348 349 /** 350 * Retreive a list of all sub folders of this folder. 351 * 352 * @param {function(Array.FolderAPI)=} success Optional callback that 353 * will receive an array of 354 * {@link FolderAPI} 355 * objects as its only 356 * argument. 357 * @param {function(GCNError):boolean=} error Optional custom error 358 * handler. 359 */ 360 folders: function (success, error) { 361 this._getItems('folder', success, error); 362 }, 363 364 /** 365 * Create a sub folder within this folder, with the option of also 366 * automatically creating a startpage for this folder. 367 * 368 * @param {string} name the folder name 369 * @param {object} settings pass in an optional settings object 370 * possible options are: 371 * <pre> 372 * { 373 * // optional description for the folder 374 * description: 'this is my folder', 375 * // set a publish directory for the folder 376 * publishDir: '/this/is/my/folder/', 377 * // adding a template id will automatically create a new 378 * // startpage for the folder 379 * templateId: 5, 380 * // provide a language code for the start page. optional. 381 * language: 'en', 382 * // when true creating the folder will fail if a folder with 383 * // that name exists. otherwise conflicting names will be 384 * // postfixed with an increasing number. defaults to false. 385 * failOnDuplicate: false 386 * } 387 * </pre> 388 * @param {function(FolderAPI)=} success Optional callback that 389 * will receive a 390 * {@link FolderAPI} object as 391 * its only argument. 392 * @param {function(GCNError):boolean=} error Optional custom error 393 * handler. 394 * @throws UNKNOWN_ARGUMENT Thrown when unexpected arguments are 395 * provided. 396 */ 397 createFolder: function () { 398 var that = this; 399 var success; 400 var error; 401 var settings; 402 var name; 403 var i; 404 var j = arguments.length; 405 406 // parse arguments 407 for (i = 0; i < j; ++i) { 408 switch (jQuery.type(arguments[i])) { 409 case 'function': 410 if (!success) { 411 success = arguments[i]; 412 } else if (success && !error) { 413 error = arguments[i]; 414 } else { 415 GCN.error('UNKNOWN_ARGUMENT', 416 'success and error handler already set. Don\'t ' + 417 'know what to do with arguments[' + i + ']'); 418 } 419 break; 420 case 'object': 421 if (!settings) { 422 settings = arguments[i]; 423 } else { 424 GCN.error('UNKNOWN_ARGUMENT', 425 'settings already set. Don\'t know what to do ' + 426 'with arguments[' + i + '] value ' + arguments[i]); 427 } 428 break; 429 case 'string': 430 if (!name) { 431 name = arguments[i]; 432 } else { 433 GCN.error('UNKNOWN_ARGUMENT', 434 'name already set. Don\'t know what to do with ' + 435 'arguments[' + i + '] value ' + arguments[i]); 436 } 437 break; 438 default: 439 GCN.error('UNKNOWN_ARGUMENT', 440 'Don\'t know what to do with arguments[' + i + '] ' + 441 'value ' + arguments[i]); 442 } 443 } 444 445 // initialize basic settings object 446 if (!settings) { 447 settings = {}; 448 } 449 450 // set default parameters 451 settings.name = name; 452 settings.motherId = this._data.id; 453 454 // automatically enable startpage generation if a template is set 455 if (settings.templateId) { 456 settings.startpage = true; 457 } 458 459 this._authAjax({ 460 url : GCN.settings.BACKEND_PATH + '/rest/folder/create/', 461 type : 'POST', 462 error : error, 463 json : settings, 464 success : function (response) { 465 that._continue(GCN.FolderAPI, response.folder, success, 466 error); 467 } 468 }); 469 }, 470 471 /** 472 * Get a URL for uploading files into this folder. 473 * 474 * @public 475 * @name uploadURL 476 * @memberOf FolderAPI 477 * @return {string} Rest API url for file uploading. 478 */ 479 '!uploadURL': function () { 480 return GCN.settings.BACKEND_PATH + 481 '/rest/file/createSimple.json?sid=' + GCN.sid + 482 '&folderId=' + this.id(); 483 }, 484 485 /** 486 * This method will inspect the json and decide whether the onSuccess 487 * or onError should be called. A file or image api object will be 488 * passed to the success handler. 489 * @TODO(petro): The success callback should not receive a second 490 * argument containing messages. It is not consitanct 491 * with out API. 492 * 493 * @public 494 * @name handleUploadResponse 495 * @memberOf FolderAPI 496 * @param {object} response The REST-API reponse object that was given 497 * in response to the upload request. 498 * @param {function(FileAPI, Array.string)=} success Optional callback 499 * that will receive 500 * as its first 501 * argument, a 502 * {@link FileAPI} 503 * object of the 504 * uploaded file. The 505 * second argument is 506 * an array of 507 * message strings 508 * returned in 509 * response to the 510 * upload request. 511 * @param {function(GCNError):boolean=} error Optional custom error 512 * handler. 513 */ 514 '!handleUploadResponse': function (response, success, error) { 515 if (GCN.getResponseCode(response) === 'OK') { 516 if (success) { 517 var that = this; 518 GCN.file(response.file, function (file) { 519 that._invoke(success, [file, response.messages]); 520 }, error); 521 } 522 } else { 523 GCN.handleResponseError(response, error); 524 } 525 }, 526 527 /** 528 * Fetch items inside this folder. 529 * 530 * @param {string} type One of: "file" 531 * "folder" 532 * "page" 533 * "image" 534 * "template" 535 * @param {function(Array.<ContentObjectAPI>)} success Callback that 536 * will receive an array 537 * of the requested items. 538 * @param {function(GCNError):boolean=} success Custom error handler. 539 */ 540 '!_getItems': function (type, success, error) { 541 var that = this; 542 543 if (!this._fetched) { 544 this._read(function () { 545 that._getItems(type, success, error); 546 }, error); 547 548 return; 549 } 550 551 var api; 552 var url = GCN.settings.BACKEND_PATH + '/rest/' + this._type + 553 '/getItems/' + this.id() + '?type=' + type; 554 555 switch (type) { 556 case 'page': 557 api = GCN.PageAPI; 558 break; 559 case 'file': 560 api = GCN.FileAPI; 561 break; 562 case 'image': 563 api = GCN.ImageAPI; 564 break; 565 case 'folder': 566 api = GCN.FolderAPI; 567 url = GCN.settings.BACKEND_PATH + '/rest/' + this._type + 568 '/getFolders/' + this.id(); 569 break; 570 default: 571 var err = GCN.createError('UNEXPECTED_TYPE', 572 'Unknown object type ' + type, this); 573 574 GCN.handleError(err, error); 575 return; 576 } 577 578 this._authAjax({ 579 url : url, 580 type : 'GET', 581 error : error, 582 success : function (response) { 583 var items = []; 584 var i; 585 var j = response.numItems; 586 587 for (i = 0; i < j; i++) { 588 items.push(that._continue(api, 589 (type === 'folder') ? response.folders[i] : 590 response.items[i], 591 null, error)); 592 } 593 594 that._invoke(success, [items]); 595 } 596 }); 597 } 598 599 }); 600 601 GCN.folder = GCN.exposeAPI(FolderAPI); 602 GCN.FolderAPI = FolderAPI; 603 604 }(GCN)); 605