Blog Post

...

Alfresco: extend Share javascript component

There is very common task that many developers face during Alfresco Share customization – how to extend client side javascript of a Share component. We all know that Alfresco combines for a component both server side javascript as well as a client side JS. For the first case Alfresco provides Module extension approach to alter server side JS and for the second case – the answer is not so clear. Sure we can modify core JS files directly on a web server, but it’s a bad practice since they can be later overwritten during Alfresco update, so it’s better to use extensions keeping changes in separate files. In this article we’ll take as an example the core Discussions Dashlet and then modify its client side javascript code.

So let’s start with a looking for Discussions Dashlet component, its id and location. For this we can use SurfBug: just add Discussions Dashlet to User Dashboard and then enable SurfBug. In the result we get the path of the component files org.alfresco.components.dashlets and its id forum-summary. Please navigate to share\WEB-INF\classes\alfresco\site-webscripts\ having just found path appended and you’ll see there are forum-summary.get.* files, here forum-summary.get.js – is a server side JS that get interpreted by Alfresco Surf engine. Let’s take a look into it: it instantiates 3 widgets, one of them is the Discussions Dashlet:

var forumSummary = {
  id: "ForumSummary",
  name: "Alfresco.dashlet.ForumSummary",
  options : {
	 siteId : (page.url.templateArgs.site != null) ? page.url.templateArgs.site : "",
	 searchRootNode : (config.scoped['RepositoryLibrary']['root-node']).value,
	 filters : model.filters,
	 regionId : args['region-id']
  }
};

The name attribute in this snippet refers by ID to client side Javascript classes (i.e. constructor functions). In this way the widget is created taking JS as a source of UI. Now let’s find this javascript class by "Alfresco.dashlet.ForumSummary" ID or simply looking to forum-summary.get.html.ftl. It’s a webapps\share\components\dashlets\forum-summary.js:

(function() {
   /* a part of code skipped*/

   Alfresco.dashlet.ForumSummary = function ForumSummary_constructor(htmlId) {
      Alfresco.dashlet.ForumSummary.superclass.constructor.call(this, "Alfresco.dashlet.ForumSummary", htmlId, ["container", "datasource", "datatable"]);
      // Services
      this.services.preferences = new Alfresco.service.Preferences();
      return this;
   };

   YAHOO.extend(Alfresco.dashlet.ForumSummary, Alfresco.component.Base, {
	/* a part of code skipped*/
   });
})();

Having the JS that generates the UI of the Discussions Dashlet, let’s slightly modify its layout. In order not to change this out-of-the-box Alfresco file we’ll extend the class within it. To make this happen – create a new file custom-discussions-dashlet.js in META_INF/components directory located in any jar-file of the Share web application. Then add custom class, having buildDescription() function (the one that performs required UI rendering in core forum-summary.js) overridden:

(function() {

   Alfresco.dashlet.CustomForumSummary = function CustomForumSummary_constructor(htmlId){
      Alfresco.dashlet.CustomForumSummary.superclass.constructor.call(this, htmlId);
      return this;
   };

   /**
    * Extended from ForumSummary
    */
   YAHOO.extend(Alfresco.dashlet.CustomForumSummary, Alfresco.dashlet.ForumSummary, {

      buildDescription: function ForumSummary_buildDescription(elCell, oRecord, oColumn, oData) {
		elCell.innerHTML = "<div>Custom discussion</div>";	
      }	 
      
   });
})();

On this step the new class is created, now we need to add reference to it in the dashlet. In forum-summary.get.html.ftl there are links to Javascripts in the header. Using Share module extensions we can add our link to just created JS class. The ftl extension will look líke forum-summary.get.html.ftl:

<#-- Add a Javascript declaration -->
<@markup id="forum-custom-js"  target="js" action="after">
	<@script src="${url.context}/res/components/custom-discussions-dashlet.js" group="dashlets" />
</@>

Please note that we do an after extension, not replace. We can’t remove a reference to the parent of our custom class. Finally, there’s left one thing – we need to change the dashlet’s code, so custom class could be initiated. For this, we do a replacement of the Discussions widget in widget array with a custom one. Extended Forum-summary.js looks as following:

