Extending Aikau Widgets

cancel
Showing results for 
Search instead for 
Did you mean: 

Extending Aikau Widgets

ddraper
Intermediate II
6 6 5,768

Introduction

I'm very keen to understand the pain points of using Aikau for customizing Alfresco Share and for creating standalone clients. I recently got some very valuable feedback from an Alfresco Community member suggesting that one area that I could try to describe better would be in extending existing Aikau widgets. I'm always very want to write posts that help people overcome any issues so I've written this to try and help people understand the various options available to them - the Aikau tutorial provides a chapter on creating new widgets but doesn't have any information on extending them.

Custom Styling

The specific use case that was raised was the issue of customizing the CSS used for a widget. Ideally we aim to make it possible to customize the styling of widgets through LESS variables in the Alfresco Share themes. Aikau provides a set of default styling variables that are referenced by the widgets covering attributes such as:

  • fonts (colour, size, family, etc)
  • borders
  • colours
  • spacing (horizontal and vertical margins and padding, line heights, etc)

...and the CSS files associated with a widget will reference these variables. This means that it is possible to customize styling by editing or creating an Alfresco Share theme as shown in this example.

An example use of these variables is shown here (taken from AlfBreadcrumb.css) - see the use of @link-font-color, @link-text-decoration and @breadcrumb-background-color - these are all examples of using the LESS variables.

.alfresco-documentlibrary-AlfBreadcrumb a {

   color: @link-font-color;

   text-decoration: @link-text-decoration;

   padding: 5px 15px 5px 30px;

   background: @breadcrumb-background-color;

   position: relative;

   display: block;

   float: left;

   cursor: pointer;

   height: 20px;

   &:hover {

      colour: @link-font-color-hover;

      text-decoration: @link-text-decoration-hover;

   }

}

It is always worth referencing the LESS variables in the CSS files of your custom widgets - and if you find that an Aikau widget is not making use of a variable or you feel that styling customization would be easier if a variable was used then please raise an issue.

Extending to Add Custom Styles

If it is not possible to set a LESS variable in your Alfresco Share theme to achieve your desired styling then you can always extend a widget and provide additional CSS files. The Surf framework that Aikau uses to build the resources required for each page will parse the source of each widget to identify the CSS dependencies that need to be included (as described in this blog post). Therefore in order to provide additional dependencies it is necessary to include them in a widget source file.

Let's say you want to extend add in a new CSS dependency for the alfresco/menus/AlfMenuItem widget - the perfect example would be the alfresco/headerAlfMenuItem as it does exactly this - the entire module looks like this (with the JSDoc removed)

define(["dojo/_base/declare",

        "alfresco/menus/AlfMenuItem"],

        function(declare, AlfMenuItem) {

   return declare([AlfMenuItem], {

      cssRequirements: [

         {cssFile:"./css/AlfMenuItem.css"}

      ]

   });

});

The main thing that this widget does is to provide a new CSS dependency that changes the styling of the menu item to be the style that you see in the Share header (i.e. with a black background) this image shows the difference:

ExtendingWidgetsBlogPost1.png

The functionality provided by alfresco/menus/AlfMenuItem is retained - all alfresco/header/AlfMenuItem does is to restyle the widget.

Extending Widget Functionality

The other major reason for extending is to either add or change the functionality of an existing widget. Aikau strives to not only be backwards compatible itself but to also ensure that 3rd party customizations (including extended widgets) continue to work against new releases. For that reason we will never remove a function from a widget (except when moving to a new major version and only then if the function has been previously deprecated - you can find a list of all deprecations in the release notes).

As well as this we use special annotations in the widgets to indicate which functions can be overridden (that is be completely replaced) or extended (be replaced but with a call to this.inherited(arguments) to call the inherited behaviour). Functions that can be overridden will be marked with @overrideable and those than can be extended will be marked with @extendable and these annotation will show up in the JSDoc as a "Support" statement as shown:

ExtendingWidgetsBlogPost2.png

As a general rule we don't automatically add these annotations to all functions - but if you have a clear requirement for a function to be supported in future releases then you should raise and issue to let us know and we will add an annotation if we feel that it is something that can be supported going forwards.

Extending a function in a widget is just a case of adding a function of the same name. If you want to invoke the function inherited from the extended widget then simply call this.inherited(arguments) - if you wish to change the arguments that are passed then you should simply include an array of new arguments as an extra argument, for example the DateRange widget extends DateTextBox and extends the setValue function but passes different arguments, as shown here:

setValue: function alfresco_forms_controls_DateRange__setValue(value) {

   if (value)

   {

      var valueTokens = value.split(this.dateSeparator);

      this.inherited(arguments, [valueTokens[0]]);

      this.toDate.setValue(valueTokens[1]);

   }

   else

   {

      this.inherited(arguments);

   }

}

Widget Life-cycle Functions

Aikau widgets extend from the dijit/_WidgetBase module and the main thing you need to know about this that the postMixInProperties function is called before the HTML template is processed and the postCreate function is called afterwards. These are the 2 key life-cycle functions that you will find yourself extending and in almost all cases you will want to call this.inherited(arguments) to retain the default functionality. The default functions provided by dijit/_WidgetBase are pure life-cycle hooks, but in most cases they will have been implemented by the Aikau widget that you are extending.

Summary (so far!)

This is an initial pass at providing some information on extending Aikau widgets - however, if there are use cases that you'd like me to elaborate on further then please let me know (via the comments section) and I will make further updates.

6 Comments
janaka1984
Established Member II

can i use common JS file with aikau page to manage logic as we did in aikau dashlet

ddraper
Intermediate II

janaka _​ Could you clarify this question for me with an example please?

One of the nice things about the Dojo _WidgetBase that we build on is that it supports the concepts of "mixin" modules (somewhat like multiple inheritance) which means we can share JavaScript across multiple widgets easily. Is this what you mean?

janaka1984
Established Member II

example:

when load browser, i need to get preference value and set into widget (e.g AlfMenuBarToggle, AlfMenuBarSelect..) as last selected value, if url parameter is empty.

Above thing is managed at postCreate() in client JS of aikau dashlet.

i need to do like this thing on aikau page

ddraper
Intermediate II

In order to get user preferences then you need to ensure that the PreferenceService is included on the page (it usually will be) and then publish requests to it to get and set preferences.

There are various examples of widgets using the PreferenceService, for example you can find this one in UploadHistory.

janaka1984
Established Member II

i have used this services with aikau page. actually my question is how can use logic to set preference value when load aikau page and browser URL does not provide parameter.

ddraper
Intermediate II

So you want to set a user preference when the page is loaded? This would be done by publishing on topics.SET_PREFERENCE ("ALF_PREFERENCE_SET"). An example of setting a preference can be found in the ThumbnailSizeSlider widget. Essentially you just need to publish the dot-notation property of the preference to set and the value to set it to.

You can always configure "publishOnReady" in your page model to publish one or more topics when the page loads, for example:

model.jsonModel = {

  publishOnReady: [

      {

         publishTopic: "TOPIC_TO_PUBLISH ON LOAD"

      }

   ],