ddraper

Material Designed Aikau

Blog Post created by ddraper on May 5, 2016

Introduction

It was recently announced at BeeCon 2016 that Alfresco would be adopting Angular 2 and Google Material Design for all future applications that it develops (but that Aikau would continue to be developed to support Alfresco Share and Records Management).

 

Obviously Google Material Design is not compatible stylistically with Share currently, but Aikau can be used to build standalone Alfresco clients as well, so I thought it might be interesting to see if I could combine the two.

 

There are specific implementations of Material Design for Angular which were unlikely to be compatible with Aikau so I just used Material Design Lite (MDL) to quickly build some widgets and construct a page.

 

The purpose of this blog is to demonstrate that these types of integrations are possible and to provide further examples of how Aikau is able to easily integrate 3rd party libraries.

 

 

Base Material Design Lite Widget

MDL is provided in the form of a JavaScript file and a CSS file. The JavaScript file should be included to process the DOM once it has been loaded. MDL is primarily aimed at static web pages rather than dynamic ones which presented a minor issue for Aikau as the DOM is dynamically constructed after the page has been loaded.

 

MDL does support dynamic construction of some of its elements (unfortunately tabs was not one of them which was something of a disappointment) but it was simple enough to “upgrade” widget elements after they had been created.

 

I created a base widget “mdl/BaseMdlWidget” that handled all the dependencies and dynamic upgrading:

 

define(['dojo/_base/declare',
        'dijit/_WidgetBase',
        'dijit/_TemplatedMixin',
        'dojo/text!./templates/Header.html', 
        'alfresco/core/Core',
        'alfresco/core/CoreWidgetProcessing',
        'dojo/_base/array'],
        function(declare, _WidgetBase, _TemplatedMixin, template, AlfCore, CoreWidgetProcessing, array) {

  return declare([_WidgetBase, _TemplatedMixin, AlfCore, CoreWidgetProcessing], {

    cssRequirements: [{cssFile:'./css/material.css'}],

    templateString: '<div>No template provided</div>',

    nonAmdDependencies: ['./material.js'],

    postCreate: function mdl_BaseMdlWidget__postCreate() {
      if (this.widgets) {
        this.processWidgets(this.widgets, this.domNode);
      }
    },

    allWidgetsProcessed: function mdl_BaseMdlWidget__allWidgetsProcessed(widgets) {
      if (widgets) {
        array.forEach(widgets, function(widget) {
          if (widget.domNode) {
            componentHandler.upgradeElement(widget.domNode);
          }
        });
      }
    }
  });
});


This widget includes the references to both the “material.css” and “material.js” files that are stored relative to the widget (Surf ensures that they are only loaded once onto the page regardless of how many Aikau widgets declare a dependency on them). Note the use of the “nonAmdDependencies” attribute to load a JavaScript file that is not AMD compatible.

 

All the subsequent MDL based widgets I created extended this module.

 

The majority of the widgets I created were just simple representations of the various layout containers, for example:

 

header.js

define(['dojo/_base/declare',
        'mdl/BaseMdlWidget',
        'dojo/text!./templates/Header.html'],
        function(declare, BaseMdlWidget, template) {

    return declare([BaseMdlWidget], {
      templateString: template
    });
});

...with the template, header.html

<header class='mdl-layout__header '></header>

 

You might wonder what the point of doing this is?

 

Well, it’s quite simple really… although it would be simpler to just write out an HTML page, you would lose all the dynamic customization options that Aikau provides. If Alfresco were to ship an MDL based Aikau client it would be possible to add, remove and reconfigure the various elements on the page through an extension module.

 

Mixing in Aikau

Some of the other widgets were much more interesting though and demonstrate the power of the Aikau mixin modules.

 

For example the “mdl/MenuItem” used for the logout option in the header menu mixes in the “alfresco/renderers/_PublishPayloadMixin” to gain access to all the payload manipulation capabilities for publications.

define(['dojo/_base/declare',
        'mdl/BaseMdlWidget',
        'dojo/text!./templates/MenuItem.html',
        'dijit/_OnDijitClickMixin',
        'alfresco/renderers/_PublishPayloadMixin'],
        function(declare, BaseMdlWidget, template, _OnDijitClickMixin, _PublishPayloadMixin) {

  return declare([BaseMdlWidget, _OnDijitClickMixin, _PublishPayloadMixin], {

    templateString: template,

    title: 'Menu Item',

    onClick: function mdl_MenuItem__onClick(evt) {
      this.publishPayload = this.getGeneratedPayload();
      this.alfPublish(this.publishTopic, this.publishPayload, !!this.publishGlobal, !!this.publishToParent);
      evt.stopPropagation();
    }
  });
});

 

