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