1 /** 2 * Copyright (C) 2005-2010 Alfresco Software Limited. 3 * 4 * This file is part of Alfresco 5 * 6 * Alfresco is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Alfresco is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * BlogPostEdit component. 22 * 23 * Component provides blog post creation/edit functionality. 24 * 25 * @namespace Alfresco 26 * @class Alfresco.BlogPostEdit 27 */ 28 (function() 29 { 30 /** 31 * YUI Library aliases 32 */ 33 var Dom = YAHOO.util.Dom; 34 35 /** 36 * BlogPostEdit constructor. 37 * 38 * @param {String} htmlId The HTML id of the parent element 39 * @return {Alfresco.BlogPostEdit} The new Post instance 40 * @constructor 41 */ 42 Alfresco.BlogPostEdit = function(htmlId) 43 { 44 Alfresco.BlogPostEdit.superclass.constructor.call(this, "Alfresco.BlogPostEdit", htmlId, ["button", "menu", "json"]); 45 46 // Initialise prototype properties 47 this.blogPostData = null; 48 this.performExternalPublish = false; 49 50 return this; 51 }; 52 53 YAHOO.extend(Alfresco.BlogPostEdit, Alfresco.component.Base, 54 { 55 /** 56 * Object container for initialization options 57 * 58 * @property options 59 * @type object 60 */ 61 options: 62 { 63 /** 64 * Current siteId. 65 * 66 * @property siteId 67 * @type string 68 */ 69 siteId: "", 70 71 /** 72 * ContainerId representing root container 73 * 74 * @property containerId 75 * @type string 76 * @default "blog" 77 */ 78 containerId: "blog", 79 80 /** 81 * True if the component should be in edit mode. 82 * 83 * @property editMode 84 * @type boolean 85 * @default: false 86 */ 87 editMode: false, 88 89 /** 90 * Id of the post to edit. Only relevant if editMode is true 91 * 92 * @property postId 93 * @type string 94 * @default: "" 95 */ 96 postId: "" 97 }, 98 99 /** 100 * Stores the data of the currently edited blog post 101 */ 102 blogPostData: null, 103 104 /** 105 * If true, an external publish/update will be executed after the post has been 106 * saved/updated. 107 */ 108 performExternalPublish: null, 109 110 /** 111 * Fired by YUI when parent element is available for scripting. 112 * Component initialisation, including instantiation of YUI widgets and event listener binding. 113 * 114 * @method onReady 115 */ 116 onReady: function BlogPostEdit_onReady() 117 { 118 if (this.options.editMode) 119 { 120 // load the blog post data prior to initializing the form 121 this._loadBlogPostData(); 122 } 123 else 124 { 125 // directly initialize the form 126 this._initializeBlogPostForm(); 127 } 128 }, 129 130 /** 131 * Loads the comments for the provided nodeRef and refreshes the ui 132 * 133 * @method _loadBlogPostData 134 * @private 135 */ 136 _loadBlogPostData: function BlogPostEdit__loadBlogPostData() 137 { 138 // ajax request success handler 139 var me = this; 140 var loadBlogPostDataSuccess = function BlogPostEdit__loadBlogPostData(response) 141 { 142 // set the blog data 143 var data = response.json.item; 144 me.blogPostData = data; 145 146 // now initialize the form, which will use the data we just loaded 147 me._initializeBlogPostForm(); 148 }; 149 150 // construct the request url 151 var url = YAHOO.lang.substitute(Alfresco.constants.URL_SERVICECONTEXT + "components/blog/post/site/{site}/{container}/{postId}", 152 { 153 site : this.options.siteId, 154 container: this.options.containerId, 155 postId: this.options.postId 156 }); 157 158 // execute ajax request 159 Alfresco.util.Ajax.request( 160 { 161 url: url, 162 method: "GET", 163 responseContentType: "application/json", 164 successCallback: 165 { 166 fn: loadBlogPostDataSuccess, 167 scope: this 168 }, 169 failureMessage: this.msg("message.loadpostdata.failure") 170 }); 171 }, 172 173 /** 174 * Initializes the blog post form with create/edit dependent data. 175 * 176 * @method _initializeBlogPostForm 177 * @private 178 */ 179 _initializeBlogPostForm: function BlogPostEdit__initializeBlogPostForm() 180 { 181 // construct the actionUrl, which is different for creating/updating a post 182 var actionUrl, draft = true, title = "", content = ""; 183 if (this.options.editMode) 184 { 185 actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "api/blog/post/node/{nodeRef}", 186 { 187 nodeRef: this.blogPostData.nodeRef.replace(":/", "") 188 }); 189 } 190 else 191 { 192 actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "api/blog/site/{site}/{container}/posts", 193 { 194 site: this.options.siteId, 195 container: this.options.containerId 196 }); 197 } 198 Dom.get(this.id + "-form").setAttribute("action", actionUrl); 199 200 // site and container 201 Dom.get(this.id + "-site").setAttribute("value", this.options.siteId); 202 Dom.get(this.id + "-container").setAttribute("value", this.options.containerId); 203 204 // draft 205 if (this.options.editMode) 206 { 207 draft = this.blogPostData.isDraft; 208 } 209 Dom.get(this.id + "-draft").setAttribute("value", draft); 210 211 // title 212 if (this.options.editMode) 213 { 214 title = this.blogPostData.title; 215 } 216 Dom.get(this.id + "-title").setAttribute("value", title); 217 218 // content 219 if (this.options.editMode) 220 { 221 content = this.blogPostData.content; 222 } 223 Dom.get(this.id + "-content").value = content; 224 225 // register the behaviour with the form and display the form 226 this._registerBlogPostForm(); 227 }, 228 229 /** 230 * Registers the form logic 231 * 232 * @method _registerBlogPostForm 233 * @private 234 */ 235 _registerBlogPostForm: function BlogPostEdit__registerBlogPostForm() 236 { 237 // initialize the tag library 238 this.modules.tagLibrary = new Alfresco.module.TagLibrary(this.id); 239 this.modules.tagLibrary.setOptions( 240 { 241 siteId: this.options.siteId 242 }); 243 244 // add the tags that are already set on the post 245 if (this.options.editMode && this.blogPostData.tags.length > 0) 246 { 247 this.modules.tagLibrary.setTags(this.blogPostData.tags); 248 } 249 250 // create the Button 251 this.widgets.saveButton = new YAHOO.widget.Button(this.id + "-save-button", 252 { 253 type: "submit", 254 label: this.msg(this.options.editMode ? "action.update" : "action.saveAsDraft") 255 }); 256 257 // publishing of a draft post button - only visible if post is a draft 258 if (!this.options.editMode || this.blogPostData.isDraft) 259 { 260 this.widgets.publishButton = Alfresco.util.createYUIButton(this, "publish-button", this.onFormPublishButtonClick); 261 Dom.removeClass(this.id + "-publish-button", "hidden"); 262 } 263 264 // publishing internal and external button / update internal and publish external 265 var publishExternalButtonLabel = ""; 266 if (!this.options.editMode) 267 { 268 publishExternalButtonLabel = this.msg("action.publishIntAndExt"); 269 } 270 else if (this.blogPostData.isPublished) 271 { 272 publishExternalButtonLabel = this.msg("action.updateIntAndExt"); 273 } 274 else 275 { 276 publishExternalButtonLabel = this.msg("action.updateIntAndPublishExt"); 277 } 278 this.widgets.publishExternalButton = Alfresco.util.createYUIButton(this, "publishexternal-button", this.onFormPublishExternalButtonClick, 279 { 280 label: publishExternalButtonLabel 281 }); 282 283 // Cancel button 284 this.widgets.cancelButton = Alfresco.util.createYUIButton(this, "cancel-button", this.onFormCancelButtonClick); 285 286 // Instantiate the simple editor we use for the form 287 this.widgets.editor = new Alfresco.util.RichEditor(Alfresco.constants.HTML_EDITOR, this.id + "-content", this.options.editorConfig); 288 this.widgets.editor.addPageUnloadBehaviour(this.msg("message.unsavedChanges.blog")); 289 this.widgets.editor.render(); 290 291 // Add validation to the rich text editor 292 this.widgets.validateOnZero = 0; 293 var keyUpIdentifier = (Alfresco.constants.HTML_EDITOR === "YAHOO.widget.SimpleEditor") ? "editorKeyUp" : "onKeyUp"; 294 this.widgets.editor.subscribe(keyUpIdentifier, function (e) 295 { 296 this.widgets.validateOnZero++; 297 YAHOO.lang.later(1000, this, this.validateAfterEditorChange); 298 }, this, true); 299 300 // Create the form that does the validation/submit 301 this.widgets.postForm = new Alfresco.forms.Form(this.id + "-form"); 302 303 // Title is mandatory 304 this.widgets.postForm.addValidation(this.id + "-title", Alfresco.forms.validation.mandatory, null, "blur"); 305 this.widgets.postForm.addValidation(this.id + "-title", Alfresco.forms.validation.length, 306 { 307 max: 256, 308 crop: true 309 }, "keyup"); 310 311 // Text is mandatory 312 this.widgets.postForm.addValidation(this.id + "-content", Alfresco.forms.validation.mandatory, null); 313 314 this.widgets.postForm.setShowSubmitStateDynamically(true, false); 315 if (this.widgets.publishButton) 316 { 317 this.widgets.postForm.setSubmitElements([this.widgets.saveButton, this.widgets.publishExternalButton, this.widgets.publishButton]); 318 } 319 else 320 { 321 this.widgets.postForm.setSubmitElements([this.widgets.saveButton, this.widgets.publishExternalButton]); 322 } 323 this.widgets.postForm.setAJAXSubmit(true, 324 { 325 successCallback: 326 { 327 fn: this.onFormSubmitSuccess, 328 scope: this 329 }, 330 failureMessage: this.msg("message.savepost.failure"), 331 failureCallback: 332 { 333 fn: this.onFormSubmitFailure, 334 scope: this 335 } 336 }); 337 if (this.options.editMode) 338 { 339 this.widgets.postForm.setAjaxSubmitMethod(Alfresco.util.Ajax.PUT); 340 } 341 this.widgets.postForm.setSubmitAsJSON(true); 342 this.widgets.postForm.doBeforeFormSubmit = 343 { 344 fn: function(form, obj) 345 { 346 //Put the HTML back into the text area 347 this.widgets.editor.save(); 348 349 // Make sure the user has written a text 350 if (Dom.get(this.id + "-content").value.length === 0) 351 { 352 Alfresco.util.PopupManager.displayMessage( 353 { 354 text: Alfresco.util.message("message.noText", this.name) 355 }); 356 return; 357 } 358 359 // disable ui elements 360 this.widgets.saveButton.set("disabled", true); 361 if (this.widgets.publishButton) 362 { 363 this.widgets.publishButton.set("disabled", true); 364 } 365 this.widgets.publishExternalButton.set("disabled", true); 366 this.widgets.cancelButton.set("disabled", true); 367 368 // update the tags set in the form 369 this.modules.tagLibrary.updateForm(this.id + "-form", "tags"); 370 371 // show a wait message 372 this.widgets.feedbackMessage = Alfresco.util.PopupManager.displayMessage( 373 { 374 text: Alfresco.util.message(this.msg("message.submitting")), 375 spanClass: "wait", 376 displayTime: 0 377 }); 378 }, 379 scope: this 380 }; 381 this.modules.tagLibrary.initialize(this.widgets.postForm); 382 this.widgets.postForm.init(); 383 384 // finally display the form 385 Dom.removeClass(this.id + "-div", "hidden"); 386 Dom.get(this.id + "-title").focus(); 387 }, 388 389 /** 390 * Called when a key was pressed in the rich text editor. 391 * Will trigger form validation after the last key stroke after a seconds pause. 392 * 393 * @method validateAfterEditorChange 394 */ 395 validateAfterEditorChange: function BlogPostEdit_validateAfterEditorChange() 396 { 397 this.widgets.validateOnZero--; 398 if (this.widgets.validateOnZero === 0) 399 { 400 var oldLength = Dom.get(this.id + "-content").value.length; 401 this.widgets.editor.save(); 402 var newLength = Dom.get(this.id + "-content").value.length; 403 if ((oldLength === 0 && newLength !== 0) || (oldLength > 0 && newLength === 0)) 404 { 405 this.widgets.postForm.updateSubmitElements(); 406 } 407 } 408 }, 409 410 /** 411 * Publish button click handler 412 * 413 * @method onFormPublishButtonClick 414 */ 415 onFormPublishButtonClick: function BlogPostEdit_onFormPublishButtonClick(type, args) 416 { 417 // make sure we set the draft flag to false 418 Dom.get(this.id + "-draft").setAttribute("value", false); 419 420 // submit the form 421 this.widgets.saveButton.fireEvent("click", 422 { 423 type: "click" 424 }); 425 }, 426 427 /** 428 * Publish external button click handler 429 * 430 * @method onFormPublishExternalButtonClick 431 */ 432 onFormPublishExternalButtonClick: function BlogPostEdit_onFormPublishExternalButtonClick(type, args) 433 { 434 // make sure we set the draft flag to false 435 Dom.get(this.id + "-draft").setAttribute("value", false); 436 437 // make sure that the post gets also externally published 438 this.performExternalPublish = true; 439 440 // submit the form 441 this.widgets.saveButton.fireEvent("click", 442 { 443 type: "click" 444 }); 445 }, 446 447 /** 448 * Cancel button click handler 449 * 450 * @method onFormCancelButtonClick 451 */ 452 onFormCancelButtonClick: function BlogPostEdit_onFormCancelButtonClick(type, args) 453 { 454 // redirect to the page we came from 455 history.go(-1); 456 }, 457 458 /** 459 * Form submit success handler 460 * 461 * @method onFormSubmitSuccess 462 */ 463 onFormSubmitSuccess: function BlogPostEdit_onFormSubmitSuccess(response) 464 { 465 // hide the wait message 466 this.widgets.feedbackMessage.destroy(); 467 468 // check whether we have to do an external publich 469 if (this.performExternalPublish) 470 { 471 // show a new wait message 472 this.widgets.feedbackMessage = Alfresco.util.PopupManager.displayMessage( 473 { 474 text: Alfresco.util.message(this.msg("message.postSavedNowPublish")), 475 spanClass: "wait", 476 displayTime: 0 477 }); 478 479 //var nodeRef = response.json.item.nodeRef; 480 var postId = response.json.item.name; 481 if (response.json.item.isPublished) 482 { 483 // perform an update 484 this.onUpdateExternal(postId); 485 } 486 else 487 { 488 // perform a publish 489 this.onPublishExternal(postId); 490 } 491 } 492 else 493 { 494 Alfresco.util.PopupManager.displayMessage( 495 { 496 text: this.msg("message.savepost.success") 497 }); 498 this._loadPostViewPage(response.json.item.name); 499 } 500 }, 501 502 /** 503 * Reenables the inputs which got disabled as part of a comment submit 504 * 505 * @method onFormSubmitFailure 506 */ 507 onFormSubmitFailure: function BlogPostEdit_onFormSubmitFailure() 508 { 509 // enable the buttons 510 this.widgets.saveButton.set("disabled", false); 511 if (this.widgets.publishButton) 512 { 513 this.widgets.publishButton.set("disabled", false); 514 } 515 this.widgets.publishExternalButton.set("disabled", false); 516 this.widgets.cancelButton.set("disabled", false); 517 518 // hide the wait message 519 this.widgets.feedbackMessage.destroy(); 520 }, 521 522 /** 523 * Publishes the blog post to an external blog. 524 * 525 * @method onPublishExternal 526 */ 527 onPublishExternal: function BlogPostEdit_onPublishExternal(postId) 528 { 529 // publish request success handler 530 var onPublished = function BlogPostEdit_onPublished(response) 531 { 532 this._loadPostViewPage(postId); 533 }; 534 535 // publish request failure handler 536 var onPublishFailed = function BlogPostEdit_onPublishFailed(response) 537 { 538 // let the user know that the publish failed, then redirect to the view page 539 this.widgets.feedbackMessage.destroy(); 540 var me = this; 541 Alfresco.util.PopupManager.displayPrompt( 542 { 543 text: this.msg("message.publishExternal.failure"), 544 buttons: [ 545 { 546 text: this.msg("button.ok"), 547 handler: function() 548 { 549 me._loadPostViewPage(postId); 550 }, 551 isDefault: true 552 }] 553 }); 554 555 }; 556 557 // get the url to call 558 var url = Alfresco.util.blog.generatePublishingRestURL(this.options.siteId, this.options.containerId, postId); 559 560 // execute ajax request 561 Alfresco.util.Ajax.request( 562 { 563 url: url, 564 method: "POST", 565 requestContentType : "application/json", 566 responseContentType : "application/json", 567 dataObj: 568 { 569 action : "publish" 570 }, 571 successMessage: this.msg("message.publishExternal.success"), 572 successCallback: 573 { 574 fn: onPublished, 575 scope: this 576 }, 577 failureCallback: 578 { 579 fn: onPublishFailed, 580 scope: this 581 } 582 }); 583 }, 584 585 /** 586 * Updates the external published blog post. 587 * 588 * @method onUpdateExternal 589 */ 590 onUpdateExternal: function BlogPostEdit_onUpdateExternal(postId) 591 { 592 // update request success handler 593 var onUpdated = function BlogPostEdit_onUpdated(response) 594 { 595 this._loadPostViewPage(postId); 596 }; 597 598 // update request failure handler 599 var onUpdateFailed = function BlogPostEdit_onUpdateFailed(response) 600 { 601 // let the user know that the publish failed, then redirect to the view page 602 this.widgets.feedbackMessage.destroy(); 603 var me = this; 604 Alfresco.util.PopupManager.displayPrompt( 605 { 606 text: this.msg("message.updateExternal.failure"), 607 buttons: [ 608 { 609 text: this.msg("button.ok"), 610 handler: function() 611 { 612 me._loadPostViewPage(postId); 613 }, 614 isDefault: true 615 }] 616 }); 617 618 }; 619 620 // get the url to call 621 var url = Alfresco.util.blog.generatePublishingRestURL(this.options.siteId, this.options.containerId, postId); 622 623 // execute ajax request 624 Alfresco.util.Ajax.request( 625 { 626 url: url, 627 method: "POST", 628 requestContentType : "application/json", 629 responseContentType : "application/json", 630 dataObj: 631 { 632 action : "update" 633 }, 634 successMessage: this.msg("message.updateExternal.success"), 635 successCallback: 636 { 637 fn: onUpdated, 638 scope: this 639 }, 640 failureCallback: 641 { 642 fn: onUpdateFailed, 643 scope: this 644 } 645 }); 646 }, 647 648 /** 649 * PRIVATE FUNCTIONS 650 */ 651 652 /** 653 * Loads the blog post view page 654 * 655 * @method _loadPostViewPage 656 */ 657 _loadPostViewPage: function BlogPostEdit__loadPostViewPage(postId) 658 { 659 window.location = Alfresco.util.blog.generateBlogPostViewUrl(this.options.siteId, this.options.containerId, postId); 660 } 661 }); 662 })(); 663