You are here

Customizing the Sites menu (Aikau)

This tutorial shows you how to customize the Alfresco Share header menu Sites item.
You should complete the previous tutorial before attempting this one.
In this tutorial you will customize the Share main menu so that the Sites menu item includes additional functionality. The Sites menu item is modified so that if a site under Recent Sites is selected, then the individual pages of that site are displayed as additional menu items, allowing you to navigate directly to a specific site page. Individual pages displayed include Site Dashboard, Document Library and Site Members.
  1. In the customize-share-header-menu/src/main/amp/web/js folder create a new folder called tutorials.
  2. In the new folder, create a new file SitesMenu.js with the following contents:

                            
     define(["dojo/_base/declare",
            "alfresco/header/AlfSitesMenu",
            "alfresco/core/CoreXhr",
            "dojo/_base/lang",
            "dojo/_base/array",
            "dojo/aspect",
            "dijit/registry",
            "alfresco/menus/AlfMenuGroup",
            "alfresco/header/AlfMenuItem",
            "alfresco/header/AlfCascadingMenu",
            "dojo/dom-style",
            "dijit/popup"], 
            function(declare, AlfSitesMenu, AlfXhr, lang, array, aspect, registry, AlfMenuGroup, AlfMenuItem, AlfCascadingMenu, domStyle, popup) {
       
       return declare([AlfSitesMenu, AlfXhr], {
          
          /**
           * Adds an individual menu item.
           * 
           * @instance
           * @param {object} group The group to add the menu item to
           * @param {object} widget The menu item to add
           * @param {integer} index The index to add the menu item at.
           */
          _addMenuItem: function tutorials_SitesMenu___addMenuItem(group, widget, index) {
             if (group == this.recentGroup)
             {
                // Create a basic group for holding the favourites...
                 var sitePageList = new AlfMenuGroup({
                   widgets: [{
                      name: "alfresco/header/AlfMenuItem",
                      config: {
                         label: "Loading..."
                      }
                   }]
                });
                
                // Create the cascading menu item to popout the favourites list...
                var siteCascade = new AlfCascadingMenu(widget.config);
                
                // Set up the sites cascading popup to asynchronously load the pages upon request...
                siteCascade.popup.onOpen = dojo.hitch(this, "loadSitePages", widget.config.siteShortName, sitePageList);
                
                // Add the list into the cascading menu...
                siteCascade.popup.addChild(sitePageList);
    
                // Add the default menu items...
                group.addChild(siteCascade);
             }
             else
             {
                // If we're not adding a Recent Sites menu item then just default to the normal action
                this.inherited(arguments);
             }
          },
          
          /**
           * This variable will be used to keep track of which sites pages have been loaded. It is initialised
           * to null and populated as page data is loaded.
           * 
           * @instance
           * @type {object}
           * @default null
           */
          _sitePagesLoaded: null,
          
          /**
           * This function is hitched to the each sites cascading menu so that when it is clicked a XHR request is made
           * to retrieve the pages for the site.
           * 
           * @instance
           * @param {string} siteShortName The short name of the site to load the pages for
           * @param {object} sitePageList A reference to the alfresco/menus/AlfMenuGroup widget that the site pages should be added to
           */
          loadSitePages: function tutorials_SitesMenu__loadSitePages(siteShortName, sitePageList) {
             if (this._sitePagesLoaded != null && this._sitePagesLoaded[siteShortName] == true)
             {
                this.alfLog("log", "Site pages already loaded for: " + siteShortName);
             }
             else
             {
                this.alfLog("log", "Loading pages for site: " + siteShortName);
                this.serviceXhr({url : Alfresco.constants.URL_SERVICECONTEXT + "tutorials/site/" + siteShortName,
                                 method: "GET",
                                 siteShortName: siteShortName, // Including the site short name will make it available in the "sitePagesLoaded" callback "originalRequestConfig"
                                 sitePageList: sitePageList,   // ...as will the sitePageList menu group
                                 successCallback: this.sitePagesLoaded,
                                 callbackScope: this});
             }
          },
          
          /**
           * This function is "hitched" from the serviceXhr call in the "loadSitePages" function and handles the response
           * from the asynchronous request to get site pages. It clears the original "Loading..." menu item and adds in
           * each of the site page links.
           * 
           * @instance
           * @param {object} response The response from the request
           * @param {object} originalRequestConfig The configuration passed on the original request
           */
          sitePagesLoaded: function tutorials_SitesMenu__loadSitePages(response, originalRequestConfig) {
             this.alfLog("log", "Site pages data loaded successfully", response);
             
             // Initialise the object that keeps track of which pages have been loaded if it has not
             // previously been initialised...
             if (this._sitePagesLoaded == null)
             {
                this._sitePagesLoaded = {};
             }
             
             // Record that the site pages have been loaded to prevent them from being loaded again...
             this._sitePagesLoaded[originalRequestConfig.siteShortName] = true;
             
             // Check for keyboard access by seeing if the first child is focused...
             var focusFirstChild = (originalRequestConfig.sitePageList && originalRequestConfig.sitePageList.getChildren().length > 0 && originalRequestConfig.sitePageList.getChildren()[0].focused);
             
             // Remove the loading item...
             array.forEach(originalRequestConfig.sitePageList.getChildren(), function(widget, index) {
                originalRequestConfig.sitePageList.removeChild(widget);
             });
             
             // Add the site pages...
             if (response.sitePages && response.sitePages.length > 0)
             {
                array.forEach(response.sitePages, function(sitePage, index) {
                   this.alfLog("log", "Adding site page menu item", sitePage);
                   var item = new AlfMenuItem(sitePage);
                   originalRequestConfig.sitePageList.addChild(item);
                }, this);
             }
             else
             {
                // TODO: Should add some error handling here - but has been left out as Example for Blog post only covers "golden path"
             }
             
             if (focusFirstChild)
             {
                // Focus the first site page...
                originalRequestConfig.sitePageList.focusFirstChild();
             }
          }
       });
    });                       
                            
                        
  3. You need to edit your Surf extension configuration file to ensure that the Dojo AMD loader can locate the new tutorials package. Edit customize-share-header-menu/src/main/amp/config/alfresco/web-extension/site-data/extensions/custom-header-extension.xml relpace the contents with the following text:

                            
    <extension>
      <modules>
        <module>
          <id>Custom Share Header Menu</id>
          <version>1.0</version>
          <auto-deploy>true</auto-deploy>
          <customizations>
            <customization>
              <targetPackageRoot>org.alfresco.share.header</targetPackageRoot>
              <sourcePackageRoot>tutorials</sourcePackageRoot>
            </customization>
          </customizations>
          <configurations>
            <config evaluator="string-compare" condition="WebFramework" replace="false">
              <web-framework>
                <dojo-pages>
                  <packages>
                    <package name="tutorials" location="js/tutorials"/>
                  </packages>
                </dojo-pages>
              </web-framework>
            </config>
          </configurations>
        </module>
      </modules>
    </extension>
                            
                        
    In addition to adding the tutorials package to the configuration, note that the file now has the following line:
    <auto-deploy>true</auto-deploy>
    This loads your Surf extension automatically when Share starts, so that you no longer need to deploy it manually from the Module Deployment page.
  4. Edit the file customize-share-header-menu/src/main/amp/config/alfresco/web-extension/site-webscripts/tutorials/share-header.get.js, created in the previous tutorial, and add the following code at the end of the file:

                            
       //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 = "tutorials/SitesMenu";
       }                        
                            
                        
  5. Create a new XML file in the folder customize-share-header-menu/src/main/amp/config/alfresco/web-extension/site-webscripts/tutorials called site-pages.get.desc.xml, with the following content:

                            
    <webscript>
       <shortname>Get the pages for the requested site</shortname>
       <description>This WebScript is added to allow the tutorials/SitesMenu widget to asynchronously request the page for each site</description>
       <url>/tutorials/site/{shortname}</url>
       <format default="json"></format>
    </webscript>                        
                            
                        
  6. In the same folder create a new JavaScript file called site-pages.get.js, with the following content:

                            
    <import resource="classpath:/alfresco/site-webscripts/org/alfresco/share/imports/share-header.lib.js">
    
    // We need to set up a fake page structure to allow the page-centric imported function to work...                                                                  
    page = { url: { templateArgs: { site: url.templateArgs.shortname}}};
    
    // Create a new object in the model for the pages and add in the default dashboard page...                                                                         
    model.pages = [
       {
          label: msg.get("page.siteDashboard.title"),
          targetUrl: "site/" + url.templateArgs.shortname + "/dashboard"
       }
    ]
    
    // Call the "getSitesPages" function imported from the "share-header.lib.js" file...                                                                               
    // Iterate over the configured pages and add the details to the model...                                                                                           
    var pages = getSitePages();
    if (pages != null)
    {
       for (var i=0; i<pages.length; i++)
       {
          model.pages.push({
             label: (pages[i].sitePageTitle) ? pages[i].sitePageTitle : pages[i].title,
             targetUrl: "site/" + url.templateArgs.shortname + "/" + pages[i].pageUrl
          });
       }
    }
    
    // Finally push in the "site-members" page (the other default page)...                                                                                             
    model.pages.push({
       label: msg.get("page.siteMembers.title"),
       targetUrl: "site/" + url.templateArgs.shortname + "/site-members"
    });
                            
                            
                        
  7. Create a new file in the same folder called site-pages.get.json.ftl, with the following content:

                            
    <#escape x as jsonUtils.encodeJSONString(x)>
    {
       "sitePages":
       [
       <#list pages as page>
          {
             "label": "${page.label}",
             "targetUrl": "${page.targetUrl}"
          }<#if page_has_next>,</#if>
       </#list>
       ]
    }
    </#escape>
                            
                            
                        

    You have now created the three essential pieces of the web script - the JavaScript code, the FreeMarker template and the web script definition file.

  8. Restart the application server by running the run.sh command to update your Surf extension module.
  9. Now log back in to Alfresco Share and select the Sites menu item. Click a site under Recent Sites. You will see that there are now additional menu items including Site Dashboard, Document Library, and Site Members. Click on one of these menu items to test it. For example, if you click on the Site Members items you will be taken to the Site Members page for that site.