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