ddraper

Customizing the Share Header Menu (Part 2)

Blog Post created by ddraper on Sep 6, 2013

Introduction

In my last post I explained the basic differences between the old (4.1) and new (4.2) Share header bars. In this post I'm going to provide a slightly more complex example that demonstrates the following:

 

  • How to create a custom widget by extending an existing widget in the Alfresco library
  • How to configure additional widget library packages in Surf
  • How to insert that custom widget into the new header


The current header menu features a 'Sites' drop-down menu that allows you to quickly return to one of the last few sites that you previously visited. The example extension I'm doing to demonstrate (provided in full in this JAR file) will update the 'Sites' drop-down menu to convert each recent site link into a cascading menu that allows the user to go straight to a specific page within the site (e.g. the Document Library or Wiki).

 

Recent Sites

I've personally found the Recent Sites list an incredibly valuable addition in my day-to-day development and testing of Share. The recent sites are stored in each users' preferences and are updated as they visit different sites. As well as appearing in the header menu they also are available for selection in many of the file pickers (e.g. 'Copy' 'Move', etc). Only the last 5 sites are shown by default but this can be changed by updating the 'max-recent-sites' element found in the 'share-config.xml' file.

 

Screenshot showing the recent sites in the Sites drop-down menu

 

The Sites Menu

The 'Sites' drop-down is unlike the other items in the menu as it is generated asynchronously when the user clicks on it. This provides a very small performance enhancement as it is unlikely as a user will want to access the menu on every page they visit. Similarly the 'Favourites' cascade menu isn't populated until a user actually clicks on it.

 

This functionality is too complex to define in a basic JSON model so it is controlled by the widget 'alfresco/header/AlfSitesMenu'. It is important to note that the all of the items within the 'Sites' menu are still built in exactly the same way, using exactly the same widgets that are used in the JSON model.

 

To achieve our use case we will need to customize the 'alfresco/header/AlfSitesMenu' widget. This can be achieved in two different ways:

 

  1. By changing the default configuration (which I'll cover in a future post)
  2. By extending the default widget, overriding some of it's functions and then replacing the default widget with the customization.

 

Extending a Widget

We're going to create a new widget called 'blogs/BlogSiteMenu' and we're going to place this widget in the 'META-INF/js' folder of the JAR that we're going to build (as this is the only location that Surf is able to load resources from within JAR files). I've previously described custom widget creation in this blog post but here is a recap of the basic steps with a focus on extending an existing widget.

 

Create the following file in the JAR: 'META-INF/js/blogs/BlogSiteMenu.js' and add the following code to it:

// Define module requirements and callback...
define(['dojo/_base/declare','alfresco/header/AlfSitesMenu'],
       function(declare, AlfSitesMenu) {

  // Module returns a new widget that extends AlfSitesMenu
  return declare([AlfSitesMenu], {
   
// Override the '_addMenuItem' function of AlfSitesMenu...
    _addMenuItem: function(group, widget, index) {
       this.inherited(arguments);
    }
  });
});

 

This code is the absolute minimum required to define a new widget that extends an existing one. The 'define' statement declares the dependent modules and passes them as arguments to a callback function that will be executed when the module is required.

 

The callback function declares a new widget that extends the 'alfresco/header/AlfSitesMenu' widget (which has been assigned to the 'AlfSitesMenu' argument). This new widget overrides the '_addMenuItem' function.

 

The function override simply calls the inherited function (i.e. calls the version defined in 'alfresco/header/AlfSitesMenu') so doesn't actually achieve anything... but the point is to illustrate how to create the extension. The full source is contained in the JAR file which you should download and read through (even if you don't deploy it) - this isn't a tutorial on writing JavaScript !! ;-)

 

Declaring Packages in Surf

Our custom widget is defined in the 'blogs' package (the part of the path that we're going to consider as the package root) and we need to add this to the Surf configuration so that the Dojo AMD loader can locate it.

 

Edit the '<tomcat-home>webapps/share/WEB-INF/surf.xml' configuration file and look for the 'dojo-pages' element. Within this element you'll find a list of packages and its here that you will need to add the location of the 'blogs' package as shown in the example below:

<dojo-pages>
   <bootstrap-file>/res/js/lib/dojo-1.9.0/dojo/dojo.js</bootstrap-file>
   <page-widget>alfresco/core/Page</page-widget>
   <base-url>/res/</base-url>
   <packages>
      <package name='dojo' location='js/lib/dojo-1.9.0/dojo'/>
      <package name='dijit' location='js/lib/dojo-1.9.0/dijit'/>
      <package name='dojox' location='js/lib/dojo-1.9.0/dojox'/>
      <package name='alfresco' location='js/alfresco'/>
      <package name='blogs' location='js/blogs'/>
   </packages>
</dojo-pages>

 

Swapping in the Custom Widget

The previous post provided detailed instructions on how to create the extension module so I'm going to jump straight into working with the 'share-header.get.js' JavaScript controller extension. To replace the default 'Sites' menu widget with our own we simply need to add the following code:

// Find the 'Sites' menu...
var sitesMenu = widgetUtils.findObject(model.jsonModel, 'id', 'HEADER_SITES_MENU');
if (sitesMenu != null)
{
  // Change the widget to our custom menu...
  sitesMenu.name = 'blogs/BlogSitesMenu';
}

 

The controller extension finds the default sites menu (identified as 'HEADER_SITES_MENU') and then changes the name that defines the module to use to that of our custom widget. When we deploy our module and refresh the page we'll see that the 'Sites' menu has been updated:

 

Screenshot of updated sites menu 1

 

Screenshot of updated sites menu 2

 

Screenshot showing updated menu 3

 

Additional Notes

Hopefully the comments in the JavaScript source should be sufficient for you to understand exactly how the new widget creates the new menus. Extending a widget obviously requires an understanding of the widget being extended and a good knowledge of JavaScript.

 

Although I've used other Dojo modules in the code it's not mandatory to do so. It's important to remember that Dojo is merely the tool used for resolving the AMD modules and that you're free to use whatever JavaScript libraries that you choose.

 

You might also note that the JAR file contains a new WebScript for retrieving the site page information. The majority of the work is actually done in the 'share-header.lib.js' file that is imported at the beginning of the 'site-pages.get.js' file and provides another example of how we're trying to make it easy for 3rd parties to re-use Alfresco code.

 

Summary

This tutorial should have demonstrated that you are not limited to any configuration schema when customizing the new Share header. The Surf framework now allows you to easily plug-in completely custom JavaScript code into Share which allows you to make fine-grained changes to existing code or to add entirely new functionality.

Outcomes