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