ddraper

Customizing the Share Header Menu (Part 1)

Blog Post created by ddraper on Sep 4, 2013

Introduction

Now that Alfresco Community 4.2d has been released I thought it would be useful to begin providing some examples of how to customize the new header bar. The new header bar is the first feature in Share to use the updated widget processing framework provided by Surf. In this post I will demonstrate how to update the default menu to convert the 'Admin Tools' link into a drop-down menu with links to all of the individual Admin Console pages. In later posts I'll show how to remove menu items and how to add custom widgets into the header.

 

Comparing the Headers

Let's first compare the old and new header menus...

 

Screenshot of the header from Alfresco Share 4.1

 

Screenshot of the Alfresco Share 4.2 header

 

As well as the obvious stylistic differences there are some major implementation differences. The original header was rendered by a combination of the 'header', 'title' and 'navigation' regions whereas these have been replaced by a single region called 'share-header'.

 

This new region is bound to the 'share-header.get' WebScript which uses the previously described approach to define the JSON model of widgets that comprise the header.

 

The structure of the old header was defined in the 'share-config.xml' configuration file whereas the new header is entirely defined by the 'share-header.get' WebScript's JavaScript controller. It is possible to render the header using the configuration from the 'share-config.xml' file by changing the 'legacy-mode-enabled' element value from 'false' to 'true'.

 

Creating the Extension Module

To customize the header you should follow the approach described in this blog post to extend the JavaScript controller of the 'share-header.get' WebScript. To briefly recap, follow these steps:

    1. Create a JAR containing the following folder structures:
      1. /alfresco/site-data/extensions
      2. /alfresco/site-webscripts
    2. In the '/alfresco/site-data/extensions' folder create a file called 'blog-extension.xml' (you can call it anything you like of course!)
    3. In the 'alfresco/site-webscripts' folder create a package path for the controller extension (e.g. 'blogs/admin-menu' - but again you can use any package you like)
    4. In the 'alfresco/site-webscripts/blogs/admin-menu' folder create a file called 'share-header.get.js'

 

Your 'blog-extension.xml' file should contain the following:

 

<extension>
  <modules>
    <module>
      <id>Update Admin Menu</id>
      <version>1.0</version>
      <customizations>
        <customization>
          <targetPackageRoot>org.alfresco.share.header</targetPackageRoot>
          <sourcePackageRoot>blogs.admin-menu</sourcePackageRoot>
        </customization>
      </customizations>
    </module>
  </modules>
</extension>

 

The 'targetPackageRoot' element identifies the location of the 'share-header.get' WebScript and the 'sourcePackageRoot' element identifies the location of your extension file. You now have the basic elements required to customize the header - everything else will be done in the '/alfresco/site-webscripts/blogs/admin-menu/share-header.get.js' file.

 

Customizing the Header

The purpose of a JavaScript controller is to construct a model object that the FreeMarker template uses when generating a fragment of DOM for the page. The model object created by the default JavaScript controller is made available to each extension controller before it is passed to the FreeMarker template and this provides them the opportunity to change the model before it is processed.

 

The model object is assigned an attribute called 'jsonModel' with a value that is a JSON object containing all the widgets to render in the header. Each widgets is given a unique 'id' attribute so that they can easily be found by extensions using the 'widgetUtils.findObject' helper function.

 

In this example we're going modify the 'alfresco/menus/AlfMenuBarItem' widget that creates the 'Admin Tools' menu item. The original definition of this can be found in the 'share-header.lib.js' library file (that is imported by 'share-header.get.js') and is:

 

{
  id: 'HEADER_ADMIN_CONSOLE',
  name: 'alfresco/menus/AlfMenuBarItem',
  config: {
    label: 'header.menu.admin.label',
    targetUrl: 'console/admin-console/application'
  }
}

We can work with this widget by adding the following to our 'share-header.get.js' extension file:

var adminMenu = widgetUtils.findObject(model.jsonModel, 'id', 'HEADER_ADMIN_CONSOLE');

if (adminMenu != null)
{
  adminMenu.name = 'alfresco/header/AlfMenuBarPopup';
  delete adminMenu.config.targetUrl;
}

 

This will find the widget (which will only be present in the model if the currently logged in user is the Admin) and then change the widget definition's 'name' attribute to be 'alfresco/header/AlfMenuBarPopup' which will convert it into a drop-down menu. We then delete the 'targetUrl' attribute because it is not required.

 

The final step is to add in the contents of the drop-down menu (I'm only going to show the first sub-group defined but you can find a JAR file containing all the source here):

 

var adminMenu = widgetUtils.findObject(model.jsonModel, 'id', 'HEADER_ADMIN_CONSOLE');
if (adminMenu != null)
{
  adminMenu.name = 'alfresco/header/AlfMenuBarPopup';
  delete adminMenu.config.targetUrl;
  adminMenu.config.widgets = [
    {
      name: 'alfresco/menus/AlfMenuGroup',
      config: {
        label: 'Tools',
        widgets: [
          {
            name: 'alfresco/header/AlfMenuItem',
            config:
            {
              label: 'Application',
              targetUrl: 'console/admin-console/application'
            }
          },
          {
            name: 'alfresco/header/AlfMenuItem',
            config:
            {
              label: 'Category Manager',
              targetUrl: 'console/admin-console/category-manager'
            }
          }
        ]
      }
    }
  ];
}

 

Here we're adding a group with the label 'Tools' which contains two menu items labelled 'Application' and 'Category Manager' which each have a page relative (that is relative to '/share/page') URL for the page that they represent.

 

Copy the JAR to the '<tomcat-home>/webapps/share/WEB-INF/lib', restart your server and go to the 'share/page/modules/deploy' page and deploy your new module.

 

Screenshot showing the Module Deployment page

 

Login to Share as 'Admin' and you'll see that the 'Admin Tools' menu has now been converted into a drop-down menu (the screenshot shows the extension provided in my sample JAR):

 

Screenshot showing the updated "Admin Tools" menu

 

Summary

Although I haven't yet explained exactly what all the widget definitions mean, which widgets are available or how you can configure each of them... this example should at least show you how you can easily update the new header to suit your needs.

You may wonder how exactly this is more beneficial than updating the menu via configuration? The main advantages are as follows:

    1. It is possible to target specific parts of the menu without including the entire menu definition. This means that multiple definitions can be deployed together that independently alter the menu without overriding the each others changes
    2. It is possible to to leverage the existing extension module features to dynamically alter the menu based on a variety of criteria including user group, page context, user privileges, etc. by deploying modules with evaluators.
    3. It is possible to dynamically add and remove features without restarting the server.
    4. There is complete flexibility in what gets added to the header - you are not constrained to any particular widget set and can easily add custom widgets that are entirely new or extend existing widgets in the Alfresco library.
    5. It's very easy to re-use all or parts of the existing menu when creating new pages or applications.


    Hopefully this information is useful as a starting point. In my next post I'll demonstrate how you can extend an existing widget and use it in the menu.

    Outcomes