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 MySites component.
 22  *
 23  * @namespace Alfresco.dashlet
 24  * @class Alfresco.dashlet.MySites
 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 
 40    /**
 41     * Use the getDomId function to get some unique names for global event handling
 42     */
 43    var favEventClass = Alfresco.util.generateDomId(null, "fav-site"),
 44       imapEventClass = Alfresco.util.generateDomId(null, "imap-site"),
 45       deleteEventClass = Alfresco.util.generateDomId(null, "del-site");
 46 
 47    /**
 48     * Preferences
 49     */
 50    var PREFERENCES_SITES_DASHLET_FILTER = "org.alfresco.share.sites.dashlet.filter";       
 51 
 52    /**
 53     * Dashboard MySites constructor.
 54     *
 55     * @param {String} htmlId The HTML id of the parent element
 56     * @return {Alfresco.dashlet.MySites} The new component instance
 57     * @constructor
 58     */
 59    Alfresco.dashlet.MySites = function MySites_constructor(htmlId)
 60    {
 61       Alfresco.dashlet.MySites.superclass.constructor.call(this, "Alfresco.dashlet.MySites", htmlId, ["button", "container", "datasource", "datatable", "animation"]);
 62 
 63       // Initialise prototype properties
 64       this.preferencesService = new Alfresco.service.Preferences();
 65       this.sites = [];
 66       this.createSite = null;
 67 
 68       // Listen for events from other components
 69       YAHOO.Bubbling.on("siteDeleted", this.onSiteDeleted, this);
 70 
 71       return this;
 72    };
 73 
 74    YAHOO.extend(Alfresco.dashlet.MySites, Alfresco.component.Base,
 75    {
 76       /**
 77        * Preferences service to get and set the dashlet's site filter
 78        *
 79        * @property preferencesService
 80        * @type Alfresco.service.Preferences
 81        * @private
 82        */
 83       preferencesService: [],
 84 
 85       /**
 86        * Site data
 87        *
 88        * @property sites
 89        * @type array
 90        * @private
 91        */
 92       sites: [],
 93 
 94       /**
 95        * CreateSite module instance.
 96        *
 97        * @property createSite
 98        * @type Alfresco.module.CreateSite
 99        */
100       createSite: null,
101 
102       /**
103        * Object container for initialization options
104        *
105        * @property options
106        * @type object
107        */
108       options:
109       {
110          /**
111           * Flag if IMAP server is enabled
112           *
113           * @property imapEnabled
114           * @type boolean
115           * @default false
116           */
117          imapEnabled: false
118       },
119 
120       /**
121        * Date drop-down changed event handler
122        * 
123        * @method onTypeFilterChanged
124        * @param p_sType {string} The event
125        * @param p_aArgs {array}
126        */
127       onTypeFilterChanged: function MySites_onTypeFilterChanged(p_sType, p_aArgs)
128       {
129          var menuItem = p_aArgs[1];
130          if (menuItem)
131          {
132             this.widgets.type.set("label", menuItem.cfg.getProperty("text"));
133          }
134          this.widgets.type.value = menuItem.value;
135          this.onTypeFilterClicked();
136       },
137 
138       /**
139        * Type button clicked event handler
140        *
141        * @method onTypeFilterClicked
142        * @param p_oEvent {object} Dom event
143        */
144       onTypeFilterClicked: function MySites_onTypeFilterClicked(p_oEvent)
145       {
146          // Save preferences and load sites afterwards
147          this.preferencesService.set(PREFERENCES_SITES_DASHLET_FILTER, this.widgets.type.value, { successCallback:
148          {
149             fn: this.loadSites,
150             scope: this
151          }});
152       },
153 
154       loadSites: function()
155       {
156          // Load sites
157          Alfresco.util.Ajax.request(
158          {
159             url: Alfresco.constants.PROXY_URI + "api/people/" + encodeURIComponent(Alfresco.constants.USERNAME) + "/sites",
160             successCallback:
161             {
162                fn: this.onSitesLoaded,
163                scope: this
164             }
165          });
166       },
167 
168       /**
169        * Retrieve user preferences
170        *
171        * @method getPrefs
172        * @param p_response {object} Response from "api/people/{userId}/sites" query
173        */
174       onSitesLoaded: function MySites_getPrefs(p_response)
175       {
176          // Save sites form response
177          var items = p_response.json;
178 
179          // Load preferences (after which the appropriate sites will be displayed) 
180          Alfresco.util.Ajax.request(
181          {
182             url: Alfresco.constants.PROXY_URI + "api/people/"+ encodeURIComponent(Alfresco.constants.USERNAME) + "/preferences?pf=org.alfresco.share.sites",
183             successCallback:
184             {
185                fn: this.onPreferencesLoaded,
186                scope: this,
187                obj: items
188             }
189          });
190       },
191 
192       /**
193        * Process response from sites and preferences queries
194        *
195        * @method onSitesUpdate
196        * @param p_response {object} Response from "api/people/{userId}/preferences" query
197        * @param p_items {object} Response from "api/people/{userId}/sites" query
198        */
199       onPreferencesLoaded: function MySites_onSitesUpdate(p_response, p_items)
200       {
201          var favSites = {},
202             imapfavSites = {},
203             siteManagers, i, j, k, l,
204             ii = 0;
205 
206          // Save preferences
207          if (p_response.json.org)
208          {
209             favSites = p_response.json.org.alfresco.share.sites.favourites;
210             imapfavSites = p_response.json.org.alfresco.share.sites.imapFavourites;
211          }
212 
213          // Select the preferred filter in the ui
214          var filter = Alfresco.util.findValueByDotNotation(p_response.json, PREFERENCES_SITES_DASHLET_FILTER, "all");
215          if (filter)
216          {
217             this.widgets.type.set("label", this.msg("filter." + filter));
218             this.widgets.type.value = filter;
219          }
220 
221          // Display the toolbar now that we have selected the filter
222          Dom.removeClass(Selector.query(".toolbar div", this.id, true), "hidden");
223 
224          for (i = 0, j = p_items.length; i < j; i++)
225          {
226             p_items[i].isSiteManager = false;
227             siteManagers = p_items[i].siteManagers;
228             for (k = 0, l = siteManagers.length; siteManagers && k < l; k++)
229             {
230                if (siteManagers[k] == Alfresco.constants.USERNAME)
231                {
232                   p_items[i].isSiteManager = true;
233                   break;
234                }
235             }
236 
237             p_items[i].isFavourite = typeof(favSites[p_items[i].shortName]) == "undefined" ? false : favSites[p_items[i].shortName];
238             if (imapfavSites)
239             {
240                p_items[i].isIMAPFavourite = typeof(imapfavSites[p_items[i].shortName]) == "undefined" ? false : imapfavSites[p_items[i].shortName];
241             }
242          }
243 
244          this.sites = [];
245          for (i = 0, j = p_items.length; i < j; i++)
246          {
247             var site =
248             {
249                shortName: p_items[i].shortName,
250                title: p_items[i].title,
251                description: p_items[i].description,
252                isFavourite: p_items[i].isFavourite,
253                isIMAPFavourite: p_items[i].isIMAPFavourite,
254                sitePreset: p_items[i].sitePreset,
255                isSiteManager: p_items[i].isSiteManager
256             };
257 
258             if (this.filterAccept(site))
259             {
260                this.sites[ii] = site;
261                ii++;
262             }
263          }
264 
265          this.sites.sort(function(a, b)
266          {
267             var name1 = a.title ? a.title.toLowerCase() : a.shortName.toLowerCase(),
268                 name2 = b.title ? b.title.toLowerCase() : b.shortName.toLowerCase();
269             return (name1 > name2) ? 1 : (name1 < name2) ? -1 : 0;
270          });
271 
272          var successHandler = function MD__oFC_success(sRequest, oResponse, oPayload)
273          {
274             oResponse.results=this.sites;
275             this.widgets.dataTable.onDataReturnInitializeTable.call(this.widgets.dataTable, sRequest, oResponse, oPayload);
276          };
277 
278          this.widgets.dataSource.sendRequest(this.sites,
279          {
280             success: successHandler,
281             scope: this
282          });
283       },
284 
285       /**
286        * Determine whether a given site should be displayed or not depending on the current filter selection
287        * @method filterAccept
288        * @param site {object} Site object literal
289        * @return {boolean}
290        */
291       filterAccept: function MySites_filterAccept(site)
292       {
293          switch (this.widgets.type.value)
294          {
295             case "all":
296                return true;
297 
298             case "sites":
299                return (site.sitePreset !== "document-workspace" && site.sitePreset !== "meeting-workspace");
300 
301             case "favSites":
302                return (site.isFavourite || (this.options.imapEnabled && site.isIMAPFavourite));
303 
304             case "docWorkspaces":
305                return (site.sitePreset === "document-workspace");
306 
307             case "meetWorkspaces":
308                return (site.sitePreset === "meeting-workspace");
309          }
310          return false;
311       },
312 
313       /**
314        * Fired by YUI when parent element is available for scripting
315        * @method onReady
316        */
317       onReady: function MySites_onReady()
318       {
319          var me = this;
320 
321          // Create Dropdown filter
322          this.widgets.type = new YAHOO.widget.Button(this.id + "-type",
323          {
324             type: "split",
325             menu: this.id + "-type-menu"
326          });
327          this.widgets.type.on("click", this.onTypeFilterClicked, this, true);
328          this.widgets.type.getMenu().subscribe("click", this.onTypeFilterChanged, this, true);
329 
330          // Listen on clicks for the create site link
331          Event.addListener(this.id + "-createSite-button", "click", this.onCreateSiteLinkClick, this, true);
332 
333          // DataSource definition
334          this.widgets.dataSource = new YAHOO.util.DataSource(this.sites,
335          {
336             responseType: YAHOO.util.DataSource.TYPE_JSARRAY
337          });
338 
339          // DataTable column defintions
340          var columnDefinitions =
341          [
342             { key: "siteId", label: "Favourite", sortable: false, formatter: this.bind(this.renderCellFavourite), width: this.options.imapEnabled ? 40 : 20 },
343             { key: "title", label: "Description", sortable: false, formatter: this.bind(this.renderCellName) },
344             { key: "description", label: "Actions", sortable: false, formatter: this.bind(this.renderCellActions), width: 32 }
345          ];
346 
347          // DataTable definition
348          this.widgets.dataTable = new YAHOO.widget.DataTable(this.id + "-sites", columnDefinitions, this.widgets.dataSource,
349          {
350             MSG_EMPTY: this.msg("label.noSites")
351          });
352 
353          // Add animation to row delete
354          this.widgets.dataTable._deleteTrEl = function(row)
355          {
356             var scope = this,
357                trEl = this.getTrEl(row);
358 
359             var changeColor = new YAHOO.util.ColorAnim(trEl,
360             {
361                opacity:
362                {
363                   to: 0
364                }
365             }, 0.25);
366             changeColor.onComplete.subscribe(function()
367             {
368                YAHOO.widget.DataTable.prototype._deleteTrEl.call(scope, row);
369             });
370             changeColor.animate();
371          };
372 
373          /**
374           * Hook favourite site events
375           */
376          var registerEventHandler = function(cssClass, fnHandler)
377          {
378             var fnEventHandler = function MS_oR_fnEventHandler(layer, args)
379             {
380                var owner = YAHOO.Bubbling.getOwnerByTagName(args[1].anchor, "div");
381                if (owner !== null)
382                {
383                   fnHandler.call(me, args[1].target.offsetParent, owner);
384                }
385 
386                return true;
387             };
388             YAHOO.Bubbling.addDefaultAction(cssClass, fnEventHandler);
389          };
390 
391          registerEventHandler(favEventClass, this.onFavouriteSite);
392          registerEventHandler(imapEventClass, this.onImapFavouriteSite);
393          registerEventHandler(deleteEventClass, this.onDeleteSite);
394 
395          // Enable row highlighting
396          this.widgets.dataTable.subscribe("rowMouseoverEvent", this.widgets.dataTable.onEventHighlightRow);
397          this.widgets.dataTable.subscribe("rowMouseoutEvent", this.widgets.dataTable.onEventUnhighlightRow);
398 
399          // Load sites & preferences
400          this.loadSites();
401       },
402 
403       /**
404        * Favourites custom datacell formatter
405        */
406       renderCellFavourite: function MySites_renderCellFavourite(elCell, oRecord, oColumn, oData)
407       {
408          Dom.setStyle(elCell, "width", oColumn.width + "px");
409          Dom.setStyle(elCell.parentNode, "width", oColumn.width + "px");
410 
411          var isFavourite = oRecord.getData("isFavourite"),
412                isIMAPFavourite = oRecord.getData("isIMAPFavourite");
413 
414          var desc = '<div class="site-favourites">';
415          desc += '<a class="favourite-site ' + favEventClass + (isFavourite ? ' enabled' : '') + '" title="' + this.msg("link.favouriteSite") + '"> </a>';
416          if (this.options.imapEnabled)
417          {
418             desc += '<a class="imap-favourite-site ' + imapEventClass + (isIMAPFavourite ? ' imap-enabled' : '') + '" title="' + this.msg("link.imap_favouriteSite") + '"> </a>';
419          }
420          desc += '</div>';
421          elCell.innerHTML = desc;
422       },
423 
424       /**
425        * Name & description custom datacell formatter
426        */
427       renderCellName: function MySites_renderCellName(elCell, oRecord, oColumn, oData)
428       {
429          var siteId = oRecord.getData("shortName"),
430                siteTitle = oRecord.getData("title"),
431                siteDescription = oRecord.getData("description");
432 
433          var desc = '<div class="site-title"><a href="' + Alfresco.constants.URL_PAGECONTEXT + 'site/' + siteId + '/dashboard" class="theme-color-1">' + $html(siteTitle) + '</a></div>';
434          desc += '<div class="site-description">' + $html(siteDescription) + '</div>';
435 
436          elCell.innerHTML = desc;
437       },
438 
439       /**
440        * Actions custom datacell formatter
441        */
442       renderCellActions: function MySites_renderCellActions(elCell, oRecord, oColumn, oData)
443       {
444          Dom.setStyle(elCell, "width", oColumn.width + "px");
445          Dom.setStyle(elCell.parentNode, "width", oColumn.width + "px");
446 
447          var isSiteManager = oRecord.getData("isSiteManager"),
448                desc = "";
449 
450          if (isSiteManager)
451          {
452             desc = '<a class="delete-site ' + deleteEventClass + '" title="' + this.msg("link.deleteSite") + '"> </a>';
453          }
454          elCell.innerHTML = desc;
455       },
456 
457       /**
458        * Adds an event handler for bringing up the delete site dialog for the specific site
459        *
460        * @method onDeleteSite
461        * @param row {object} DataTable row representing file to be actioned
462        */
463       onDeleteSite: function MySites_onDeleteSite(row)
464       {
465          var record = this.widgets.dataTable.getRecord(row);
466 
467          // Display the delete dialog for the site
468          Alfresco.module.getDeleteSiteInstance().show(
469          {
470             site: record.getData()
471          });
472       },
473 
474       /**
475        * Fired by DeleteSite module when a site has been deleted.
476        *
477        * @method onSiteDeleted
478        * @param layer {object} Event fired (unused)
479        * @param args {array} Event parameters (unused)
480        */
481       onSiteDeleted: function MySites_onSiteDeleted(layer, args)
482       {
483          var site = args[1].site,
484             siteId = site.shortName;
485 
486          // Find the record corresponding to this site
487          var record = this._findRecordByParameter(siteId, "shortName");
488          if (record !== null)
489          {
490             this.widgets.dataTable.deleteRow(record);
491          }
492       },
493 
494       /**
495        * Adds an event handler that adds or removes the site as favourite site
496        *
497        * @method onFavouriteSite
498        * @param row {object} DataTable row representing file to be actioned
499        */
500       onFavouriteSite: function MySites_onFavouriteSite(row)
501       {
502          var record = this.widgets.dataTable.getRecord(row),
503             site = record.getData(),
504             siteId = site.shortName;
505 
506          site.isFavourite = !site.isFavourite;
507 
508          this.widgets.dataTable.updateRow(record, site);
509 
510          // Assume the call will succeed, but register a failure handler to replace the UI state on failure
511          var responseConfig =
512          {
513             failureCallback:
514             {
515                fn: function MS_oFS_failure(event, obj)
516                {
517                   // Reset the flag to it's previous state
518                   var record = obj.record,
519                      site = record.getData();
520 
521                   site.isFavourite = !site.isFavourite;
522                   this.widgets.dataTable.updateRow(record, site);
523                   Alfresco.util.PopupManager.displayPrompt(
524                   {
525                      text: this.msg("message.siteFavourite.failure", site.title)
526                   });
527                },
528                scope: this,
529                obj:
530                {
531                   record: record
532                }
533             },
534             successCallback:
535             {
536                fn: function MS_oFS_success(event, obj)
537                {
538                   var record = obj.record,
539                      site = record.getData();
540 
541                   YAHOO.Bubbling.fire(site.isFavourite ? "favouriteSiteAdded" : "favouriteSiteRemoved", site);
542                },
543                scope: this,
544                obj:
545                {
546                   record: record
547                }
548             }
549          };
550 
551          this.preferencesService.set(Alfresco.service.Preferences.FAVOURITE_SITES + "." + siteId, site.isFavourite, responseConfig);
552       },
553 
554       /**
555        * Adds an event handler that adds or removes the site as favourite site
556        *
557        * @method _addImapFavouriteHandling
558        * @param row {object} DataTable row representing file to be actioned
559        */
560       onImapFavouriteSite: function MySites_onImapFavouriteSite(row)
561       {
562          var record = this.widgets.dataTable.getRecord(row),
563             site = record.getData(),
564             siteId = site.shortName;
565 
566          site.isIMAPFavourite = !site.isIMAPFavourite;
567 
568          this.widgets.dataTable.updateRow(record, site);
569 
570          // Assume the call will succeed, but register a failure handler to replace the UI state on failure
571          var responseConfig =
572          {
573             failureCallback:
574             {
575                fn: function MS_oIFS_failure(event, obj)
576                {
577                   // Reset the flag to it's previous state
578                   var record = obj.record,
579                      site = record.getData();
580 
581                   site.isIMAPFavourite = !site.isIMAPFavourite;
582                   this.widgets.dataTable.updateRow(record, site);
583                   Alfresco.util.PopupManager.displayPrompt(
584                   {
585                      text: this.msg("message.siteFavourite.failure", site.title)
586                   });
587                },
588                scope: this,
589                obj:
590                {
591                   record: record
592                }
593             }
594          };
595 
596          this.preferencesService.set(Alfresco.service.Preferences.IMAP_FAVOURITE_SITES + "." + siteId, site.isIMAPFavourite, responseConfig);
597       },
598 
599       /**
600        * Fired by YUI Link when the "Create site" label is clicked
601        * @method onCreateSiteLinkClick
602        * @param event {domEvent} DOM event
603        */
604       onCreateSiteLinkClick: function MySites_onCreateSiteLinkClick(event)
605       {
606          Alfresco.module.getCreateSiteInstance().show();
607          Event.preventDefault(event);
608       },
609 
610       /**
611        * Searches the current recordSet for a record with the given parameter value
612        *
613        * @method _findRecordByParameter
614        * @param p_value {string} Value to find
615        * @param p_parameter {string} Parameter to look for the value in
616        */
617       _findRecordByParameter: function MySites__findRecordByParameter(p_value, p_parameter)
618       {
619         var recordSet = this.widgets.dataTable.getRecordSet();
620         for (var i = 0, j = recordSet.getLength(); i < j; i++)
621         {
622            if (recordSet.getRecord(i).getData(p_parameter) == p_value)
623            {
624               return recordSet.getRecord(i);
625            }
626         }
627         return null;
628       }
629    });
630 })();