// replace ForumSummary with CustomForumSummary
for (i = 0; i < model.widgets.length; i++) { 
    if (model.widgets[i].id == 'ForumSummary') {
        model.widgets.splice(i, 1);
        var customForumSummary = {
                id : "customForumSummary",
                name : "Alfresco.dashlet.CustomForumSummary",
                options : {
                    siteId : (page.url.templateArgs.site != null) ? page.url.templateArgs.site
                            : "",
                    searchRootNode : (config.scoped['RepositoryLibrary']['root-node']).value,
                    filters : model.filters,
                    regionId : args['region-id']
                }
            };      
        model.widgets.push(customForumSummary);
    }
}

In this snippet we can see how our custom widget is created using name attribute as reference to the class and then how it replaces the core widget.

That’s it, I hope my post was helpful. Thank you for interest!

Comments (9)

Tags: alfresco


Comments:

...

Damree Ilyaad Mar 01, 2017 at 14:03 #

Hi Stanislav, Great article. I am currently facing a similar problem. I customized documentlist.js. But I dont know in which folder to put it in my share archtype project (Alfresco 5.1). Any help from you?

...

Stanislav Mar 05, 2017 at 17:01 #

Hi Damree, thanks! You can put customized js file anywhere you want, e.g. into SHARE/components. Just specify the path in *.ftl

...

Ivab Mar 28, 2017 at 18:37 #

Great article. In order to simplify the Forum-summary.js you could use widgetUtils to find the json object and change it directly, without push it again in the model.

...

Stanisalv Mar 29, 2017 at 09:10 #

Thanks Ivab. widgetUtils did their job badly, that's why custom method was written.

...

eswbitto Apr 21, 2017 at 23:33 #

Hello Stanislav, I have looked over your tutorial and I'm quite please with it. I was wondering if the same approach could be done for the Activities dashlet for both the personal one and the site dashlet. Essentially my goal is to only allow users to see their own activities rather than all members on the site (for privacy issues). I have been able to create some xml files that filter results to a specific group. I can also modify the js files in the exploded share.war file. So that the default is not set to "all" and will default to "mine". So my adjustments work that way. I just want to be able to implement it the correct way. Thoughts?

...

Stanislav Apr 26, 2017 at 09:17 #

Hello eswbitto. Your approach looks good, the only drawback I see is that you make changes on the Alfresco out-of-the-box JS-file within the exploded share.war. It's not a good practice since after any Alfresco update, your changes may be overritten. So maybe it's worth to extend this JS-file and keep your changes in the dir that won't be rewritten on some Alfresco update.

...

monica Feb 02, 2018 at 09:36 #

Hello Stanislav, Do you have any idea how to extend/override any file from a jar(eg. "aikau-1.0.101.10.jar") within the exploded share.war.

...

Stanislav May 01, 2018 at 18:48 #

Hey Monica, not sure about aikau.jar, but other Alfresco jars that include Alfresco JSs and configs can be extended in the same way as described in this post.

...

progressdll Sep 28, 2018 at 09:03 #

Hello eswbitto. I implemented to change the userfilter this way. (function() { /** * Dashboard custom Activities constructor. * * @param {String} htmlId The HTML id of the parent element * @return {Alfresco.dashlet.Activities} The new component instance * @constructor */ Alfresco.dashlet.CustomActivities = function CustomActivities_constructor(htmlId) { Alfresco.dashlet.CustomActivities.superclass.constructor.call(this, htmlId); return this; }; YAHOO.extend(Alfresco.dashlet.CustomActivities, Alfresco.dashlet.Activities); Alfresco.dashlet.CustomActivities.prototype.populateActivityList = function Activities_populateActivityList(dateFilter, userFilter, activityFilter) { alert("reseting filter" + userFilter); userFilter = "mine"; Alfresco.dashlet.CustomActivities.superclass.populateActivityList.call(this,dateFilter,userFilter,activityFilter); }; })();

Leave a Comment