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 * Dashboard MyTasks component. 22 * 23 * @namespace Alfresco.dashlet 24 * @class Alfresco.dashlet.MyTasks 25 */ 26 (function() 27 { 28 /** 29 * YUI Library aliases 30 */ 31 var Dom = YAHOO.util.Dom, 32 Event = YAHOO.util.Event, 33 Selector = YAHOO.util.Selector; 34 35 /** 36 * Alfresco Slingshot aliases 37 */ 38 var $html = Alfresco.util.encodeHTML, 39 $siteURL = Alfresco.util.siteURL; 40 /** 41 * Preferences 42 */ 43 var PREFERENCES_TASKS_DASHLET_FILTER = "org.alfresco.share.tasks.dashlet.filter"; 44 45 /** 46 * Dashboard MyTasks constructor. 47 * 48 * @param {String} htmlId The HTML id of the parent element 49 * @return {Alfresco.dashlet.MyTasks} The new component instance 50 * @constructor 51 */ 52 Alfresco.dashlet.MyTasks = function MyTasks_constructor(htmlId) 53 { 54 Alfresco.dashlet.MyTasks.superclass.constructor.call(this, "Alfresco.dashlet.MyTasks", htmlId, ["button", "container", "datasource", "datatable", "paginator", "history", "animation"]); 55 56 // Services 57 this.services.preferences = new Alfresco.service.Preferences(); 58 59 return this; 60 }; 61 62 /** 63 * Extend from Alfresco.component.Base 64 */ 65 YAHOO.extend(Alfresco.dashlet.MyTasks, Alfresco.component.Base); 66 67 /** 68 * Augment prototype with Common Workflow actions to reuse createFilterURLParameters 69 */ 70 YAHOO.lang.augmentProto(Alfresco.dashlet.MyTasks, Alfresco.action.WorkflowActions); 71 72 /** 73 * Augment prototype with main class implementation, ensuring overwrite is enabled 74 */ 75 YAHOO.lang.augmentObject(Alfresco.dashlet.MyTasks.prototype, 76 { 77 /** 78 * Object container for initialization options 79 * 80 * @property options 81 * @type object 82 */ 83 options: 84 { 85 /** 86 * Task types not to display 87 * 88 * @property hiddenTaskTypes 89 * @type object 90 * @default [] 91 */ 92 hiddenTaskTypes: [], 93 94 /** 95 * Maximum number of tasks to display in the dashlet. 96 * 97 * @property maxItems 98 * @type int 99 * @default 50 100 */ 101 maxItems: 50, 102 103 /** 104 * Filter look-up: type to display value and query value 105 * 106 * @property filters 107 * @type Object 108 */ 109 filters: {} 110 }, 111 112 /** 113 * Fired by YUI when parent element is available for scripting 114 * @method onReady 115 */ 116 onReady: function MyTasks_onReady() 117 { 118 // Create filter menu 119 this.widgets.filterMenuButton = Alfresco.util.createYUIButton(this, "filters", this.onFilterSelected, 120 { 121 type: "menu", 122 menu: "filters-menu", 123 lazyloadmenu: false 124 }); 125 126 // Load preferences (after which the appropriate tasks will be displayed) 127 this.services.preferences.request(PREFERENCES_TASKS_DASHLET_FILTER, 128 { 129 successCallback: 130 { 131 fn: this.onPreferencesLoaded, 132 scope: this 133 } 134 }); 135 }, 136 137 /** 138 * Process response from preference query 139 * 140 * @method onPreferencesLoaded 141 * @param p_response {object} Response from "api/people/{userId}/preferences" query 142 */ 143 onPreferencesLoaded: function MyTasks_onPreferencesLoaded(p_response) 144 { 145 // Select the preferred filter in the ui 146 var filter = Alfresco.util.findValueByDotNotation(p_response.json, PREFERENCES_TASKS_DASHLET_FILTER, "allTasks"); 147 filter = this.options.filters.hasOwnProperty(filter) ? filter : "allTasks"; 148 this.widgets.filterMenuButton.set("label", this.msg("filter." + filter)); 149 this.widgets.filterMenuButton.value = filter; 150 151 // Display the toolbar now that we have selected the filter 152 Dom.removeClass(Selector.query(".toolbar div", this.id, true), "hidden"); 153 154 // Prepare webscript url to task instances 155 var webscript = YAHOO.lang.substitute("api/task-instances?authority={authority}&properties={properties}&exclude={exclude}", 156 { 157 authority: encodeURIComponent(Alfresco.constants.USERNAME), 158 properties: ["bpm_priority", "bpm_status", "bpm_dueDate", "bpm_description"].join(","), 159 exclude: this.options.hiddenTaskTypes.join(",") 160 }); 161 162 /** 163 * Create datatable with a simple pagination that only displays number of results. 164 * The pagination is handled in the "base" data source url and can't be changed in the dashlet 165 */ 166 this.widgets.alfrescoDataTable = new Alfresco.util.DataTable( 167 { 168 dataSource: 169 { 170 url: Alfresco.constants.PROXY_URI + webscript, 171 initialParameters: this.substituteParameters(this.options.filters[filter]) || "" 172 }, 173 dataTable: 174 { 175 container: this.id + "-tasks", 176 columnDefinitions: 177 [ 178 { key: "isPooled", sortable: false, formatter: this.bind(this.renderCellIcons), width: 24 }, 179 { key: "title", sortable: false, formatter: this.bind(this.renderCellTaskInfo) }, 180 { key: "name", sortable: false, formatter: this.bind(this.renderCellActions), width: 45 } 181 ], 182 config: 183 { 184 MSG_EMPTY: this.msg("message.noTasks") 185 } 186 }, 187 paginator: 188 { 189 history: false, 190 hide: false, 191 config: 192 { 193 containers: [this.id + "-paginator"], 194 template: this.msg("pagination.template"), 195 pageReportTemplate: this.msg("pagination.template.page-report"), 196 rowsPerPage: this.options.maxItems 197 } 198 } 199 }); 200 201 // Override DataTable function to set custom empty message 202 var me = this, 203 dataTable = this.widgets.alfrescoDataTable.getDataTable(), 204 original_doBeforeLoadData = dataTable.doBeforeLoadData; 205 206 dataTable.doBeforeLoadData = function MyTasks_doBeforeLoadData(sRequest, oResponse, oPayload) 207 { 208 // Hide the paginator if there are fewer rows than would cause pagination 209 Dom.setStyle(this.configs.paginator.getContainerNodes(), "visibility", (oResponse.results.length == 0) ? "hidden" : "visible"); 210 211 if (oResponse.results.length === 0) 212 { 213 oResponse.results.unshift( 214 { 215 isInfo: true, 216 title: me.msg("empty.title"), 217 description: me.msg("empty.description") 218 }); 219 } 220 221 return original_doBeforeLoadData.apply(this, arguments); 222 }; 223 }, 224 225 /** 226 * Reloads the list with the new filter and updates the filter menu button's label 227 * 228 * @param p_sType {string} The event 229 * @param p_aArgs {array} Event arguments 230 */ 231 onFilterSelected: function MyTasks_onFilterSelected(p_sType, p_aArgs) 232 { 233 var menuItem = p_aArgs[1]; 234 235 if (menuItem) 236 { 237 this.widgets.filterMenuButton.set("label", menuItem.cfg.getProperty("text")); 238 this.widgets.filterMenuButton.value = menuItem.value; 239 240 var parameters = this.substituteParameters(this.options.filters[menuItem.value], {}); 241 this.widgets.alfrescoDataTable.loadDataTable(parameters); 242 243 // Save preferences 244 this.services.preferences.set(PREFERENCES_TASKS_DASHLET_FILTER, menuItem.value); 245 } 246 }, 247 248 /** 249 * Priority & pooled icons custom datacell formatter 250 */ 251 renderCellIcons: function MyTasks_onReady_renderCellIcons(elCell, oRecord, oColumn, oData) 252 { 253 var data = oRecord.getData(), 254 desc = ""; 255 256 if (data.isInfo) 257 { 258 oColumn.width = 52; 259 Dom.setStyle(elCell, "width", oColumn.width + "px"); 260 Dom.setStyle(elCell.parentNode, "width", oColumn.width + "px"); 261 262 desc = '<img src="' + Alfresco.constants.URL_RESCONTEXT + 'components/images/help-task-bw-32.png" />'; 263 } 264 else 265 { 266 var priority = data.properties["bpm_priority"], 267 priorityMap = { "1": "high", "2": "medium", "3": "low" }, 268 priorityKey = priorityMap[priority + ""], 269 pooledTask = data.isPooled; 270 271 desc = '<img src="' + Alfresco.constants.URL_RESCONTEXT + 'components/images/priority-' + priorityKey + '-16.png" title="' + this.msg("label.priority", this.msg("priority." + priorityKey)) + '"/>'; 272 if (pooledTask) 273 { 274 desc += '<br/><img src="' + Alfresco.constants.URL_RESCONTEXT + 'components/images/pooled-task-16.png" title="' + this.msg("label.pooledTask") + '"/>'; 275 } 276 } 277 278 elCell.innerHTML = desc; 279 }, 280 281 /** 282 * Task info custom datacell formatter 283 */ 284 renderCellTaskInfo: function MyTasks_onReady_renderCellTaskInfo(elCell, oRecord, oColumn, oData) 285 { 286 var data = oRecord.getData(), 287 desc = ""; 288 289 if (data.isInfo) 290 { 291 desc += '<div class="empty"><h3>' + data.title + '</h3>'; 292 desc += '<span>' + data.description + '</span></div>'; 293 } 294 else 295 { 296 var taskId = data.id, 297 message = data.properties["bpm_description"], 298 dueDateStr = data.properties["bpm_dueDate"], 299 dueDate = dueDateStr ? Alfresco.util.fromISO8601(dueDateStr) : null, 300 today = new Date(), 301 type = data.title, 302 status = data.properties["bpm_status"], 303 assignee = data.owner; 304 305 // if there is a property label available for the status use that instead 306 if (data.propertyLabels && Alfresco.util.isValueSet(data.propertyLabels["bpm_status"], false)) 307 { 308 status = data.propertyLabels["bpm_status"]; 309 } 310 // if message is the same as the task type show the <no message> label 311 if (message == type) 312 { 313 message = this.msg("workflow.no_message"); 314 } 315 316 var messageDesc = '<h3><a href="' + $siteURL('task-edit?taskId=' + taskId + '&referrer=tasks') + '" class="theme-color-1" title="' + this.msg("title.editTask") + '">' + $html(message) + '</a></h3>', 317 dateDesc = dueDate ? '<h4><span class="' + (today > dueDate ? "task-delayed" : "") + '" title="' + 318 this.msg("title.dueOn", Alfresco.util.formatDate(dueDate, "longDate")) + '">' + Alfresco.util.formatDate(dueDate, "longDate") + '</span></h4>' : "", 319 statusDesc = '<div title="' + this.msg("title.taskSummary", type, status) + '">' + this.msg("label.taskSummary", type, status) + '</div>', 320 unassignedDesc = ''; 321 322 if (!assignee || !assignee.userName) 323 { 324 unassignedDesc = '<span class="theme-bg-color-5 theme-color-5 unassigned-task">' + this.msg("label.unassignedTask") + '</span>'; 325 } 326 desc = messageDesc + dateDesc + statusDesc + unassignedDesc; 327 } 328 329 elCell.innerHTML = desc; 330 }, 331 332 /** 333 * Actions custom datacell formatter 334 */ 335 renderCellActions:function MyTasks_onReady_renderCellActions(elCell, oRecord, oColumn, oData) 336 { 337 var data = oRecord.getData(), 338 desc = ""; 339 340 if (data.isInfo) 341 { 342 oColumn.width = 0; 343 Dom.setStyle(elCell, "width", oColumn.width + "px"); 344 Dom.setStyle(elCell.parentNode, "width", oColumn.width + "px"); 345 } 346 else 347 { 348 if (data.isEditable) 349 { 350 desc += '<a href="' + $siteURL('task-edit?taskId=' + data.id + '&referrer=tasks') + '" class="edit-task" title="' + this.msg("title.editTask") + '"> </a>'; 351 } 352 desc += '<a href="' + $siteURL('task-details?taskId=' + data.id + '&referrer=tasks') + '" class="view-task" title="' + this.msg("title.viewTask") + '"> </a>'; 353 } 354 355 elCell.innerHTML = desc; 356 } 357 358 }); 359 })(); 360