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 * BlogPostList component. 22 * 23 * @namespace Alfresco 24 * @class Alfresco.BlogPostList 25 */ 26 (function() 27 { 28 /** 29 * YUI Library aliases 30 */ 31 var Dom = YAHOO.util.Dom, 32 Event = YAHOO.util.Event, 33 Element = YAHOO.util.Element; 34 35 /** 36 * Alfresco Slingshot aliases 37 */ 38 var $html = Alfresco.util.encodeHTML; 39 40 41 /** 42 * BlogPostList constructor. 43 * 44 * @param {String} htmlId The HTML id of the parent element 45 * @return {Alfresco.BlogPostList} The new BlogPostList instance 46 * @constructor 47 */ 48 Alfresco.BlogPostList = function(htmlId) 49 { 50 /* Mandatory properties */ 51 this.name = "Alfresco.BlogPostList"; 52 this.id = htmlId; 53 54 /* Initialise prototype properties */ 55 this.widgets = {}; 56 this.currentFilter = {}; 57 this.tagId = 58 { 59 id: 0, 60 tags: {} 61 }; 62 63 /* Register this component */ 64 Alfresco.util.ComponentManager.register(this); 65 66 /* Load YUI Components */ 67 Alfresco.util.YUILoaderHelper.require(["button", "dom", "datasource", "datatable", "paginator", "event", "element"], this.onComponentsLoaded, this); 68 69 /* Decoupled event listeners */ 70 YAHOO.Bubbling.on("tagSelected", this.onTagSelected, this); 71 YAHOO.Bubbling.on("blogConfigChanged", this.onBlogConfigChanged, this); 72 YAHOO.Bubbling.on("changeFilter", this.onChangeFilter, this); 73 YAHOO.Bubbling.on("blogpostlistRefresh", this.onBlogPostListRefresh, this); 74 YAHOO.Bubbling.on("deactivateAllControls", this.onDeactivateAllControls, this); 75 76 return this; 77 }; 78 79 Alfresco.BlogPostList.prototype = 80 { 81 /** 82 * Object container for initialization options 83 * 84 * @property options 85 * @type object 86 */ 87 options: 88 { 89 /** 90 * Current siteId. 91 * 92 * @property siteId 93 * @type string 94 */ 95 siteId: "", 96 97 /** 98 * ContainerId representing root container 99 * 100 * @property containerId 101 * @type string 102 * @default "blog" 103 */ 104 containerId: "blog", 105 106 /** 107 * Initially used filter name and id. 108 */ 109 initialFilter: {}, 110 111 /** 112 * Number of items per page 113 * 114 * @property pageSize 115 * @type int 116 */ 117 pageSize: 10, 118 119 /** 120 * Flag indicating whether the list shows a detailed view or a simple one. 121 * 122 * @property simpleView 123 * @type boolean 124 */ 125 simpleView: false, 126 127 /** 128 * Maximum length of post to show in list view 129 * 130 * @property maxContentLength 131 * @type int 132 * @default 512 133 */ 134 maxContentLength: 512 135 }, 136 137 /** 138 * Current filter to filter blog post list. 139 * 140 * @property currentFilter 141 * @type object 142 */ 143 currentFilter: null, 144 145 /** 146 * Object container for storing YUI widget instances. 147 * 148 * @property widgets 149 * @type object 150 */ 151 widgets: null, 152 153 /** 154 * Object container for storing module instances. 155 * 156 * @property modules 157 * @type object 158 */ 159 modules: null, 160 161 /** 162 * Object literal used to generate unique tag ids 163 * 164 * @property tagId 165 * @type object 166 */ 167 tagId: null, 168 169 /** 170 * Tells whether an action is currently ongoing. 171 * 172 * @property busy 173 * @type boolean 174 * @see _setBusy/_releaseBusy 175 */ 176 busy: false, 177 178 /** 179 * True if publishing actions should be displayed 180 * 181 * @property showPublishingActions 182 * @type boolean 183 * @default false 184 */ 185 showPublishingActions: false, 186 187 /** 188 * Offset of first record on page 189 * 190 * @property recordOffset 191 * @type int 192 * @default 0 193 */ 194 recordOffset: 0, 195 196 /** 197 * Total number of posts in the current view (across all pages) 198 * 199 * @property totalRecords 200 * @type int 201 * @default 0 202 */ 203 totalRecords: 0, 204 205 /** 206 * Set multiple initialization options at once. 207 * 208 * @method setOptions 209 * @param obj {object} Object literal specifying a set of options 210 */ 211 setOptions: function BlogPostList_setOptions(obj) 212 { 213 this.options = YAHOO.lang.merge(this.options, obj); 214 return this; 215 }, 216 217 /** 218 * Set messages for this component. 219 * 220 * @method setMessages 221 * @param obj {object} Object literal specifying a set of messages 222 * @return {Alfresco.DocumentList} returns 'this' for method chaining 223 */ 224 setMessages: function BlogPostList_setMessages(obj) 225 { 226 Alfresco.util.addMessages(obj, this.name); 227 return this; 228 }, 229 230 /** 231 * Fired by YUILoaderHelper when required component script files have 232 * been loaded into the browser. 233 * 234 * @method onComponentsLoaded 235 */ 236 onComponentsLoaded: function BlogPostList_onComponentsLoaded() 237 { 238 Event.onContentReady(this.id, this.onReady, this, true); 239 }, 240 241 /** 242 * Fired by YUI when parent element is available for scripting. 243 * Component initialisation, including instantiation of YUI widgets and event listener binding. 244 * 245 * @method onReady 246 */ 247 onReady: function BlogPostList_onReady() 248 { 249 // Reference to self used by inline functions 250 var me = this; 251 252 // Simple view button 253 this.widgets.simpleView = Alfresco.util.createYUIButton(this, "simpleView-button", this.onSimpleView); 254 255 // called by the paginator on state changes 256 var handlePagination = function BlogPostList_handlePagination(state, dt) 257 { 258 //me.currentPage = state.page; 259 me._updateBlogPostList( 260 { 261 page: state.page 262 }); 263 }; 264 265 // YUI Paginator definition 266 this.widgets.paginator = new YAHOO.widget.Paginator( 267 { 268 containers: [this.id + "-paginator"], 269 rowsPerPage: this.options.pageSize, 270 initialPage: 1, 271 template: this._msg("pagination.template"), 272 pageReportTemplate: this._msg("pagination.template.page-report"), 273 previousPageLinkLabel: this._msg("pagination.previousPageLinkLabel"), 274 nextPageLinkLabel: this._msg("pagination.nextPageLinkLabel") 275 }); 276 277 this.widgets.paginator.subscribe("changeRequest", handlePagination); 278 279 // Hook action events for details view 280 var fnActionHandlerDiv = function BlogPostList_fnActionHandlerDiv(layer, args) 281 { 282 var owner = YAHOO.Bubbling.getOwnerByTagName(args[1].anchor, "div"); 283 if (owner !== null) 284 { 285 if (typeof me[owner.className] == "function") 286 { 287 args[1].stop = true; 288 me[owner.className].call(me, args[1].target.offsetParent, owner); 289 } 290 } 291 return true; 292 }; 293 YAHOO.Bubbling.addDefaultAction("blogpost-action-link-div", fnActionHandlerDiv); 294 295 // Hook action events for simple view 296 var fnActionHandlerSpan = function BlogPostList_fnActionHandlerSpan(layer, args) 297 { 298 var owner = YAHOO.Bubbling.getOwnerByTagName(args[1].anchor, "span"); 299 if (owner !== null) 300 { 301 var action = owner.className; 302 var target = args[1].target; 303 if (typeof me[action] == "function") 304 { 305 me[action].call(me, target.offsetParent, owner); 306 args[1].stop = true; 307 } 308 } 309 return true; 310 }; 311 YAHOO.Bubbling.addDefaultAction("blogpost-action-link-span", fnActionHandlerSpan); 312 313 // DataSource definition 314 var uriBlogPostList = YAHOO.lang.substitute(Alfresco.constants.URL_SERVICECONTEXT + "components/blog/site/{site}/{container}/posts", 315 { 316 site: this.options.siteId, 317 container: this.options.containerId 318 }); 319 this.widgets.dataSource = new YAHOO.util.DataSource(uriBlogPostList, 320 { 321 responseType: YAHOO.util.DataSource.TYPE_JSON, 322 connXhrMode: "queueRequests", 323 responseSchema: 324 { 325 resultsList: "items", 326 metaFields: 327 { 328 recordOffset: "startIndex", 329 totalRecords: "total", 330 metadata: "metadata" 331 } 332 } 333 }); 334 335 /** 336 * Blog post element. We only have a list and not an acutal table, there is therefore 337 * only one column renderer 338 * 339 * @method renderBlogPost 340 * @param elCell {object} 341 * @param oRecord {object} 342 * @param oColumn {object} 343 * @param oData {object|string} 344 */ 345 var renderBlogPost = function BlogPostList_renderBlogPost(elCell, oRecord, oColumn, oData) 346 { 347 // hide the parent temporarily as we first insert the structure and then the content 348 // to avoid problems caused by broken xhtml 349 Dom.addClass(elCell, 'hidden'); 350 351 // fetch the data and pregenerate some values 352 var data = oRecord.getData(); 353 var postViewUrl = Alfresco.util.blog.generateBlogPostViewUrl(me.options.siteId, me.options.containerId, data.name); 354 var statusLabel = Alfresco.util.blog.generatePostStatusLabel(me, data); 355 var authorLink = Alfresco.util.people.generateUserLink(data.author); 356 357 var html = ""; 358 // detailed view 359 if (!me.options.simpleView) 360 { 361 html += '<div class="node post">'; 362 363 // actions 364 html += Alfresco.util.blog.generateBlogPostActions(me, data, 'div', me.showPublishingActions); 365 366 // begin view 367 html += '<div class="nodeContent">'; 368 html += '<span class="nodeTitle"><a href="' + postViewUrl + '">' + $html(data.title) + '</a> '; 369 html += '<span class="theme-color-2 nodeStatus">' + statusLabel + '</span></span>'; 370 html += '<div class="published">'; 371 if (!data.isDraft) 372 { 373 html += '<span class="nodeAttrLabel">' + me._msg("post.publishedOn") + ': </span>'; 374 html += '<span class="nodeAttrValue">' + Alfresco.util.formatDate(data.releasedOn) + '</span>'; 375 html += '<span class="separator"> </span>'; 376 } 377 html += '<span class="nodeAttrLabel">' + me._msg("post.author") + ': </span>'; 378 html += '<span class="nodeAttrValue">' + authorLink + '</span>'; 379 if (data.isPublished && data.postLink && data.postLink.length > 0) 380 { 381 html += '<span class="separator"> </span>'; 382 html += '<span class="nodeAttrLabel">' + me._msg("post.externalLink") + ': </span>'; 383 html += '<span class="nodeAttrValue"><a target="_blank" href="' + data.postLink + '">' + me._msg("post.clickHere") + '</a></span>'; 384 } 385 html += '</div>'; 386 html += '<div class="content yuieditor"></div>'; 387 html += '</div>'; 388 // end view 389 390 html += '</div>'; 391 392 // begin footer 393 html += '<div class="nodeFooter">'; 394 html += '<span class="nodeAttrLabel replyTo">' + me._msg("post.replies") + ': </span>'; 395 html += '<span class="nodeAttrValue">(' + data.commentCount + ')</span>'; 396 html += '<span class="separator"> </span>'; 397 html += '<span class="nodeAttrValue"><a href="' + postViewUrl + '">' + me._msg("post.read") + '</a></span>'; 398 html += '<span class="separator"> </span>'; 399 400 html += '<span class="nodeAttrLabel tagLabel">' + me._msg("label.tags") +': </span>'; 401 if (data.tags.length > 0) 402 { 403 for (var x=0; x < data.tags.length; x++) 404 { 405 if (x > 0) 406 { 407 html += ', '; 408 } 409 html += Alfresco.util.tags.generateTagLink(me, data.tags[x]); 410 } 411 } 412 else 413 { 414 html += '<span class="nodeAttrValue">' + me._msg("post.noTags") + '</span>'; 415 } 416 html += '</div></div>'; 417 // end 418 } 419 420 // simple view 421 else 422 { 423 // add a class to the parent div so that we can add a separator line in the simple view 424 Dom.addClass(elCell, 'row-separator'); 425 426 html += '<div class="node post simple">'; 427 428 // begin actions 429 html += Alfresco.util.blog.generateBlogPostActions(me, data, 'span', me.showPublishingActions); 430 431 // begin view 432 html += '<div class="nodeContent">'; 433 html += '<span class="nodeTitle"><a href="' + postViewUrl + '">' + $html(data.title) + '</a> '; 434 html += '<span class="theme-color-2 nodeStatus">' + statusLabel + '</span></span>'; 435 html += '<div class="published">'; 436 if (!data.isDraft) 437 { 438 html += '<span class="nodeAttrLabel">' + me._msg("post.publishedOn") + ': </span>'; 439 html += '<span class="nodeAttrValue">' + Alfresco.util.formatDate(data.releasedOn) + '</span>'; 440 html += '<span class="separator"> </span>'; 441 } 442 html += '<span class="nodeAttrLabel">' + me._msg("post.author") + ': </span>'; 443 html += '<span class="nodeAttrValue">' + authorLink + '</span>'; 444 if (data.isPublished && data.postLink && data.postLink.length > 0) 445 { 446 html += '<span class="separator"> </span>'; 447 html += '<span class="nodeAttrLabel">' + me._msg("post.externalLink") + ': </span>'; 448 html += '<span class="nodeAttrValue"><a target="_blank" href="' + data.postLink + '">' + me._msg("post.clickHere") + '</a></span>'; 449 } 450 html += '</div>'; 451 html += '</div>'; 452 html += '</div>'; 453 } 454 455 // assign html 456 elCell.innerHTML = html; 457 458 // finally add the content. We do this here to avoid a broken page layout, as 459 // data.content isn't valid xhtml. 460 if (!me.options.simpleView) 461 { 462 var contentElem = Dom.getElementsByClassName("content", "div", elCell); 463 if (contentElem.length == 1) 464 { 465 contentElem[0].innerHTML = data.content; 466 } 467 } 468 469 // now show the element 470 Dom.removeClass(elCell, 'hidden'); 471 }; 472 473 // DataTable column defintions 474 var columnDefinitions = [ 475 { 476 key: "blogposts", label: "BlogPosts", sortable: false, formatter: renderBlogPost 477 }]; 478 479 // DataTable definition 480 this.widgets.dataTable = new YAHOO.widget.DataTable(this.id + "-postlist", columnDefinitions, this.widgets.dataSource, 481 { 482 initialLoad: false, 483 dynamicData: true, 484 MSG_EMPTY: this._msg("message.loading") 485 }); 486 487 // Update totalRecords on the fly with value from server 488 this.widgets.dataTable.handleDataReturnPayload = function DL_handleDataReturnPayload(oRequest, oResponse, oPayload) 489 { 490 // Save totalRecords for Paginator update later 491 me.recordOffset = oResponse.meta.recordOffset; 492 me.totalRecords = oResponse.meta.totalRecords; 493 494 oPayload = oPayload || {}; 495 oPayload.recordOffset = oResponse.meta.recordOffset; 496 oPayload.totalRecords = oResponse.meta.totalRecords; 497 return oPayload; 498 } 499 500 // Prevent the DataTable from updating the Paginator widget 501 this.widgets.dataTable.doBeforePaginatorChange = function DL_doBeforePaginatorChange(oPaginatorState) 502 { 503 return false; 504 } 505 506 // Rendering complete event handler 507 this.widgets.dataTable.subscribe("renderEvent", function() 508 { 509 // Update the paginator if it's been created 510 this.widgets.paginator.setState( 511 { 512 recordOffset: this.recordOffset, 513 totalRecords: this.totalRecords 514 }); 515 this.widgets.paginator.render(); 516 }, this, true); 517 518 // Custom error messages 519 this._setDefaultDataTableErrors(this.widgets.dataTable); 520 521 // Hook tableMsgShowEvent to clear out fixed-pixel width on <table> element (breaks resizer) 522 this.widgets.dataTable.subscribe("tableMsgShowEvent", function(oArgs) 523 { 524 // NOTE: Scope needs to be DataTable 525 this._elMsgTbody.parentNode.style.width = ""; 526 }); 527 528 // Override abstract function within DataTable to set custom error message 529 this.widgets.dataTable.doBeforeLoadData = function BlogPostList_doBeforeLoadData(sRequest, oResponse, oPayload) 530 { 531 if (oResponse.error) 532 { 533 try 534 { 535 var response = YAHOO.lang.JSON.parse(oResponse.responseText); 536 this.set("MSG_ERROR", response.message); 537 } 538 catch(e) 539 { 540 me._setDefaultDataTableErrors(me.widgets.dataTable); 541 } 542 } 543 else if (oResponse.results && !me.options.usePagination) 544 { 545 this.renderLoopSize = Alfresco.util.RENDERLOOPSIZE; 546 } 547 548 // set whether publishing actions should be available 549 me.showPublishingActions = oResponse.meta.metadata.externalBlogConfig; 550 551 // Must return true to have the "Loading..." message replaced by the error message 552 return true; 553 }; 554 555 // Enable row highlighting 556 this.widgets.dataTable.subscribe("rowMouseoverEvent", this.onEventHighlightRow, this, true); 557 this.widgets.dataTable.subscribe("rowMouseoutEvent", this.onEventUnhighlightRow, this, true); 558 559 // Load the new blog posts by default 560 var filterObj = YAHOO.lang.merge( 561 { 562 filterId: "new", 563 filterOwner: "Alfresco.BlogPostListFilter", 564 filterData: null 565 }, this.options.initialFilter); 566 YAHOO.Bubbling.fire("changeFilter", filterObj); 567 }, 568 569 // Actions 570 571 /** 572 * Action handler for the simple view toggle button 573 * 574 * @method onSimpleView 575 */ 576 onSimpleView: function BlogPostList_onSimpleView(e, p_obj) 577 { 578 this.options.simpleView = !this.options.simpleView; 579 p_obj.set("label", this._msg(this.options.simpleView ? "header.detailList" : "header.simpleList")); 580 581 // refresh the list 582 YAHOO.Bubbling.fire("blogpostlistRefresh"); 583 Event.preventDefault(e); 584 }, 585 586 /** 587 * Handler for the view blog post action links 588 * 589 * @method onViewBlogPost 590 * @param row {object} DataTable row representing post to be actioned 591 */ 592 onViewBlogPost: function BlogPostList_onViewNode(row) 593 { 594 var record = this.widgets.dataTable.getRecord(row); 595 window.location = this._generatePostViewUrl(record.getData('name')); 596 }, 597 598 /** 599 * Handler for the edit blog post action links 600 * 601 * @method onEditBlogPost 602 * @param row {object} DataTable row representing post to be actioned 603 */ 604 onEditBlogPost: function BlogPostList_onEditBlogPost(row) 605 { 606 var record = this.widgets.dataTable.getRecord(row); 607 var url = YAHOO.lang.substitute(Alfresco.constants.URL_PAGECONTEXT + "site/{site}/blog-postedit?postId={postId}", 608 { 609 site: this.options.siteId, 610 postId: record.getData('name') 611 }); 612 window.location = url; 613 }, 614 615 /** 616 * Handler for the delete blog post action links 617 * 618 * @method onDeleteBlogPost 619 * @param row {object} DataTable row representing post to be actioned 620 */ 621 onDeleteBlogPost: function BlogPostList_onDeleteBlogPost(row) 622 { 623 var record = this.widgets.dataTable.getRecord(row); 624 var me = this; 625 Alfresco.util.PopupManager.displayPrompt( 626 { 627 title: this._msg("message.confirm.delete.title"), 628 text: this._msg("message.confirm.delete", $html(record.getData('title'))), 629 buttons: [ 630 { 631 text: this._msg("button.delete"), 632 handler: function BlogPostList_onDeleteBlogPost_delete() 633 { 634 this.destroy(); 635 me._deleteBlogPostConfirm.call(me, record.getData('name')); 636 } 637 }, 638 { 639 text: this._msg("button.cancel"), 640 handler: function BlogPostList_onDeleteBlogPost_cancel() 641 { 642 this.destroy(); 643 }, 644 isDefault: true 645 }] 646 }); 647 }, 648 649 /** 650 * Handler for the publish external action links 651 * 652 * @method onPublishExternal 653 * @param row {object} DataTable row representing post to be actioned 654 */ 655 onPublishExternal: function BlogPostList_onPublishExternal(row) 656 { 657 var record = this.widgets.dataTable.getRecord(row); 658 this._publishExternal(record.getData('name')); 659 }, 660 661 /** 662 * Handler for the update external action links 663 * 664 * @method onUpdateExternal 665 * @param row {object} DataTable row representing post to be actioned 666 */ 667 onUpdateExternal: function BlogPostList_onUpdateExternal(row) 668 { 669 var record = this.widgets.dataTable.getRecord(row); 670 this._updateExternal(record.getData('name')); 671 }, 672 673 /** 674 * Handler for the unpublish external action links 675 * 676 * @method onUnpublishExternal 677 * @param row {object} DataTable row representing post to be actioned 678 */ 679 onUnpublishExternal: function BlogPostList_onUnpublishExternal(row) 680 { 681 var record = this.widgets.dataTable.getRecord(row); 682 this._unpublishExternal(record.getData('name')); 683 }, 684 685 /** 686 * Tag selected handler 687 * 688 * @method onTagSelected 689 */ 690 onTagSelected: function BlogPostList_onTagSelected(layer, args) 691 { 692 var obj = args[1]; 693 if (obj && (obj.tagName !== null)) 694 { 695 var filterObj = 696 { 697 filterId: obj.tagName, 698 filterOwner: "Alfresco.BlogPostListTags", 699 filterData: null 700 }; 701 YAHOO.Bubbling.fire("changeFilter", filterObj); 702 } 703 }, 704 705 /** 706 * On blog config changed h handler 707 * 708 * @method onTagSelected 709 */ 710 onBlogConfigChanged: function BlogPostList_onBlogConfigChanged(layer, args) 711 { 712 // refresh the list 713 this._updateBlogPostList(); 714 }, 715 716 // Actions implementation 717 718 /** 719 * Blog post deletion implementation 720 * 721 * @method _deleteBlogPostConfirm 722 * @param postId {string} the id of the blog post to delete 723 */ 724 _deleteBlogPostConfirm: function BlogPostList__deleteBlogPostConfirm(postId) 725 { 726 // show busy message 727 if (! this._setBusy(this._msg('message.wait'))) 728 { 729 return; 730 } 731 732 // ajax request success handler 733 var onDeletedSuccess = function BlogPostList_deleteBlogPostConfirm_onDeletedSuccess(response) 734 { 735 // remove busy message 736 this._releaseBusy(); 737 738 // reload the table data 739 this._updateBlogPostList(); 740 }; 741 742 // get the url to call 743 var url = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "api/blog/post/site/{site}/{container}/{postId}?page=blog-postlist", 744 { 745 site: this.options.siteId, 746 container: this.options.containerId, 747 postId: encodeURIComponent(postId) 748 }); 749 750 // execute ajax request 751 Alfresco.util.Ajax.request( 752 { 753 url: url, 754 method: "DELETE", 755 responseContentType : "application/json", 756 successMessage: this._msg("message.delete.success"), 757 successCallback: 758 { 759 fn: onDeletedSuccess, 760 scope: this 761 }, 762 failureMessage: this._msg("message.delete.failure"), 763 failureCallback: 764 { 765 fn: function(response) 766 { 767 this._releaseBusy(); 768 }, 769 scope: this 770 } 771 }); 772 }, 773 774 /** 775 * Publishing of a blog post implementation 776 * 777 * @method _publishExternal 778 * @param postId {string} the id of the blog post to publish 779 */ 780 _publishExternal: function BlogPostList__publishExternal(postId) 781 { 782 // show busy message 783 if (! this._setBusy(this._msg('message.wait'))) 784 { 785 return; 786 } 787 788 // ajax call success handler 789 var onPublishedSuccess = function BlogPostList_onPublishedSuccess(response) 790 { 791 // remove busy message 792 this._releaseBusy(); 793 794 // reload the table data 795 this._updateBlogPostList(); 796 }; 797 798 // get the url to call 799 var url = Alfresco.util.blog.generatePublishingRestURL(this.options.siteId, this.options.containerId, postId); 800 801 // execute ajax request 802 Alfresco.util.Ajax.request( 803 { 804 url: url, 805 method: "POST", 806 requestContentType : "application/json", 807 responseContentType : "application/json", 808 dataObj: 809 { 810 action : "publish" 811 }, 812 successMessage: this._msg("message.publishExternal.success"), 813 successCallback: 814 { 815 fn: onPublishedSuccess, 816 scope: this 817 }, 818 failureMessage: this._msg("message.publishExternal.failure"), 819 failureCallback: 820 { 821 fn: function(response) { this._releaseBusy(); }, 822 scope: this 823 } 824 }); 825 }, 826 827 828 /** 829 * Updating of an external published blog post implementation 830 * 831 * @method _updateExternal 832 * @param postId {string} the id of the blog post to update 833 */ 834 _updateExternal: function BlogPostList__updateExternal(postId) 835 { 836 // show busy message 837 if (! this._setBusy(this._msg('message.wait'))) 838 { 839 return; 840 } 841 842 // ajax request success handler 843 var onUpdatedSuccess = function BlogPostList_onUpdatedSuccess(response) 844 { 845 // remove busy message 846 this._releaseBusy(); 847 848 // reload the table data 849 this._updateBlogPostList(); 850 }; 851 852 // get the url to call 853 var url = Alfresco.util.blog.generatePublishingRestURL(this.options.siteId, this.options.containerId, postId); 854 855 // execute ajax request 856 Alfresco.util.Ajax.request( 857 { 858 url: url, 859 method: "POST", 860 requestContentType : "application/json", 861 responseContentType : "application/json", 862 dataObj: 863 { 864 action : "update" 865 }, 866 successMessage: this._msg("message.updateExternal.success"), 867 successCallback: 868 { 869 fn: onUpdatedSuccess, 870 scope: this 871 }, 872 failureMessage: this._msg("message.updateExternal.failure"), 873 failureCallback: 874 { 875 fn: function(response) { this._releaseBusy(); }, 876 scope: this 877 } 878 }); 879 }, 880 881 882 /** 883 * Unpublishing of an external published blog post implementation 884 * 885 * @method _unpublishExternal 886 * @param postId {string} the id of the blog post to update 887 */ 888 _unpublishExternal: function BlogPostList__onUnpublishExternal(postId) 889 { 890 // show busy message 891 if (! this._setBusy(this._msg('message.wait'))) 892 { 893 return; 894 } 895 896 // ajax request success handler 897 var onUnpublishedSuccess = function BlogPostList_onUnpublishedSuccess(response) 898 { 899 // remove busy message 900 this._releaseBusy(); 901 902 // reload the table data 903 this._updateBlogPostList(); 904 }; 905 906 // get the url to call 907 var url = Alfresco.util.blog.generatePublishingRestURL(this.options.siteId, this.options.containerId, postId); 908 909 // execute ajax request 910 Alfresco.util.Ajax.request( 911 { 912 url: url, 913 method: "POST", 914 requestContentType : "application/json", 915 responseContentType : "application/json", 916 dataObj: 917 { 918 action : "unpublish" 919 }, 920 successMessage: this._msg("message.unpublishExternal.success"), 921 successCallback: 922 { 923 fn: onUnpublishedSuccess, 924 scope: this 925 }, 926 failureMessage: this._msg("message.unpublishExternal.failure"), 927 failureCallback: 928 { 929 fn: function(response) 930 { 931 this._releaseBusy(); 932 }, 933 scope: this 934 } 935 }); 936 }, 937 938 939 // row highlighting 940 941 /** 942 * Custom event handler to highlight row. 943 * 944 * @method onEventHighlightRow 945 * @param oArgs.event {HTMLEvent} Event object. 946 * @param oArgs.target {HTMLElement} Target element. 947 */ 948 onEventHighlightRow: function BlogPostList_onEventHighlightRow(oArgs) 949 { 950 // only highlight if we got actions to show 951 var record = this.widgets.dataTable.getRecord(oArgs.target.id); 952 var permissions = record.getData('permissions'); 953 if (!(permissions.edit || permissions["delete"])) 954 { 955 return; 956 } 957 958 var elem = Dom.getElementsByClassName('post', null, oArgs.target, null); 959 Dom.addClass(elem, 'over'); 960 }, 961 962 /** 963 * Custom event handler to unhighlight row. 964 * 965 * @method onEventUnhighlightRow 966 * @param oArgs.event {HTMLEvent} Event object. 967 * @param oArgs.target {HTMLElement} Target element. 968 */ 969 onEventUnhighlightRow: function BlogPostList_onEventUnhighlightRow(oArgs) 970 { 971 var elem = Dom.getElementsByClassName('post', null, oArgs.target, null); 972 Dom.removeClass(elem, 'over'); 973 }, 974 975 976 /** 977 * BlogPostList Change filter event handler 978 * 979 * @method onChangeFilter 980 * @param layer {object} Event fired (unused) 981 * @param args {array} Event parameters (new filterId) 982 */ 983 onChangeFilter: function BlogPostList_onChangeFilter(layer, args) 984 { 985 var obj = args[1]; 986 if ((obj !== null) && (obj.filterId !== null)) 987 { 988 this.currentFilter = 989 { 990 filterId: obj.filterId, 991 filterOwner: obj.filterOwner, 992 filterData: obj.filterData 993 }; 994 this._updateBlogPostList( 995 { 996 page: 1 997 }); 998 YAHOO.Bubbling.fire("filterChanged", this.currentFilter); 999 } 1000 }, 1001 1002 /** 1003 * Deactivate All Controls event handler 1004 * 1005 * @method onDeactivateAllControls 1006 * @param layer {object} Event fired 1007 * @param args {array} Event parameters (depends on event type) 1008 */ 1009 onDeactivateAllControls: function BlogPostList_onDeactivateAllControls(layer, args) 1010 { 1011 var index, widget, fnDisable = Alfresco.util.disableYUIButton; 1012 for (index in this.widgets) 1013 { 1014 if (this.widgets.hasOwnProperty(index)) 1015 { 1016 fnDisable(this.widgets[index]); 1017 } 1018 } 1019 }, 1020 1021 /** 1022 * Updates the list title considering the current active filter. 1023 */ 1024 updateListTitle: function BlogPostList_updateListTitle() 1025 { 1026 var elem = Dom.get(this.id + '-listtitle'); 1027 var title = this._msg("title.postlist"); 1028 1029 var filterOwner = this.currentFilter.filterOwner; 1030 var filterId = this.currentFilter.filterId; 1031 var filterData = this.currentFilter.filterData; 1032 if (filterOwner == "Alfresco.BlogPostListFilter") 1033 { 1034 if (filterId == "all") 1035 { 1036 title = this._msg("title.allposts"); 1037 } 1038 if (filterId == "new") 1039 { 1040 title = this._msg("title.newposts"); 1041 } 1042 else if (filterId == "mydrafts") 1043 { 1044 title = this._msg("title.mydrafts"); 1045 } 1046 else if (filterId == "mypublished") 1047 { 1048 title = this._msg("title.mypublished"); 1049 } 1050 else if (filterId == "publishedext") 1051 { 1052 title = this._msg("title.publishedext"); 1053 } 1054 } 1055 else if (filterOwner == "Alfresco.BlogPostListTags") 1056 { 1057 title = this._msg("title.bytag", $html(filterData)); 1058 } 1059 else if (filterOwner == "Alfresco.BlogPostListArchive" && filterId == "bymonth") 1060 { 1061 var date = new Date(filterData.year, filterData.month, 1); 1062 var formattedDate = Alfresco.util.formatDate(date, this._msg("date-format.monthYear")); 1063 title = this._msg("title.bymonth", formattedDate); 1064 } 1065 1066 elem.innerHTML = title; 1067 }, 1068 1069 1070 /** 1071 * BlogPostList Refresh Required event handler 1072 * 1073 * @method onBlogPostListRefresh 1074 * @param layer {object} Event fired (unused) 1075 * @param args {array} Event parameters (unused) 1076 */ 1077 onBlogPostListRefresh: function BlogPostList_onBlogPostListRefresh(layer, args) 1078 { 1079 this._updateBlogPostList(); 1080 }, 1081 1082 /** 1083 * Displays the provided busyMessage but only in case 1084 * the component isn't busy set. 1085 * 1086 * @return true if the busy state was set, false if the component is already busy 1087 */ 1088 _setBusy: function BlogPostList__setBusy(busyMessage) 1089 { 1090 if (this.busy) 1091 { 1092 return false; 1093 } 1094 this.busy = true; 1095 this.widgets.busyMessage = Alfresco.util.PopupManager.displayMessage( 1096 { 1097 text: busyMessage, 1098 spanClass: "wait", 1099 displayTime: 0 1100 }); 1101 return true; 1102 }, 1103 1104 /** 1105 * Removes the busy message and marks the component as non-busy 1106 */ 1107 _releaseBusy: function BlogPostList__releaseBusy() 1108 { 1109 if (this.busy) 1110 { 1111 this.widgets.busyMessage.destroy(); 1112 this.busy = false; 1113 return true; 1114 } 1115 else 1116 { 1117 return false; 1118 } 1119 }, 1120 1121 /** 1122 * Gets a custom message 1123 * 1124 * @method _msg 1125 * @param messageId {string} The messageId to retrieve 1126 * @return {string} The custom message 1127 * @private 1128 */ 1129 _msg: function BlogPostList_msg(messageId) 1130 { 1131 return Alfresco.util.message.call(this, messageId, "Alfresco.BlogPostList", Array.prototype.slice.call(arguments).slice(1)); 1132 }, 1133 1134 /** 1135 * Resets the YUI DataTable errors to our custom messages 1136 * NOTE: Scope could be YAHOO.widget.DataTable, so can't use "this" 1137 * 1138 * @method _setDefaultDataTableErrors 1139 * @param dataTable {object} Instance of the DataTable 1140 */ 1141 _setDefaultDataTableErrors: function BlogPostList__setDefaultDataTableErrors(dataTable) 1142 { 1143 var msg = Alfresco.util.message; 1144 dataTable.set("MSG_EMPTY", msg("message.empty", "Alfresco.BlogPostList")); 1145 dataTable.set("MSG_ERROR", msg("message.error", "Alfresco.BlogPostList")); 1146 }, 1147 1148 /** 1149 * Updates blog post list by calling data webscript with current site and filter information 1150 * 1151 * @method _updateBlogPostList 1152 */ 1153 _updateBlogPostList: function BlogPostList__updateBlogPostList(p_obj) 1154 { 1155 // show busy message 1156 /*if (! this._setBusy(this._msg('message.wait'))) 1157 { 1158 return; 1159 }*/ 1160 1161 // Reset the custom error messages 1162 this._setDefaultDataTableErrors(this.widgets.dataTable); 1163 1164 // ajax request success handler 1165 var successHandler = function BlogPostList__updateBlogPostList_successHandler(sRequest, oResponse, oPayload) 1166 { 1167 // remove busy message 1168 //this._releaseBusy(); 1169 1170 this.widgets.dataTable.onDataReturnInitializeTable.call(this.widgets.dataTable, sRequest, oResponse, oPayload); 1171 this.updateListTitle(); 1172 }; 1173 1174 // ajax request failure handler 1175 var failureHandler = function BlogPostList__updateBlogPostList_failureHandler(sRequest, oResponse) 1176 { 1177 // remove busy message 1178 //this._releaseBusy(); 1179 1180 if (oResponse.status == 401) 1181 { 1182 // Our session has likely timed-out, so refresh to offer the login page 1183 window.location.reload(true); 1184 } 1185 else 1186 { 1187 try 1188 { 1189 var response = YAHOO.lang.JSON.parse(oResponse.responseText); 1190 this.widgets.dataTable.set("MSG_ERROR", response.message); 1191 this.widgets.dataTable.showTableMessage(response.message, YAHOO.widget.DataTable.CLASS_ERROR); 1192 if (oResponse.status == 404) 1193 { 1194 // Site or container not found - deactivate controls 1195 YAHOO.Bubbling.fire("deactivateAllControls"); 1196 } 1197 } 1198 catch(e) 1199 { 1200 this._setDefaultDataTableErrors(this.widgets.dataTable); 1201 } 1202 } 1203 }; 1204 1205 // get the url to call 1206 this.widgets.dataSource.sendRequest(this._buildBlogPostListParams(p_obj || {}), 1207 { 1208 success: successHandler, 1209 failure: failureHandler, 1210 scope: this 1211 }); 1212 }, 1213 1214 /** 1215 * Build URI parameter string for doclist JSON data webscript 1216 * 1217 * @method _buildDocListParams 1218 * @param p_obj.page {string} Page number 1219 * @param p_obj.pageSize {string} Number of items per page 1220 */ 1221 _buildBlogPostListParams: function BlogPostList__buildDocListParams(p_obj) 1222 { 1223 var params = 1224 { 1225 contentLength: this.options.maxContentLength, 1226 fromDate: null, 1227 toDate: null, 1228 tag: null, 1229 page: this.widgets.paginator.getCurrentPage() || "1", 1230 pageSize: this.widgets.paginator.getRowsPerPage() 1231 }; 1232 1233 // Passed-in overrides 1234 if (typeof p_obj == "object") 1235 { 1236 params = YAHOO.lang.merge(params, p_obj); 1237 } 1238 1239 // calculate the startIndex param 1240 params.startIndex = (params.page-1) * params.pageSize; 1241 1242 // check what url to call and with what parameters 1243 var filterOwner = this.currentFilter.filterOwner; 1244 var filterId = this.currentFilter.filterId; 1245 var filterData = this.currentFilter.filterData; 1246 1247 // check whether we got a filter or not 1248 var url = ""; 1249 if (filterOwner == "Alfresco.BlogPostListFilter") 1250 { 1251 // latest only 1252 if (filterId == "all") 1253 { 1254 url = ""; 1255 } 1256 if (filterId == "new") 1257 { 1258 url = "/new"; 1259 } 1260 else if (filterId == "mydrafts") 1261 { 1262 url = "/mydrafts"; 1263 } 1264 else if (filterId == "mypublished") 1265 { 1266 url = "/mypublished"; 1267 } 1268 else if (filterId == "publishedext") 1269 { 1270 url = "/publishedext"; 1271 } 1272 } 1273 else if (filterOwner == "Alfresco.TagFilter") 1274 { 1275 params.tag = encodeURIComponent(filterData); 1276 } 1277 else if (filterOwner == "Alfresco.BlogPostListArchive" && filterId == "bymonth") 1278 { 1279 var fromDate = new Date(filterData.year, filterData.month, 1); 1280 var toDate = new Date(filterData.year, filterData.month + 1, 1); 1281 toDate = new Date(toDate.getTime() - 1); 1282 params.fromDate = fromDate.getTime(); 1283 params.toDate = toDate.getTime(); 1284 } 1285 1286 // build the url extension 1287 var urlExt = "", paramName; 1288 for (paramName in params) 1289 { 1290 if (params[paramName] !== null) 1291 { 1292 urlExt += "&" + paramName + "=" + encodeURIComponent(params[paramName]); 1293 } 1294 } 1295 if (urlExt.length > 0) 1296 { 1297 urlExt = urlExt.substring(1); 1298 } 1299 return url + "?" + urlExt; 1300 } 1301 }; 1302 })(); 1303