Another example was the “mdl/CreateContentFabButton” that mixed in the 'alfresco/documentlibrary/_AlfCreateContentMenuItemMixin' and 'alfresco/documentlibrary/_AlfCreateContentPermissionsMixin' modules to be able to generate content creation dialogs and automatically disable itself when a folder is viewed that the current user cannot create content in.

define(['dojo/_base/declare',
        'mdl/FabButton',
        'alfresco/documentlibrary/_AlfCreateContentMenuItemMixin',
        'alfresco/documentlibrary/_AlfCreateContentPermissionsMixin',
        'alfresco/documentlibrary/_AlfDocumentListTopicMixin',
        'dojo/_base/lang'],
        function(declare, AlfFilteringMenuItem, _AlfCreateContentMenuItemMixin, _AlfCreateContentPermissionsMixin, _AlfDocumentListTopicMixin, lang) {

  return declare([AlfFilteringMenuItem, _AlfCreateContentMenuItemMixin, _AlfCreateContentPermissionsMixin, _AlfDocumentListTopicMixin], {

    postCreate: function alfresco_documentlibrary_AlfCreateContentMenuBarPopup__postCreate() {
      this.alfSubscribe(this.hashChangeTopic, lang.hitch(this, this.onFilterChange));
      this.alfSubscribe(this.userAccessChangeTopic, lang.hitch(this, this.onUserAcess));
      this.alfSubscribe(this.metadataChangeTopic, lang.hitch(this, this.onCurrentNodeChange));
    },

    filter: function alfresco_documentlibrary_AlfCreateContentMenuItem__filter(payload) {
      if (this.hasPermission(this.permission, payload.userAccess)) {
        this.domNode.setAttribute('disabled');
      }
      else {
        this.domNode.removeAttribute('disabled');
      }
    }
  });
});

 

Building a Document Library

Having created some modules I then set about composing a page using them with the Aikau Document Library. In a previous blog post I described how the doclib.lib.js and doclib.lib.properties files could be imported into an Aikau page WebScript. I briefly mentioned that this library file provided functions that could be called to build specific parts of the Document Library.

 

I’ve used this approach to place the controls normally found in a sidebar (filters, tree, tags and categories) into the MDL drawer and placed a breadcrumb trail and document list into the main content section.

 

Other Steps

There a few other steps that were necessary…

 

The Java based LESS engine in Surf compressor was having an issue with the material.css file so I swapped out the “css.theme.handler” bean with a custom version that uses a Node based LESS processor by adding the following definition into the “web-application-config.xml” file (PLEASE NOTE: This is only available in Surf 6 and can’t be used in Alfresco 5.0 or 5.1 out-of-the-box).

<bean id='css.theme.handler' parent='css.theme.handler.abstract' class='org.springframework.extensions.surf.ExternalLessCssThemeHandler'>
  <property name='cmd'><value>lessc -</value></property>
</bean>

 

This required me to install LESS globally via NPM.

npm install less -g

I also updated the “theme_1-theme.xml” to set a LESS variable to disable legacy button design:

<less-variables>
  @use-legacy-buttons: false;
</less-variables>

It was also necessary to update the “page-template.ftl” file to include:

<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<link rel='stylesheet' href='https://fonts.googleapis.com/icon?family=Material+Icons'>

To get the necessary icon font from and set the viewport property for scaling to other devices.

 

Test it out

All the code is available on a GitHub repository for you to try out. Simply clone the repository and run:Test it out

mvn clean install jetty:run

 

Make sure you have an Alfresco Repository running locally on port 8080 and when the Jetty server has started go to http://localhost:8090/aikau-sample/page/ap/ws/home

 

Once you’ve logged in you should be taken to the main page which shows the content from the sample site. This video shows what you can expect to see.

 

Summary

This is just another example of how Aikau can make use of 3rd party libraries and should demonstrate that it is possible to easily take advantage of the capabilities that Aikau and Surf provides with your own custom widgets. It is by no means a statement of direction for Aikau but hopefully shows what is possible in a short amount of time and hopefully highlighted a few useful tricks along the way.

Outcomes