Quantcast
Channel: Aikau – Alfresco Developer Blog
Viewing all 43 articles
Browse latest View live

Share Header Colour Customization

$
0
0

by Dave Draper

Introduction

Alfresco Share has supported themes in general for some time, but it is more challenging to customize the colours used in the Share header bar. We’ve made some updates in the Aikau 1.0.18 release that now make this a much simpler process. You’ll be able to take advantage of these in either Alfresco Community 5.0.d or Alfresco Enterprise 5.0.1 if you upgrade the default version of Aikau used, but will be available for use out-of-the-box in Alfresco Enterprise 5.0.2 and future Community releases. This blog post will explain how to create or update a Surf theme to customize the header colours, as well as providing some context on why it has taken so long to provide this capability and the ways in which it will further improve in the future.

A Bit of History…

The current widgets used for the Share header were created during the 4.2 release. At that time we were experimenting with ways in which we could improve theme handling but it wasn’t until after the 4.2 release that we included dynamic LESS pre-processing into Surf page rendering.

Although there was an effort to generate some momentum in updating the Share themes it wasn’t really a priority at the time and as a result the capabilities that were introduced weren’t made use of in the 5.0 release.

It’s only now that 5.0 is starting to get some focus in the field that we’ve started to see questions related to this particular type of customization. It has always been possible to change the header colours by modifying the CSS files directly or replacing them completely, but with the release of Aikau 1.0.18 we’ve gone back through the “alfresco/header” packaged widgets and updated the CSS files to make use of some new LESS variables.

LESS and Themes

Overriding the default LESS variables (which are defined in defaults.less in Aikau and included for every theme) is currently done by adding a particular element to the Surf Theme XML file. I appreciate that it’s not ideal to be writing LESS in an XML file but there are historical reasons for this and in the future I hope to be able to change this so that the Theme XML file can reference one or more LESS files as required.

A Surf Theme is defined by an XML file that lives in the “themes” subfolder of the client’s Surf configuration folder, in Share this can be found in “share/WEB-INF/classes/alfresco/site-data/themes”. If you want to create a new theme for Share that supports the legacy YUI2 widgets you should also create a theme folder with a name that matches your Surf Theme name – if working with a standalone Aikau client (e.g. one created by the Aikau Maven Archetype) then this isn’t necessary.

In the theme XML file include the following within the <theme> element:

<css-tokens>
  <less-variables>
  </less-variables>
</css-tokens>

Within the <less-variables> element you can place any valid LESS content (http://lesscss.org/features/). If we want to override the LESS variables for the header we can add the following content that results in an awesomely garish header:

@header-background-color: #0082c8;
@header-font-color: #ccc;
@header-hover-background-color: orange;
@header-hover-font-color: green;
@header-focus-background-color: yellow;
@header-focus-font-color: red;
@header-menubar-font-color: pink;
@header-dropdown-menu-font-color: purple;
The resulting customized header

The resulting customized header

Variable Breakdown

We’ve tried to make the LESS variables as semantically meaningful as possible, but in case it’s not obvious I’ll break down what each variable does.

  • @header-background-color – This is the main background color for the header (e.g. in Share this is black)
  • @header-font-color – This is the colour of fonts when menus are neither hovered or focused, in Share this is a light grey colour by default.
  • @header-hover-background-color – This is used for the background colour of the header menu widgets when the mouse hovers over them. In Share this is a light grey colour.
  • @header-hover-font-color – This is used as the colour of the header menu widgets when the mouse is hovered over them
  • @header-focus-background-color – This is the background colour of the header menu widgets when they have focus, therefore it is also used as the background colour of drop-down menus (as they have focus when opened). In Share this is a darker grey colour by default.
  • @header-focus-font-color – This is used as the font colour of focused header menu widgets. So it is used as the font colour of items in opened drop-down menus. In Share this is white by default
  • @header-menubar-font-color – This is used as the font colour of menu bar items (e.g. not drop-down menu items). In Share this is the darker grey by default.
  • @header-dropdown-menu-font-color – This is used as the font colour of drop-down menu items. In Share this is white by default.
Editing the Green Theme in Share

Editing the Green Theme in Share

If you look through the defaults.less file in Aikau you’ll see that there are lots of other LESS variables that you can override. Although not all of the widget CSS files make use of these LESS variables we are going to endeavour to improve this over future releases. However, if there are any widgets in particular that you wish were easier to customize then please let us know – it’s very difficult for us to support use cases that we don’t know about, so please let us know by raising issues on GitHub or JIRA.


Creating Aikau Site Pages for Share

$
0
0

Introduction

The Aikau framework provides a simpler way of creating pages in Share where a page can be declaratively defined as a JSON model in a WebScript. This avoids the necessity to create the XML and FreeMarker files for Surf Pages, Templates and Components.

I’ve been asked how you would create an Aikau page such that it is available as a site page in Share (e.g. a page that can be added via the Site Customization tooling in Share). So thought it would be worth capturing this information in a blog post. This is one of those interesting use cases where the old and new approaches of Share development intersect…

Background

In Share we use “pre-sets” configuration to provide default User and Site dashboards. These are XML configurations that define the Surf objects that can be used to “cookie-cut” new page instances (which are then stored on the Alfresco Repository).

The pre-sets can be found in in this file and the “site-dashboard” pre-set contains a property (“sitePages”) that defines the initial set of pages for each site. Once the site is created a new Surf Page instance is created on the Repository and when you add or remove pages from the site it is this property that is updated (in the instance, not the pre-set).

The “Customize Site” page lists both the available “Site Pages” and the “Current Site Pages” and the list of pages to choose from is defined in the “share-config.xml” file under the “SitePages” condition, e.g:

<config evaluator="string-compare" condition="SitePages">
  <pages>
    <page id="calendar">calendar</page>
    <page id="wiki-page">wiki-page?title=Main_Page</page>
    <page id="documentlibrary">documentlibrary</page>
    <page id="discussions-topiclist">discussions-topiclist</page>
    <page id="blog-postlist">blog-postlist</page>
    <page id="links">links</page>
    <page id="data-lists">data-lists</page>
  </pages>
</config>

It’s possible to extend this configuration to include additional pages, however the underlying code currently assumes that each page is mapped to a Surf object. This means that if you want to add in an Aikau page to this list then you need to create a Surf Page object (even though it won’t actually be used to render the page at all).

Example

Say you want to add in a new Aikau page called “Example”. You need to create a Share configuration extension that defines the new page (one way of doing this would be to create a “share-config-custom.xml” file that you place in the “alfresco/web-extension” classpath).

The file would contain the following XML:

<alfresco-config>
  <config evaluator="string-compare" condition="SitePages" replace="false">
    <pages>
      <page id="example">dp/ws/example</page>
    </pages>
  </config>
</alfresco-config>

But you’d also need to create a Surf Page XML file (placed in the  “alfresco/site-data/pages” classpath) containing:

<?xml version='1.0' encoding='UTF-8'?>
<page>
  <title>Example Site Page</title>
  <description>Example of adding a new site page</description>
</page>

Which would result in the following being shown when customizing a site:

The Customize Site page showing an Aikau page.

The Customize Site page showing an Aikau page.

 

Aikau – Using the AlfDocumentPreview Widget

$
0
0

Introduction

This afternoon I saw a Tweet asking if there were any examples of how to use the AlfDocumentPreview widget.  Aikau documentation is currently very thin on the ground (as you’re probably no doubt painfully aware) so I thought it would be worth writing up a quick blog post to describe how we use it and how you can too. If there’s anything that you want more information on then it’s worth Tweeting me @_DaveDraper with a request – I can’t guarantee that I’ll be able to write it up as a blog post, but I will try to do my best as my time allows!

Background

Most of the Aikau widgets are completely new, some are “shims” around existing YUI2 based code and a few are direct ports of YUI2 widgets. The AlfDocumentPreview widget (and it’s associated plugins) is a good example of a ported widget. The original code was copied into an Aikau widget definition and then most of the YUI2 code was replaced, bugs were fixed and thorough JSLinting applied.

You might wonder why we’d go to such lengths when a widget already existed. This essentially gets right to one of the fundamental points of Aikau as a framework. The code inside the widget really isn’t important – what’s important is defining an interface to a widget that performs a single specific task that can be referenced in a declarative model. The widget becomes an API to a piece of UI functionality – in this case, previewing a widget.

Every Aikau page model that references it will never need to change – even if we decide to completely rewrite the widget to use JQuery, Angular, Web Components or whatever happens to be the current flavour of the month – the pages will function as they always have.

Where is the previewer used?

The rule of thumb that I tell anyone asks me, is that if Alfresco has used an Aikau widget in a product feature then it’s fair game for use in your application or extension. There are a number of widgets that are definitely beta quality (and we call these out in the JSDoc) which might be subject to change, but once it’s been used in a feature then we’re obliged to maintain backwards compatibility and fix any bugs with it.

The AlfDocumentPreview is currently being used in the new filtered search feature that is part of the 5.0 release (and you’ll also find it used in the Film Strip View that is part of the prototype Aikau based Document Library which is not yet a product feature!). If you click on the thumbnail of any document (that is not an image) then a new dialog is opened that contains a preview of that document. The preview will render the appropriate plugin (e.g. PDF.js, video, audio, etc) for the content type.

The filtered search page in Alfresco Share 5.0

The filtered search page in Alfresco Share 5.0

A preview of a search result

A preview of a search result

How it works

Each row in the search results is an AlfSearchResult widget that contains a SearchThumbnail widget. When you click on the thumbnail widget (of the appropriate type) then a payload is published on the “ALF_CREATE_DIALOG_REQUEST” topic to which the AlfDialogService subscribes. The payload contains a JSON model of widgets to render in the dialog when it is displayed. The model is an AlfDocument widget that contains an AlfDocumentPreview widget.

...
widgetsContent: [
  {
    name: "alfresco/documentlibrary/AlfDocument",
    config: {
      widgets: [
        {
          name: "alfresco/preview/AlfDocumentPreview"
        }
      ]
    }
  }
],
...

The point of the AlfDocument widget is to ensure that all of the relevant Node data is available to pass to a child widget (in this case the AlfDocumentPreview – but it could be something else) so to do something with.

One of the key things about the search page is that search requests only return a very limited amount of data about each node (unlike requests from the Document Library which are slower but contain much more information such as all the properties and the actions permitted for the current user).

An additional XHR request is required to obtain all the data required to preview the node. The payload published when clicking on the thumbnail also contains the publication to make once the dialog has been displayed:

...
publishOnShow: [
  {
    publishTopic: "ALF_RETRIEVE_SINGLE_DOCUMENT_REQUEST",
    publishPayload: {
      nodeRef: this.currentItem.nodeRef
    }
  }
]
...

The “ALF_RETRIEVE_SINGLE_DOCUMENT_REQUEST” is serviced by the DocumentService and the AlfDocument subscribes to successful document loaded publications (note that the SearchThumbnail will have a “currentItem” attribute set containing the limited data returned by the search request which will contain a “nodeRef” attribute).

The AlfDocument only processes it’s child widgets once it has some data about a specific node. Once the DocumentService has published the node data then it will process the AlfDocumentPreview widget. From that point on the AlfDocumentPreview will use the data that has been provided to create the appropriate plugin to preview the document.

Other Ways to use AlfDocumentPreview

You don’t have to use an AlfDocumentPreview within an AlfDocument, you just need to ensure that you provide it with node data as the “currentItem” configuration attribute. So if you already have the all the data (for example if you’ve made a request from within your JavaScript controller or if you are accessing it from a list that has been generated from the REST API used to service the Document Library) then you can configure it into the widget directly.

The following is an example of a simple Aikau page model that previews a document (obviously you need to swap in your own nodeRef!):

model.jsonModel = {
  services: ["alfresco/services/DocumentService"],
  widgets: [
    {
      name: "alfresco/documentlibrary/AlfDocument",
      config: {
        nodeRef: "workspace://SpacesStore/7d829b79-c9ba-4bce-a4df-7563c107c599",
        widgets: [
          {
            name: "alfresco/preview/AlfDocumentPreview"
          }
        ]
      }
    }
  ]
};

You also don’t need to display it in a dialog either.

Once again this should hopefully demonstrate how you can re-use Aikau widgets to achieve very specific objectives – try doing using the YUI2 previewer in isolation and then you’ll understand why it’s been ported!

Summary

Hopefully this has provided both a useful description of how we’re currently using the AlfDocumentPreview widget (as well as how we’ve configured pub/sub in the filtered page to link widgets and services). If anything isn’t clear or you have further questions then please comment below.

“Eddie would go”

$
0
0

by Dave Draper

Today we released version 1.0.6 of Aikau and would really like to get some feedback on what we’ve done so far. If you tuned into Tech Talk Live 83 then you’ll know that we’ve been busy breaking Aikau out of Share and the Alfresco release life-cycle and into its own GitHub project.

We’ve done this so that we can iterate on Aikau faster to support Alfresco modules (such as Records Management) and to try to engage better with the Alfresco Community. The Aikau team are working to one-week long Sprints with a release at the end of each Sprint (so you can expect a new release every Tuesday!). During each sprint we will be adding more features and fixing any bugs that have been found in the previous sprint but always prioritizing bugs over features.

For the last few releases we have predominantly been focusing on the infrastructure of the Aikau project, i.e. moving the code to GitHub and ensuring that Aikau can be developed and tested outside of the internal Alfresco eco-system. This is where you come in…

We’d be really grateful if you could do one of two things for us…

1. Clone the GitHub repository, follow the development environment setup instructions (available for Linux, Windows and Mac) and check that you can build Aikau, start the test app and run the unit test suite on the Vagrant test VM.

2. Start working your way through the tutorial that will take you through the process of creating a new standalone client using the new Maven archetype. We’ve written 20 chapters of the tutorial and have so far ported 6 into GitHub markdown format. In each sprint we’ll be porting more and then writing more chapters. The tutorial has been road tested by quite a few people internally but we’d really like some external feedback on it (e.g. if there are things that aren’t clear or steps that don’t work).

We’re also interested in your contributions, bug reports and feature requests. We’ve defined some contribution guidelines to try to make the criteria for accepting contributions as transparent as possible which we will probably adjust over time as necessary to encourage active participation.

There’s still a long way to go for the Aikau project – some of the widgets are still only beta quality, and some still only work when used within Alfresco Share – but we’re making good progress. Over the coming weeks you should hopefully see new and improved widgets, more tutorials, publicly accessible JSDocs and improved test coverage.

In the meantime, give it a go and let us know what you think. Please provide feedback via the comments section or Tweet me directly at @_DaveDraper – many thanks in advance!

Why Alfresco 5.0.d will be a game changer for UI development

$
0
0

by Dave Draper

Introduction

It was recently announced that Alfresco 5.0.d has been released. There is lots of great stuff in this release for the Alfresco Community to enjoy – but the thing that I’m most excited about is that 5.0.d has a dependency on artefacts created from the independent Aikau GitHub project. This is a significant change because, for the first time, it is going to allow Community users to have access to the latest UI updates and fixes, rather than needing to wait until the next Community release.

The Benefits of an Independent Aikau

Before I explain how unbelievably easy it is to upgrade the version of Aikau that is used in 5.0.d, let’s cover some of the reasons why you should be excited about this change if you customize or make enhancements to Alfresco Share.

First and foremost, you can get an updated version of Aikau every week – this means you get access to the latest widgets, improvements and bug fixes almost as soon as they are implemented. Those enhancements can even come directly from the Alfresco Community as we’re very happy to merge your pull requests into Aikau, if they meet our documented acceptance criteria.

This means that you don’t have to passively wait anywhere between 6 months and a year for a new release that may or may not contain a fix that you might be hoping for. Now you have the opportunity to raise bugs (and optionally provide the fixes for them) as well as raising feature requests for inclusion in future development sprints. This gives the Alfresco Community unprecedented influence on updates to the UI code.

The Aikau project backlog is public so you can see what we’re going to be working on in the near future, and can give us an indication of what you’d like to see implemented, by raising new issues or voting on specific issues.

How to update Aikau in 5.0.d

The best part is that you won’t even need to re-build anything in order to get updated versions of Aikau… you just need to follow these 3 simple steps:

  1. Download the JAR for the version you want from the Alfresco Maven repository
  2. Drop it into the “share/WEB-INF/lib” directory
  3. Restart your server.

That’s it.

No really, that’s it… Surf supports multiple versions of Aikau and will always use the latest version available (although you can still manually configure the version used with the Module Deployment page if you want to).

The Aikau project even provides a Grunt task called “clientPatch” for patching Aikau clients, if you’ve cloned the GitHub repository and want to verify your own changes before submitting a pull request. You can even configure a list of different clients and then pick which one you want to update.

Summary

With the release of 5.0.d you can now take advantage of the latest updates to Aikau as they happen. Your installation of Alfresco Community can keep up with UI related bug fixes and your customizations can leverage all the new features and widgets that get released every week.

Alfresco Community 5.0.d is a great release and is going to revolutionize Share UI development.

 

 

 

Adding Views to Filtered Search

$
0
0

by Dave Draper

Introduction

One of the Alfresco Solutions Engineers recently contacted me to ask how easy it would be to add a table view into the new filtered search page in Alfresco 5.0. Fortunately this page is built using the Aikau framework, so this is actually an incredibly easy task to accomplish. This blog will take you through the process. If you have trouble following the steps or just want to try it out then download the example extension module from here.

Extension Module Creation

The best practice to customizing Alfresco Share is to first create an extension module, and for Aikau pages this is a very straightforward process. First of all ensure that Share is running in “client-debug” mode.

Now login to Share and perform a search so that the filtered search page is displayed.

Filtered search page

Open the “Debug” drop-down menu and select “Toggle Developer View

Debug Menu

You should see a page that looks like this:

Developer View

Now click on the link at the very top of the page that says “Click to generate extension JAR”. This will generate a JAR file containing all files required to customize the filtered search page.

Unpack the JAR file and open the “/alfresco/site-webscripts/org/alfresco/share/pages/faceted-search/customization/faceted-search.get.js” file in your editor of choice.

Now go back to the filtered search page (still in developer view) and click on the info icon for the main list. It should display a tooltip indicating that the widget selected has an id of “FCTSRCH_SEARCH_RESULTS_LIST”.

Selecting the Search List

Copy the “Find Widget Code Snippet”, it should be:

widgetUtils.findObject(model.jsonModel.widgets, "id", "FCTSRCH_SEARCH_RESULTS_LIST");

Paste this into the “faceted-search.get.js” file that is open in your editor. This snippet of code is all you need to target a widget on an Aikau page (obviously each snippet of code is different for each widget on the page), and in this case you have targeted the main search results list.

Understanding the extension

Lists in Aikau are used to manage data and delegate the rendering of that data to one or more views . We want to add an additional view into the search page.

There is lots of information in the Aikau tutorial on creating views, so I’m not going to repeat that information here, but if you’re not familiar with defining a list then you should certainly work your way through the tutorial.

To add a new view you just need to “push” a new widget declaration into the “widgets” array of the search lists “config” object. You can create any view you like, but as a relatively simple example you could create the following (this would be the complete contents of the faceted-search.get.js file):

var widget = widgetUtils.findObject(model.jsonModel.widgets, "id", "FCTSRCH_SEARCH_RESULTS_LIST");
if (widget && widget.config && widget.config.widgets)
{
   widget.config.widgets.push({
      name: "alfresco/documentlibrary/views/AlfSearchListView",
      config: {
         viewSelectionConfig: {
            label: "Table View",
            iconClass: "alf-tableview-icon"
         },
         widgetsForHeader: [
            {
               name: "alfresco/documentlibrary/views/layouts/HeaderCell",
               config: {
                  label: "Name"
               }
            },
            {
               name: "alfresco/documentlibrary/views/layouts/HeaderCell",
               config: {
                  label: "Description"
               }
            }
         ],
         widgets: [
            {
               name: "alfresco/search/AlfSearchResult",
               config: {
                  widgets: [
                     {
                        name: "alfresco/documentlibrary/views/layouts/Row",
                        config: {
                           widgets: [
                              {
                                 name: "alfresco/documentlibrary/views/layouts/Cell",
                                 config: {
                                    additionalCssClasses: "mediumpad",
                                    widgets: [
                                       {
                                          name: "alfresco/renderers/SearchResultPropertyLink",
                                          config: {
                                             propertyToRender: "displayName"
                                          }
                                       }
                                    ]
                                 }
                              },
                              {
                                 name: "alfresco/documentlibrary/views/layouts/Cell",
                                 config: {
                                    additionalCssClasses: "mediumpad",
                                    widgets: [
                                       {
                                          name: "alfresco/renderers/Property",
                                          config: {
                                             propertyToRender: "description"
                                          }
                                       }
                                    ]
                                 }
                              }
                           ]
                        }
                     }
                  ]
               }
            }
         ]
      }
   });
}

We’re pushing in a new “alfresco/documentlibrary/views/AlfDocumentListView” that uses the table view icon (“alf-tableview-icon“), has a label of “Table View” (which we could have localized if we wanted) and a value of “table”.

The view has two header cells (for name and description) and each item in the list is rendered as an “alfresco/documentlibrary/views/layouts/Row” widget containing two “alfresco/documentlibrary/views/layouts/Cell” widgets.

The first cell contains “alfresco/renderers/SearchResultPropertyLink” that renders the “displayName” of the item and the second is a simple “alfresco/renderers/Property” that renders the description.

Testing out the view

Re-package the extension files as a JAR file, copy that JAR file into the “share/WEB-INF/lib” folder and then restart the server. When you perform a search you should see your table view as an option.

Selecting the view

Selecting the table view will show the search results as:

Search Table View

You can add more columns to your table view, but it’s important to understand that the API used on the search page only retrieves a very small set of Node data. The data that is available for each node found is:

  • displayName
  • description
  • mimetype
  • modifiedBy (user display name)
  • modifiedByUser (username)
  • modifiedOn
  • name
  • title
  • nodeRef
  • path (within a site)
  • site (if the node is in a site)
  • size (in bytes)
  • tags
  • type (e.g. “document”)

If you want to display more than than this limited set of data then there are a couple of options available.

One approach that you could take is to use the “alfresco/documentlibrary/views/layouts/XhrLayout” widget that allows an initial version of the view to be rendered for an item (using the limited data set) and when that item is clicked the full node data is requested and the “full” view is then rendered using that data. However, this widget is only a prototype and should only be used as an example.

Another option would be to extend the “alfresco/documentlibrary/AlfSearchList” widget to request the full data for each node before the view is rendered. This would naturally slow down the rendering of search results but would allow you to display any of the data available for that node.

Deprecations

The example used in this blog will work on 5.0, but you should be aware that some of the widgets referenced have now been deprecated in later versions of Alfresco. The deprecated widgets won’t be removed for a long time, but if you’re customizing 5.0.1 onwards then you should look to use the latest versions. All deprecations are listed in the release notes for Aikau.

Aikau Update, May 2015

$
0
0

by Dave Draper

Introduction

I’ve been pretty quiet with blogs and social media of late so I thought I’d provide a bit of an insight into what’s been going on with the Aikau UI framework.

Processes

On the whole things have been going exceptionally well. We’ve managed to maintain our weekly release cycle since the beginning of the year and have now made 18 releases (including 3 hotfix releases which were useful in proving that that element of our development process works).

Although the team is incredibly small (just the two of us at the moment), we’re now servicing 4 different Alfresco Engineering teams working on a variety of projects, along with a small handful of customer engagements.

Because we have such short Sprints we’re able to turn around requirements and bug fixes incredibly quickly, and thanks to our automated unit tests (which just passed the 75% code coverage mark with the 1.0.16 release) we’re able to ensure backwards compatibility.

The test page for a new MultipleSelectInput form control created for another Engineering team

The test page for a new MultipleSelectInput form control created for another Engineering team

Automated Testing

At the moment we only have automated testing against Firefox and Chrome (on a local Vagrant VM) but have already successfully tested against a Selenium Grid that uses Internet Explorer and are looking to start incorporating this into testing in the future. At the moment we still rely on manual testing to pick up IE bugs.

The teams that we’re supporting raise bugs and feature requests as they find them and we prioritize them as necessary, ensuring that bugs are prioritized above anything else to try to maintain zero technical debt.

Recent Code Coverage Results

Recent Code Coverage Results

Educational Material

As well as improving our unit test coverage we’re also trying to improve our JSDoc documentation and when we work on any module we look to try and provide a useful description and examples of how it should be used. We’re still a long way from where we want to be, but we are making steady progress.

Another way in which we’re trying to provide educational material for Aikau is with the new index page for the test application. If you were to clone the GitHub repository and run:

mvn clean install jetty:run

…then you could access the page at “http://localhost:8089/aikau/page/tp/ws/Index” and use the “Filter results” box to search for widgets or services that you might be interested in. We’re updating the unit test WebScript descriptor files to set more meaningful “shortname” and “description” values – once again, this is an ongoing process.

Unit Test Index Page

The Unit Test Application Index Page

Document Library

Although our primary goal is to support the other Engineering teams development work we have an ongoing background task in porting the Document Library over to use Aikau. When we initially started looking at this back in the very early days we were only trying to port the existing capabilities and find ways to harness the existing action handling code. Now we’re looking to improve the Document Library with features such as inline commenting; inline content creation and metadata editing; popup previews; and drag-and-drop version update. We also want to make sure that it’s possible to easily create a configurable Document Library within a Share page and a standalone Aikau client via library files that can be imported into your Aikau page WebScripts.

The Document Library isn’t in bad shape at the moment – the biggest challenge now is to work through the remaining actions that aren’t supported and find the best way of being able to support legacy Share based XML configuration for actions, as well as making it easy to use actions in non-Share based standalone clients. You can follow the progress we make by cloning this GitHub repository which is a simple Aikau client with a page showing the authenticated user’s “User Home” directory. It would be really good to get some feedback on what we’re doing – particularly with regards to whether or not you’d be able to customize this Document Library more easily to fit your specific use cases.

DocumentLibrary

The work-in-progress Aikau Document Library

Pull Requests, Feature Requests and Bug Reports

The only less positive to report so far is the lack of pull requests that we’ve received. The Alfresco Community were apparently clamouring for an easier way of contributing code to Alfresco and Aikau provides the easiest way to do that so far. It’s possible that this is because it’s still very new and that only the recent 5.0.1 and 5.0.d releases support the external Aikau libraries.

I do see that we get a lot of traffic on the GitHub site (around 50 unique visitors per day) and that the tutorials are getting a lot of hits. We’ve also had a couple of external issues raised which we’ve tried to turn around as quickly as possible.

A screenshot from one of the tutorials hosted on GitHub

A screenshot from one of the tutorials hosted on GitHub

I also note that there is still some general concerns about Aikau in the Alfresco IRC channel. Maybe this is to be expected as Aikau still needs to prove it’s worth in the field – but I can say that the feedback within the company is incredibly positive and Aikau is definitely showing its value in accelerating the rate of UI development work internally. Hopefully once we’ve set out the ways in which Aikau can guarantee future-proof customizations from release-to-release of Share then the benefit will be seen outside of Alfresco as well. One thing I would say is that the discussions on IRC never materialise into issues on GitHub or JIRA – if you have something you want fixing or improving then let us know! We’ve already implemented feature requests and bug fixes that came from the forums and have added others to the backlog to work on in future sprints.

Long Term Thinking

We know that we’re not following the latest trends (interestingly I’ve noticed that the conversation about the best UI framework to use has shifted from Angular to React in recent months, no doubt it will have moved on to something else 12 months from now) but there’s no reason to think that Aikau won’t be around for the long haul – especially when you consider that the vast majority of Share is built on YUI2 which is approaching its 10th anniversary. Our black-box, widget-based, declarative approach to page creation is also holding strong with rewrites and updates to widgets being made without needing to make any changes to the pages that use them. We’ve also been able to migrate from Dojo 1.9.0 to 1.10.4 fairly seamlessly where our unit tests were able to quickly identify the few bugs that the upgrade introduced.

Summary

So in summary it feels as though we’re on the right track. Our processes are working, we’re making regular releases, code coverage is steadily increasing, JSDoc is improving and we’re adding more widgets and services every week. If you’ve not tried out Aikau then why not follow the tutorial and see how easy it is to quickly develop reliable, web-based clients for Alfresco.

Sample JSDoc Page

Sample JSDoc Page

Share Header Colour Customization

$
0
0

by Dave Draper

Introduction

Alfresco Share has supported themes in general for some time, but it is more challenging to customize the colours used in the Share header bar. We’ve made some updates in the Aikau 1.0.18 release that now make this a much simpler process. You’ll be able to take advantage of these in either Alfresco Community 5.0.d or Alfresco Enterprise 5.0.1 if you upgrade the default version of Aikau used, but will be available for use out-of-the-box in Alfresco Enterprise 5.0.2 and future Community releases. This blog post will explain how to create or update a Surf theme to customize the header colours, as well as providing some context on why it has taken so long to provide this capability and the ways in which it will further improve in the future.

A Bit of History…

The current widgets used for the Share header were created during the 4.2 release. At that time we were experimenting with ways in which we could improve theme handling but it wasn’t until after the 4.2 release that we included dynamic LESS pre-processing into Surf page rendering.

Although there was an effort to generate some momentum in updating the Share themes it wasn’t really a priority at the time and as a result the capabilities that were introduced weren’t made use of in the 5.0 release.

It’s only now that 5.0 is starting to get some focus in the field that we’ve started to see questions related to this particular type of customization. It has always been possible to change the header colours by modifying the CSS files directly or replacing them completely, but with the release of Aikau 1.0.18 we’ve gone back through the “alfresco/header” packaged widgets and updated the CSS files to make use of some new LESS variables.

LESS and Themes

Overriding the default LESS variables (which are defined in defaults.less in Aikau and included for every theme) is currently done by adding a particular element to the Surf Theme XML file. I appreciate that it’s not ideal to be writing LESS in an XML file but there are historical reasons for this and in the future I hope to be able to change this so that the Theme XML file can reference one or more LESS files as required.

A Surf Theme is defined by an XML file that lives in the “themes” subfolder of the client’s Surf configuration folder, in Share this can be found in “share/WEB-INF/classes/alfresco/site-data/themes”. If you want to create a new theme for Share that supports the legacy YUI2 widgets you should also create a theme folder with a name that matches your Surf Theme name – if working with a standalone Aikau client (e.g. one created by the Aikau Maven Archetype) then this isn’t necessary.

In the theme XML file include the following within the <theme> element:

<css-tokens>
  <less-variables>
  </less-variables>
</css-tokens>

Within the <less-variables> element you can place any valid LESS content (http://lesscss.org/features/). If we want to override the LESS variables for the header we can add the following content that results in an awesomely garish header:

@header-background-color: #0082c8;
@header-font-color: #ccc;
@header-hover-background-color: orange;
@header-hover-font-color: green;
@header-focus-background-color: yellow;
@header-focus-font-color: red;
@header-menubar-font-color: pink;
@header-dropdown-menu-font-color: purple;
The resulting customized header

The resulting customized header

Variable Breakdown

We’ve tried to make the LESS variables as semantically meaningful as possible, but in case it’s not obvious I’ll break down what each variable does.

  • @header-background-color – This is the main background color for the header (e.g. in Share this is black)
  • @header-font-color – This is the colour of fonts when menus are neither hovered or focused, in Share this is a light grey colour by default.
  • @header-hover-background-color – This is used for the background colour of the header menu widgets when the mouse hovers over them. In Share this is a light grey colour.
  • @header-hover-font-color – This is used as the colour of the header menu widgets when the mouse is hovered over them
  • @header-focus-background-color – This is the background colour of the header menu widgets when they have focus, therefore it is also used as the background colour of drop-down menus (as they have focus when opened). In Share this is a darker grey colour by default.
  • @header-focus-font-color – This is used as the font colour of focused header menu widgets. So it is used as the font colour of items in opened drop-down menus. In Share this is white by default
  • @header-menubar-font-color – This is used as the font colour of menu bar items (e.g. not drop-down menu items). In Share this is the darker grey by default.
  • @header-dropdown-menu-font-color – This is used as the font colour of drop-down menu items. In Share this is white by default.
Editing the Green Theme in Share

Editing the Green Theme in Share

If you look through the defaults.less file in Aikau you’ll see that there are lots of other LESS variables that you can override. Although not all of the widget CSS files make use of these LESS variables we are going to endeavour to improve this over future releases. However, if there are any widgets in particular that you wish were easier to customize then please let us know – it’s very difficult for us to support use cases that we don’t know about, so please let us know by raising issues on GitHub or JIRA.


Aikau Update August 2015

$
0
0

Introduction

It’s been a few months since my last update on Aikau so I thought it would be useful to provide some information on what we’ve been up to recently. I had hoped that we’d be able to make more regular communications on what is included in each weekly release and although the release notes, the JIRA backlog and sprint progress are publicly available, they don’t provide an enormous amount of context on what we’ve been working on. Internally we hold a Sprint review before each release to share with the teams that depend on Aikau the features implemented and bugs fixed, but this isn’t shared outside of the company.

In an ideal world we’d share a more detailed blog post each week, detailing what we’ve done and provide some real-world use cases of how the updates can be used. This week we released 1.0.33 – our 33rd release of the year (not including hot-fixes) – and our team velocity and processes have comfortably stabilized.

Some sprints we find ourselves working on nothing but bugs (as we prioritize these above everything else); some sprints it’s mostly feature development or infrastructure work (such as getting our unit tests working against a Selenium Grid).

In the future I’ll endeavour to provide more frequent updates, and although I can’t cover in detail everything we’ve been working on over the last dozen sprints, I’d like to highlight a few things that might warrant your further investigation.

So in no particular order, here are a few things that you might like to be aware of…

Button Styling

There is lots of work going on behind the scenes in reviewing Share from a design and usability point of view, some of which will be surfaced in the next release of Alfresco. Aikau faces the interesting challenge of supporting releases both past and future, and one of the new design requirements has been a button design. We needed to find a way of preserving the old button style when Aikau is used on a 5.0.n release but also enabling the new improved style in 5.1.n releases. We’ve achieved this through the use of LESS variables and in particular a single variable that allows us to toggle between the old and new styles.

By default Aikau uses the “legacy” style and Share in Alfresco 5.1 will enable the new style by overriding the variable in the LESS XML file (yes, we know… LESS in XML isn’t great – we still haven’t had the opportunity to do anything about that yet!). This also means that buttons can be easily styled per theme, using those LESS variables.

We continue to push more and more of the widget styling into LESS variables to avoid the need for custom CSS selectors as they will invariably be brittle as Aikau development progresses. If there is a specific widget that you would like to see us update to take advantage of LESS then you should raise an issue.

Multiple Document Libraries on a Single Page

One of the internal component teams that is consuming Aikau is implementing a single page that has multiple Aikau Document Libraries within an alfresco/layout/AlfTabContainer. This has been quite a challenge since we’re not completely finished on the Aikau Document Library, and this exercise has flushed out lots of bugs and allowed us to make some great improvements to our publication/subscription framework to ensure that the Document Libraries don’t interfere with each other (e.g. creating content in the wrong location, refreshing all the lists at once, etc). It’s also focused our attention on fixing lots of the little niggly bugs in our Document Library implementation to make it a more polished experience.

Search Without URL hashing or Infinite Scroll

We wrote the new filtered search page for Share 5.0 long before Aikau was abstracted to a project in its own right and it was written very much with a single use case in mind. Since then we’ve done lots of re-factoring and re-work on our list implementations, and quite rightly we’ve had requests to support alternative ways of providing search – namely with basic pagination and without requiring URL hashing. I’m pleased to say that with the release of 1.0.30 both of these things are possible. This will make it much easier to embed the search widgets within pages that aren’t fully dedicated to search.

Document Library Actions

We know that although Aikau predominantly supports Share it should also support other standalone clients. Since those clients won’t have access to the Share Document Library XML action configuration we needed to find a way in which to support actions in a variety of situations. We’ve settled on a fall-back model in which there are 3 ways in which you can define actions:

  1. Where available the XML configuration will be used
  2. It is also possible to configure in completely custom menu items as actions
  3. When nothing else is available fall-back to metadata evaluated actions.

This last approach requires that we map each of the existing Share Document Library action evaluators into individual AMD modules. This means it becomes really easy to add and remove actions as necessary, as well as insert new actions. Where you want to provide an entirely new action, you simply need to include a service to handle the topic that the action publishes. Hopefully this should make action configuration much simpler to re-use and customize dynamically, based on evaluated extension modules. We’re still a long way from completing this exercise but we have at least settled on an appropriate path.

Form Updates

There is steady incremental improvement on forms in Aikau. There’s still a full UX/design review on the horizon but we have made a few tweaks to the design (in particular how form controls are displayed in dialogs). We’ve also provided the ability to auto-save forms and prevent displaying validation errors immediately. It’s also possible to drive form values to and from the browser URL hash.

We’ve added an additional layout widget for forms that allows form controls to be placed in tabs: it’s worth understanding that you can’t use just any layout widget with a form because they won’t necessarily provide the capabilities to delegate the form-to-form-control communications that enable the dynamic validation, display, enablement, and requirement behaviour that Aikau forms provide.

Finally we’ve added support for dynamically showing and hiding warnings based on the changing values of the fields in the form.

Screenshot showing warnings in a form

Screenshot showing a form displaying dynamically evaluated warnings

Filtered Lists

We’ve extended the alfresco/lists/AlfSortablePaginatedList to create an alfresco/lists/AlfFilteredList. This provides the additional ability to update the request for data to include additional filters. Although this doesn’t perform any filtering on the client, it does enable filters to be passed to an API. It also supports the ability to set the filters as browser URL hash parameters to support back button navigation and sharing of bookmarks. This widget can best be seen in the Aikau Unit Test application home page.

Screenshot of Unit Test Application Index Page

Screenshot showing the Aikau Unit Test Application index page

Debug Log

When the Aikau project first started we had the alfresco/logging/SubscriptionLog widget for debugging communication over the publication/subscription layer. We’ve since replaced this with the much improved alfresco/logging/DebugLog which provides the additional capabilities to clear logs, filter on type or text and has expandable/collapsible payload rendering. We’re going to continue to improve this widget over time (any suggestions that you think would be useful are always appreciated) and you can make use of this already in Alfresco Share when client-debug mode is enabled via the Debug Menu in the header bar.

Screenshot of the DebugLog widget

Screenshot showing the DebugLog widget in a dialog

Dashlets

One of the core benefits of Aikau is its unit testing framework. This allows us to release frequently and be confident that we haven’t caused any regressions from the previous release. When the occasional regression does slip through the net we will hotfix the release containing the bug and add a new unit test to prevent any future regressions. When we first abstracted Aikau from Share we weren’t able to remove all of the core Share/YUI2 dependencies from all modules. Dashlets were an example of this, meaning they couldn’t be used outside of Share and couldn’t be unit tested. We’ve since completely removed all of those Share and YUI dependencies which has enabled us to fully unit test the Dashlet widget. Aikau Dashlets also make full use of LESS variables which means that they can be easily themed in Share.

Layout Widgets

We continue to add layout widgets and improve the behaviour of the existing layout widgets. I thought it would be worth calling out a few of the recent additions and updates…

HorizontalWidgets

The alfresco/layout/HorizontalWidgets widget has been updated so that it now takes into account changes to the visibility of its immediate child widgets. This means that the full horizontal space is always consumed as widgets are displayed and hidden. It does this by using the visibilityConfig and invisibilityConfig attributes on its child widgets, and then resizes and recalculates as they are hidden or revealed. Coupled with the existing ability to mix and match fixed widths, percentage widths, and automatically assigned widths on its child widgets, makes this a very powerful tool for fluid layouts.

FixedHeaderFooter

As its name suggests, the alfresco/layout/FixedHeaderFooter provides the ability to define fixed-height header and footer widget models, with a scrollable central panel. It can be configured to have a fixed height or can automatically grow to consume all of the available vertical space from its offset within a page. This makes it possible to have key controls always visible on the page such as the pagination controls for a list or a menu bar that relates to the scrolling content.

InfiniteScrollArea

The alfresco/layout/InfiniteScrollArea is designed to work with the alfresco/lists/AlfSortablePaginatedList (or one of its descendant modules). It can be thought of as the inverse of infinite scrolling – instead of scrolling triggering the loading of the next page of data, pages of data are continually requested until the available vertical space is used up. If more space is then provided (for example if it was included in a resizeable Dashlet that was then expanded) then more data will automatically be requested.

StripedContent

During a prototyping exercise we looked at various layout options and one that has since been integrated into Aikau is the alfresco/layout/StripedContent. This widget allows for a fixed width vertical column to be added to a page where stripes are rendered across the full width of the page. A few stripe styles are included out-of-the-box that can be configured through LESS variables.

Drag And Drop

The Content Modelling feature in Alfresco 5.1 makes heavy use of the Aikau drag-and-drop capabilities. This has meant that we’ve had the opportunity to flush out lots of bugs and make drag-and-drop in Aikau really simple. All the drag-and-drop modules were re-written (and can be found in the alfresco/dnd package) to be completely abstract to support custom data modelling. Really, this needs a blog post or a set of tutorials in its own right, but the unit test pages should give you an idea of what’s possible. Again, just something to be aware of – at some point it would be great if we could make use of the capabilities for a complete drag-and-drop development environment (we even have a unit test page that allows you to build drag-and-drop data models for this purpose!) – but sadly we just don’t have the bandwidth to work on it at the moment.

Where To Find Out More

It’s a great idea to keep a clone of the Aikau GitHub repository up-to-date so that you can use the Unit Test Application to see examples of all the widgets in action. Although this application is intended for unit testing rather than demonstration purposes it is a great way of seeing various configurations of all the widgets in action.

 

Aikau 1.0.34 – Form Control Rule Evaluation Updates

$
0
0

Introduction

In my last blog post I said that I would try and provide more frequent updates on Aikau. Just over a week has passed since then and we’ve released version 1.0.34 at the end of Sprint 34. We didn’t deliver a huge amount as we only had 35% availability due to team members’ vacation but there was one addition that I thought was worth mentioning.

Form Control Rule Evaluation

We had a requirement from one the feature teams using Aikau to update the form controls to support OR based evaluation of the dynamic visibility, requirement and enablement behaviour. Previously we had only supported AND based evaluation such that all the configured rules needed to be true but the team wanted to be able to make a form field required if either one of two fields was not empty.

As an aside there was already a workaround to implement this using the “autoSetConfig” capabilities provided in forms to set the value of a hidden field and then use the value of that hidden field as the evaluated target for the rules. However, the updates we’ve since made are a much cleaner way of implementing the solution

The original dynamic rule capabilities are described in the Aikau tutorial on the GitHub repository so it is worth reviewing that chapter first if you’re not familiar with the concepts before you read on.

So for example you have three fields “accidents”, “convictions” and “details” and you want to ensure that if either “accidents” or “convictions” are indicated that the “details” must be provided. You can set up your basic form controls like this:

{
  id: "ACCIDENTS",
  name: "alfresco/forms/controls/RadioButtons",
  config: {
    fieldId: "ACCIDENTS",
    name: "accidents",
    value: "NO",
    label: "Previous accidents",
    description: "Have you been involved in any previous accidents?",
    optionsConfig: {
      fixed: [
        { label: "Yes", value: "YES"},
        { label: "No", value: "NO"}
      ]
    }
  }
},
{
  id: "CONVICTIONS",
  name: "alfresco/forms/controls/RadioButtons",
  config: {
    fieldId: "CONVICTIONS",
    name: "convictions",
    value: "NO",
    label: "Previous Convictions",
    description: "Do you have any previous convictions?",
    optionsConfig: {
      fixed: [
        { label: "Yes", value: "YES"},
        { label: "No", value: "NO"}
      ]
    }
  }
},
{
  id: "DETAILS",
  name: "alfresco/forms/controls/TextArea",
  config: {
    fieldId: "DETAILS",
    name: "details",
    label: "Details",
    description: "Please provide the details of your previous accidents and/or convictions"
  }
}

Previously if you’d configured the “requirementConfig” attribute so that the “details” field became required based on the values of the “accidents” and “convictions” fields you would have created the following:

requirementConfig: {
  initialValue: true,
  rules: [
    {
      targetId: "ACCIDENTS",
      isNot: ["NO"]
    },
    {
      targetId: "CONVICTIONS",
      isNot: ["NO"]
    }
  ]
}

However, this would mean that the “details” field would only be required when both the “accidents” field and the “convictions” fields were both set to “YES”. To resolve this you can now update the configuration with a new “rulesMethod” attribute.

requirementConfig: {
  initialValue: true,
  rulesMethod: "ANY", // NOTE: This the key attribute!
  rules: [
    {
      targetId: "ACCIDENTS",
      isNot: ["NO"]
    },
    {
      targetId: "CONVICTIONS",
      isNot: ["NO"]
    }
  ]
}

Summary

This demonstrates a few of the things we like about the Aikau framework. First of all we were able to make this change in a single module (alfresco/forms/controls/utilities/RulesEngineMixin) and this new capability was immediately available for all of the form controls.

It is also a completely backwards compatible change. If you didn’t specific a “rulesMethod” attribute before then your form models will continue to work exactly as they did before. Our comprehensive unit test suites ensured that we didn’t regress any of the existing functionality.

Finally it shows that we’re able to respond to requests as they arrive and to continue to iterate on existing code without needing to constantly re-invent the wheel.

So a full page example of this would be:

model.jsonModel = {
  services: [],
  widgets: [
    {
      id: "FORM",
      name: "alfresco/forms/Form",
      config: {
        okButtonPublishTopic: "SAVE_FORM",
        okButtonLabel: "Save",
        widgets: [
          {
            id: "ACCIDENTS",
            name: "alfresco/forms/controls/RadioButtons",
            config: {
              fieldId: "ACCIDENTS",
              name: "accidents",
              value: "NO",
              label: "Previous accidents",
              description: "Have you been involved in any previous accidents?",
              optionsConfig: {
                fixed: [
                  { label: "Yes", value: "YES"},
                  { label: "No", value: "NO"}
                ]
              }
            }
          },
          {
            id: "CONVICTIONS",
            name: "alfresco/forms/controls/RadioButtons",
            config: {
              fieldId: "CONVICTIONS",
              name: "convictions",
              value: "NO",
              label: "Previous Convictions",
              description: "Do you have any previous convictions?",
              optionsConfig: {
                fixed: [
                  { label: "Yes", value: "YES"},
                  { label: "No", value: "NO"}
                ]
              }
            }
          },
          {
            id: "DETAILS",
            name: "alfresco/forms/controls/TextArea",
            config: {
              fieldId: "DETAILS",
              name: "details",
              label: "Details",
              description: "Please provide the details of your previous accidents and/or convictions",
              requirementConfig: {
                initialValue: true,
                rulesMethod: "ANY",
                rules: [
                  {
                    targetId: "ACCIDENTS",
                    isNot: ["NO"]
                  },
                  {
                    targetId: "CONVICTIONS",
                    isNot: ["NO"]
                  }
                ]
              }
            }
          }
        ]
      }
    }
  ]
};

Aikau 1.0.39 – Dynamic Form Field Option Updates

$
0
0

Amongst all the bug fixes and features added since my last post, in the 1.0.39 release of Aikau we’ve added a useful addition to our forms capabilities that I thought would be worth calling out. It’s actually something that I’ve been meaning to add for a while but have never had a use-case to drive its inclusion. If you’re not familiar with the different ways in which you can provide a from control with options, then you should review the information in this tutorial before reading any further.

When using a form control (e.g. Select, ComboBox, MultiSelectInput, RadioButtons), you can provide a “publishTopic” attribute that will be used to request the options for that form control to use, however the published payload didn’t provide any data about the the current values of the other fields in the form. We’ve now updated the Form widget to subscribe to a new topic that can be used to update the options-requesting payload with the current form values and then forward the request onto another topic.

In the specific use-case we needed to solve, we needed to get the available sites on the currently selected Cloud network. When the user changed the network we wanted to update a FilteringSelect widget to show the sites for that network.

This extract from one of our form models shows how this can be configured

{
  id: "CLOUD_SYNC_TENANT",
  name: "alfresco/forms/controls/FilteringSelect",
  config: {
    fieldId: "CLOUD_SYNC_TENANT",
    name: "remoteTenantId",
    label: "cloud-sync.dialog.network.label",
    optionsConfig: {
      queryAttribute: "value",
      labelAttribute: "value",
      valueAttribute: "value",
      publishTopic: topics.GET_CLOUD_TENANTS,
      publishPayload: {
        resultsProperty: "response"
      }
    }
  }
},
{
  id: "CLOUD_SYNC_SITE",
  name: "alfresco/forms/controls/FilteringSelect",
  config: {
    fieldId: "CLOUD_SYNC_SITE",
    name: "remoteSiteId",
    label: "cloud-sync.dialog.site.label",
    optionsConfig: {
      changesTo: [
        {
          targetId: "CLOUD_SYNC_TENANT"
        }
      ],
      queryAttribute: "title",
      labelAttribute: "title",
      valueAttribute: "shortName",
      publishTopic: topics.GET_FORM_VALUE_DEPENDENT_OPTIONS,
      publishPayload: {
        publishTopic: topics.GET_CLOUD_SITES,
        resultsProperty: "response"
      },
      publishGlobal: false
    }
  }
},

The key things to notice here are:

  1. We’re now using constants for all our topics. As well as reducing the number of string values to maintain, it means that we are able to improve our JSDoc for the topics to include information about the publishers and subscribers of those topics as well as the parameters that should be included in the payloads.
  2. We use topics.GET_FORM_VALUE_DEPENDENT_OPTIONS as the optionsConfig.publishTopic to request that the form (in which the control is placed) should add the current value of all the other fields into the payload provided.
  3. The optionsConfig.publishPayload.publishTopic is assigned the topic that is then published by the form using the updated payload. The subscriber to this topic should provide the options to be displayed.
  4. The optionsConfig.publishGlobal is configured to be false to ensure that the form detects the publication (a Form will generate a unique pubSubScope and pass it on to its child controls in order to scope communication within the form).
  5. It’s also worth noting how the optionsConfig.changesTo configuration is used to trigger a reloading of options as the user switches tenants (networks).

In this example the options retrieval is handled by a service subscribing to the topics.GET_CLOUD_SITES. This is able to check the published payload to find the tenant from which to retrieve the sites, e.g:

if (payload.username && payload.remoteTenantId)
{
  this.serviceXhr({
    url : AlfConstants.PROXY_URI + "cloud/people/" + payload.username + "/sites?network=" + payload.remoteTenantId,
    method: "GET",
    data: payload
  });
}

This is obviously just a single example of how this feature could be used. No doubt there will be plenty of other use cases in the future that need to take advantage of this capability.

Introducing the Aikau Sandpit

$
0
0

Aikau development continues rapidly with new releases each week. One of the challenges we have is in providing suitable education for getting up-to-speed with what widgets are currently available. We have the JSDoc and the online tutorial but these require you to either have or create a client or work within Alfresco Share. We had various feedback that it would be useful to have a “kitchen-sink” style application to show-case all the widgets but have found that trying to create a single application to demonstrate every widget is quite a sizable challenge. Instead we have created a “sandpit” application to demonstrate widgets that allows dynamic customization of the example configuration provided. This application is online now and can be found by following this link.

When you visit the application you’ll find an index page that allows you to search for and navigate to particular widget examples. Each page will contain one or more snippets of Aikau JSON model with a preview of what the model will render. You can edit the JSON model and update the preview to experiment with each widget. Every page has tabs for debug logging, mock XHR logging and the JSDoc for the primary widget being shown.

Sandpit_Screenshot_2

At the moment there aren’t very many example pages but we will be adding new examples for each new widget we add from now on. We’re also hoping that the Alfresco Community will get involved and contribute examples that they find useful. Contributing can be done via GitHub pull requests and instructions can be found here.

The Sandpit application will be updated each Tuesday as part of the Aikau release process. As always we’re grateful for any feedback or contributions.

Aikau 1.0.57 – Improving 3rd Party Testing

$
0
0

Background

The Aikau team is committed to providing weekly backwards compatible releases.

It is important to understand that whilst we guarantee that all configuration options for a widget will be honoured in future releases (unless deprecated for removal in the next major release), we will not guarantee that the internal implementation of any given widget will not change. This means that the HTML structure for any given widget could potentially change in any release.

This means that you cannot not rely on HTML structure or CSS classes used within a widget for customizing its appearance (the correct approach is to create a theme file that overrides the necessary LESS variables). It also means that any automated tests cannot rely on CSS selectors continuing to work for all future releases.

Solution

The Records Management (RM) team have recently run into this latter problem with their automated testing and have asked us to resolve the situation. Therefore from version 1.0.57 we have started to externalise the CSS selectors that can be used for automated testing.

These are provided in the form of Java ResourceBundle property files that are published as the test resources for the Aikau project. They are Java properties because the RM team are testing using Java based Selenium. However, it is possible to simply unpack the JAR file into your project for Intern JavaScript based testing.

We won’t simply be providing the test selectors – we will also be updating our own unit tests to use these properties files in our own testing. This means that when we make a change to the struture or CSS classes of a widget we will need to update the associated selectors property file in order to ensure that our own unit tests do not break. This means that it will be safe to rely on these test selectors in your own testing (providing that the version of the Aikau tests JAR used in tests matches the version of the Aikau JAR that is being tested).

Process

Because the Aikau code base is so large and the Aikau team is so small, it will not be possible to do this in a single sprint. Therefore we will be providing the test selectors on demand. The RM team have provided us an with an initial set to provide and all new tests will be written using externalised selectors – however, full conversion is expected to take a considerable length of time. Therefore if you have a need for specific selectors in your tests then it is recommended that you raise a feature request on JIRA or an issue on GitHub (or better yet – provide the selectors yourself via a pull request!)

We will provide one properties file for each Aikau module, each property will have a comment to indicate what it will be used for and in most cases the property will be parametrized so that widget identifiers (and when required indices) can be provided.

Examples

This is an example excerpt from the alfresco/forms/controls/MultiSelectInput properties file:

# A specific result in the drop-down
nth.result=#{0}_CONTROL_RESULTS .alfresco-forms-controls-MultiSelect__results__result:nth-child({1})

This shows an example of a selector that allows you to find a specific result in MultiSelectInput form control drop-down menu. In Java testing you would access that property as follows:

ResourceBundle selectors =
  ResourceBundle.getBundle("alfresco.forms.controls.MultiSelectInput");
String pattern = selectors.getString("nth-result");
String selector = MessageFormat.format(pattern, "WIDGET1", "4");

In the Aikau unit test framework we are importing the “properties-reader” package in order to be able to load the properties as follows:

var selectors = propertiesReader("./src/test/resources/test-selectors/alfresco/forms/controls/MultiSelectInput.properties");
var selector = selectors.get("nth-result").replace("{0}","WIDGET1").replace("{1}","4");

Summary

Aikau has provided backwards compatible releases for developing future proof Alfresco Share customizations and standalone clients and is now going to be provided a future proof way  of testing those solutions.

Aikau 1.0.63 – Support for versioned library imports

$
0
0

Introduction

This blog post describes how you can now safely import Aikau library files into WebScript controllers when you have multiple versions of Aikau available in your application. PLEASE NOTE: This information only applies if you’re using Alfresco 5.1 or 5.0.3 onwards.

Background

In the Aikau 1.0.63 release we have completed the final stage of fixing AKU-411. This bug was raised because there was no reliable way of knowing which version of an Aikau library file would be imported into a WebScript JavaScript controller.

Although Alfresco Share will only ship with a single version of Aikau (included as a JAR file in the WEB-INF/lib folder) additional JARs might be added when applying AMP files (such as Records Management). This meant that there would be duplicate versions of library files available on the classpath to be imported and as a result you could not guarantee which version would be loaded.

We made some changes in the Alfresco 5.0.3 service pack to remedy this problem (also available in Alfresco 5.1) and have now updated Aikau to take advantages of these capabilities.

At the time of writing there is only a single library file shipped with Aikau which can be used for building Document Libraries within a page – but in the future we hope to provide many more library files to address a variety of common use cases.

A New Way to Import Library Files

Previously you would have needed to imported the library file as follows:

<import resource="classpath:alfresco/site-webscripts/org/alfresco/aikau/webscript/libs/doclib/doclib.lib.js">

But you can now import the file as follows:

<import resource="classpath:alfresco/site-webscripts/org/alfresco/aikau/{aikauVersion}/libs/doclib/doclib.lib.js">

The {aikauVersion} token will automatically be swapped out for the version of Aikau that is being used by Surf. By default the most recent version of Aikau available will always be used, however it is possible to select and use an older version from the Module Deployment page (found at /share/page/modules/deploy – see screenshot below)

1.0.63-BlogPost-1

If you use the {aikauVersion} token then you are effectively stating that you always want to use the same version of the library file that is shipped with the currently used version. However, it is still entirely possible to use a specific version, e.g.

<import resource="classpath:alfresco/site-webscripts/org/alfresco/aikau/1.0.63/libs/doclib/doclib.lib.js">

However, this does mean that you need to ensure that the version specified is available.

This means that we are now able to make incremental improvements and fixes to the Document Library import file, it also means that it now makes sense for us to start providing more files that can be imported.

How To Use The Document Library Import

The doclib.lib.js file has been written with re-use in mind. It provides a number of different functions that can be called giving you the choice of building an entire Document Library or just fragments of the Document Library (such as the list, the toolbar, the tree, etc) and all the functions take a configuration object so you can control how the Document Library will be built.

1.0.63-blogpost-2

So for example if you wanted to build a full Document Library for company home you could use the following in your WebScript controller:

<import resource="classpath:alfresco/site-webscripts/org/alfresco/aikau/{aikauVersion}/libs/doclib/doclib.lib.js">

model.jsonModel = {
  services: getDocumentLibraryServices(),
  widgets: [
    getDocLib({
      rootNode: “alfresco://company/home”,
    })
  ]
};

There are a variety of other options that you can provide when calling the function, for example:

  • idPrefix – (string) A prefix for the IDs of all the widgets created
  • siteId – (string) the site shortName attribute of the site to build a Document Library for
  • containerId – (string) the name of the folder in which the Document Library content resides within the site (typically this would be “documentLibrary”
  • rawData – (boolean) whether or not to make XHR requests directly to the Alfresco Repository and bypass the Alfresco Share web-tier
  • rootNode – (string) A nodeRef to root the Document Library
  • rootLabel – (string) The label for the root of the Document Library as shown in the breadcrumb trail and in the navigation tree
  • useHash – (boolean) Whether or not to update the browser URL hash with Document Library state
  • getUserPreferences – (boolean) indicates whether or not the user preferences should be retrieved from the Alfresco Repository
  • docLibPreferences – (object) custom preferences for the Document Library (sortField, sortAscending, showFolders, hideBreadcrumbTrail, showSidebar).

The functions that you can call include:

  • getDocLib (builds the whole Document Library calling the following functions as appropriate)
  • getDocLibFilters
  • getDocLibTree
  • getDocLibTags
  • getDocLibCategories
  • getDocLibToolbar
  • getDocLibBreadcrumbTrail
  • getDocLibList
  • getDocLibCreateContentMenu
  • getDocLibSelectedItemActions
  • getDocLibSortOptions
  • getDocLibConfigMenu

Localization Properties Importing

As well as providing an import for the Document Library model and additional properties import is provided for localization purposes. For the background on importing properties files you should read this related blog post.

These imports support the {aikauVersion} token in exactly the same way. Previously you would have imported the file as follows:

surf.include.resources=org/alfresco/aikau/webscript/libs/doclib/doclib.lib

But now you can do so using the token:

surf.include.resources=org/alfresco/aikau/{aikauVersion}/libs/doclib/doclib.lib

Aikau 101

$
0
0

Introduction

A complaint that we have heard on occasion is that it is hard to find and hire people with Aikau skills. It’s probably not unexpected that there are few people with a lot of experience in Aikau – after all it’s only really existed as a named entity for a couple of years and is specific to a single vendor in a relatively niche market of IT.

…But “skills” ?

If you have working knowledge of HTML, JavaScript and CSS then you’re pretty much halfway there. The other half of the puzzle is getting your head around 3 concepts:

  • Modules
  • Pub/Sub
  • Services

It’s also vitally important to understand the problem that Aikau is trying to achieve. It is not intended to be the go-to solution for building any web application:

It is about providing a way in which a page can be defined in such a way that anyone can make small or large alterations to that page with the minimum of effort. It is about providing a way in which Alfresco can quickly iterate on its own use cases (as well as those of its partners, customers and community) in a backwards compatible way. Finally, it is about providing re-usable components to build solutions that are specifically targeted for Alfresco.

Modules

Aikau aims to decompose solutions into the smallest possible, reusable components (or widgets). Each widget is typically independent of any other in order that it can be tested as a single atomic unit.

Being able to test each widget is essential.

By defining a widget as a configurable “black box” we are able to write tests to verify how a widget behaves when configured in a certain way. We do not have to write full integration tests of how every widget interacts with every other type of widget – simply how a widget responds to publications (more on that later).

When we first started writing Aikau, there was no native module loading available (unlike now) so we used the AMD paradigm as provided by Dojo (also implemented in RequireJS). Native JavaScript imports (to the best of my knowledge) are still constrained to just JavaScript files – but some frameworks (such as Angular 2) are providing the ability to define components that reference external CSS and HTML templates (for the record, Aikau was doing this 3 years in earlier !)

Although it is the Surf framework that handles the CSS, HTML (and i18n) dependency loading it is the Aikau widget that defines the dependencies. When creating an Aikau widget you simply need to understand how these dependencies can be declared.

It’s important to be able to recognize the “boiler plate” of an Aikau widget. This is the most simple example of a widget that defines HTML, CSS and i18n dependencies.

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

  return declare([_WidgetBase, _TemplatedMixin, AlfCore], {
    i18nRequirements: [{i18nFile: "./i18n/MyWidget.properties"}],
    cssRequirements: [{cssFile:"./css/MyWidget.css"}],
    templateString: template,
    postCreate: function() {
      // TODO Put your code here
    }
  });
});

All your code (any JavaScript you like) should go into the postCreate function.

Let’s say that you don’t want an external template and have no CSS or i18n dependencies. This reduces the basic widget to this:

define(["dojo/_base/declare",
        "dijit/_WidgetBase",
        "alfresco/core/Core"],
       function(declare, _WidgetBase, AlfCore) {

  return declare([_WidgetBase, AlfCore], {
    buildRendering: function() {
      // TODO: Create some HTML for the widget and assign to this.domNode
    },
    postCreate: function() {
      // TODO Put your code here
    }
  });
});

The buildRendering function should be implemented to construct the DOM for the widget – again, using any JavaScript that you’d like.

The buildRendering and postCreate functions are part of the Dojo widget life-cycle that Aikau make use of. It is necessary to extend “dijit/_WidgetBase” and to use the define and declare functions when writing a widget – but literally everything else your widget does is entirely up to you. We just happen to use a lot of other Dojo capabilities because we find them useful – whether or not you choose to is entirely up you.

But there is no magic here – it is just JavaScript.

The define function tells the AMD loader what modules to load, the declare function creates the JavaScript Class. The buildRendering and postCreate functions are called when an instance of the class is created. A more in-depth description of widget creation can be found here.

In order to make it possible for a page to be easily customized it is essential that the building blocks of that page (the widgets) be completely decoupled from one another. This is where the publication/subscription model comes in.

The Publication / Subscription Model

It would undoubtedly be much easier to implement a solution where there are fixed references between widgets, but that would greatly constrain what a 3rd party could do a page.

Instead Aikau widgets communicate with one another by publishing requests on topics and subscribing (or listening) to and responding to other requests that are published.

In order to ensure that communications between widgets can be constrained to a subset of widgets it is possible to define a scope. This allows one group of widgets that share a common topic type to communicate with each other without impacting another group of widgets.

Imagine a scenario where you have two lists on the page each with their own sorting controls – changing the a sort order in one list should not update the order of the other list. This is where scoping comes in.

A publication/subscription scope is set on a widget by setting its “pubSubScope” attribute with a string value. This value is prefixed onto all topics published and only topics prefixed with that value are subscribed to.

The “pubSubScope” attribute is one of a handful of attributes that is passed down from parent widget to child widget. A child will have the same scope as its parent unless specifically configured otherwise.

Services

As well as being decoupled from each other via the publication/subscription model, widgets are also decoupled from data. This allows a widget to work with multiple data sources – so for example the “alfresco/lists/AlfList” widget can be used to render any list – documents, sites, people, properties, aspects, etc. All data should be accessed via a service.

Services in Aikau can be considered the glue that binds the page together. They can perform a number of roles as well as handling XHR requests – the “alfresco/services/DialogService” for example is purely responsible for the creation and management of modal dialogs. If you don’t like the default dialogs in Aikau then an alternative service can be used instead – widgets don’t “care” what services their request for a dialog, only that it is serviced.

The most common role of a service though is to make asynchronous (XHR) requests for data from the Alfresco Repository. A widget will publish a request for some data on a specific topic and if a service exists that subscribes to that topic then it will process that request, retrieve the requested data from the Alfresco repository and return it to the widget on the requested response topic.

Dipping back very briefly into the subject of publication/subscription scoping…. Services are typically not scoped. However, in order that widgets are able to communicate with them all publication configuration can include an option to publish “globally” – or without scope. This ensures that it is not necessary to have instances of services at every scope used by widgets on the page.

Putting It Altogether

An Aikau page is declared as a model in a WebScript JavaScript controller. I typically describe this as a JSON model and am frequently criticized by my colleagues for describing it as such because in the WebScript controller you are technically creating a JavaScript Object Literal – but on it’s way to being processed by Surf it does get converted into JSON, so I’m going to keep calling it JSON.

The structure of the model in your JavaScript controller should look like this:

model.jsonModel = {
  services: [],
  widgets: []
};

…services and widgets being added into the appropriate arrays.

The “widgets” model will typically become a deeply nested tree with widgets placed inside other widgets.

By constructing a page like this is means two things:

  1. It is possible to intercept and customize a default model before it is processed. This means that extensions can add, remove and reconfigure widgets and the fact that widgets are decoupled means that this can be done without causing reference errors
  2. Page models can be dynamically constructed and rendered safely on a running server (as demonstrated numerous times over the last year at various Alfresco conferences and Tech Talk Live sessions)

The disadvantage of this approach is that for simplicity you normally have to rely on the various widgets in the “alfresco/layout” package to build the structure of your page rather than just using HTML/CSS.

However it is possible to embed Aikau into any DOM node on the page by including a “rootNodeId” attribute in your model. This would allow you to construct the layout for your page in your WebScript template using HTML into which the Aikau model could be built.

It’s also possible to have multiple Aikau models embedded into different locations on the page – the best approach for this would be to use the standard Surf region/component development approach. Effectively this is what you see on most pages in Share – the header is a Surf Component rendering an Aikau model and the remainder of the page is made up of other Surf Components rendering YUI2.

Summary

Aikau is really just a way of packaging HTML, CSS and JavaScript into reusable modules. It isn’t a new language, but is merely a new way of thinking about web development. This approach has its advantages (reuse, extensibility, customization, dynamic page creation) but also has its drawbacks (requires a different way of thinking, is a layer of abstraction away from traditional web development).

It’s not a framework for any use case – it’s targeted specifically for Alfresco development and depending upon your specific use case it may or may not be the right choice for you. It is worth remembering that unless we know your use cases we’ll never be able to address them – so if there’s something you’d like Aikau to do better then please let us know!


Aikau 1.0.66 – Angular 2 Integration

$
0
0

Introduction

One of the greatest misconceptions about Aikau is that it is somehow aiming to compete with other UI frameworks and libraries such as Angular and React. This really isn’t the case – Aikau is designed to address specific use cases that no other UI framework meets.

This isn’t trying to say that Aikau is in any way better – it’s just that it can do things that other frameworks can’t. We have integrated other frameworks such as Dojo, JQuery and YUI2 into Aikau – but Angular has been somewhat conspicuous by its absence.

There are a couple of key reasons for this:

  1. Angular 1 doesn’t really “play nicely” with other frameworks, although Angular 2 does a much better job of this
  2. Quite honestly there has never been a truly compelling reason to integrate it.

It’s worth remembering the granularity of Aikau widgets and how they are fully decoupled from both each other and the data that they use. Whilst this approach has been key to supporting the dynamic customization use cases, it has not lent itself particularly well to making use of the capabilities that Angular provides.

As you may have heard from recent announcements at BeeCon, Alfresco is looking to start making greater use of Angular 2 for the development of new applications but that it intends to continue to develop Aikau for use in Share.

Recent Announcements

That doesn’t mean that Share is not capable of making use of Angular 2 (or indeed any of the other modern UI frameworks such as React, Ember, etc). In my previous post I showed how modern web development practices could be integrated into Share and in this post I’m going to demonstrate how to make use of some new capabilities available in the 1.0.66 release of Aikau that will allow you to seamlessly insert Angular 2 code into an Aikau page in Share.

One important thing to be aware of… the widget that will be demonstrated resides under a new “alfresco/experimental” package in the Aikau library – anything under this package does not fall into the usual backwards compatibility rules of Aikau and as such maybe changed or removed at any time. If this widget appears useful then you should let us know and we’ll look to make it a fully fledged Aikau widget so that it gets all the backwards compatibility guarantees that this brings.

In this example we’re going to be integrating an example from the Angular 2 tutorial into the faceted search page in Share. Doing so holds no value other than to demonstrate that it can be done.

Step 1. Get Aikau release

First of all, you need to make sure you have downloaded the 1.0.66 release of Aikau and have placed it in the “share/WEB-INF/lib” folder.

Step 2. Create extension

Now you need to create an extension module for the faceted search page. The quickest way to do this is to follow the steps in this blog post to download an extension JAR file for the faceted search page.

Step 3. Create a package definition

Unpack the JAR file somewhere and edit the the “alfresco/site-data/extensions/extension.xml” file to add in a new AMD package declaration for the Angular 2 tutorial code (background information on defining new AMD packages via extensions can be found in the Alfresco Documentation here.

<extension>
  <modules>
    <module>
      <id>Angular 2 Tutorial Extension</id>
      <auto-deploy>false</auto-deploy>
      <evaluator type="default.extensibility.evaluator"/>
      <configurations>
        <config evaluator="string-compare" condition="WebFramework" replace="false">
          <web-framework>
            <dojo-pages>
              <packages>
                <package name="blog" location="js/blog"/>
              </packages>
            </dojo-pages>
          </web-framework>
        </config>
      </configurations>
      <customizations>
        <customization>
          <targetPackageRoot>org.alfresco.share.pages.faceted-search</targetPackageRoot>
          <sourcePackageRoot>org.alfresco.share.pages.faceted-search.customization</sourcePackageRoot>
        </customization>
      </customizations>
    </module>
  </modules>
</extension>

Next you want to copy the “main.ts” and “app.component.ts” (these can be copied from here) into the “META-INF/js/blog” folder.

Step 4. Edit the controller extension

Now you want to update the generated JavaScript controller extension (“alfresco/site-webscripts/org/alfresco/share/pages/faceted-search/customization/faceted-search.get.js”) to make a dynamic request to add the new Angular 2 widget into the page.

Add the following code into the file:

var verticalStack = widgetUtils.findObject(model.jsonModel.widgets, "id", "FCTSRCH_MAIN_VERTICAL_STACK");
if (verticalStack && verticalStack.config && verticalStack.config.widgets)
{
  verticalStack.config.widgets.unshift({
    name: "alfresco/experimental/ng2/Bootstrap",
    config: {
      main: "blog/main.ts",
      templateString: "<my-app>Loading...</my-app>"
    }
  });
}

The Bootstrap Widget

The widget being added is the “alfresco/experimental/ng2/Bootstrap” widget. The purpose of this widget is to bootstrap the example from the Angular 2 tutorial. Here we are choosing to insert the example above the main search controls.

There are two configuration attributes:

  • “main” is the root Angular 2 component to load that should include the call to bootstrap Angular 2
  • “templateString” is the DOM fragment that contains the custom elements that the Angular 2 component will be looking to parse during bootstrapping.

Once you’ve made these changes you can re-pack the JAR file and copy it to the “share/WEB-INF/lib” folder.

Restart Share and perform a search. Initially you won’t see anything different – this is because the module has not been applied. More importantly, a second extension module provided by the Aikau JAR is also required.

Step 5. Deploy the modules

Navigate to the Module Deployment page (“/share/page/modules/deploy”) and add the “Angular 2 Tutorial Extension” and the “Angular 2 Support (version 1.0.66) module and click the “Apply Changes” button.

Screenshot from 2016-05-03 09:35:54

The “Angular 2 Support” module adds all of the required Angular 2 JavaScript dependencies that are required – most importantly it loads System.js that is used to transpile the TypeScript and handle the ES6 import calls.

Once you have applied these modules you can reload the search page and you’ll see the tutorial example displayed like so:

Screenshot from 2016-04-28 21:23:02

Summary

Obviously this example has no practical purpose whatsoever. However the technique could be used to for much more sensible use cases.

It’s worth noting that, from the moment you bootstrap into an Angular 2 component, you are completely leaving Aikau behind and all future imports should be done via the ES6 import approach as shown in the Angular 2 tutorials.

It’s also important to recognize that this is not suitable for production purposes, because in reality you would want to transpile and compress the Angular 2 code before using it.

If you think the “alfresco/experimental/ng2/Bootstrap” widget would be useful to be made a first class Aikau widget then please let us know – if enough people are interested then we’ll move it to an appropriate package and make it product ready.

Download the Source

You can download the extension module source from this folder in a new GitHub repository that I’ve setup.

Material Designed Aikau

$
0
0

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.

Adding the Aikau Document Library as a Site Page in Share

$
0
0

Introduction

In previous blog posts I’ve shown examples of how the Aikau version of the Document Library can be used both within Share and in standalone clients. In this blog post I thought it might be useful to provide a more in-depth guide on how to add the Aikau Document Library as a site page in Share, as well as to provide a general status update on progress.

Background

It’s important to understand that the Aikau team is a “Component Team” and not a “Feature Team”. This means that we provide the components (in this case Aikau widgets and services) for other teams to deliver features or products.

At the time of writing there is no feature team driving the replacement of the old YUI2 Document Library with the Aikau version – nor indeed has there ever been. Aikau has always predominantly been about re-use and the Document Library has progressed because other features have required Document Library related widgets.

There are two epics in JIRA that list the current tasks required to achieve feature parity with the YUI2 Document Library: one for general features and one for action support. Reviewing these epics should give an overview of what work remains.

In general the Document Library is quite functional and should be more than adequate for covering a large number of use cases. The following steps and code is available within the following GitHub repository and all of the files described before are linked to the specific files in that repository.

Create the Aikau Document Library Page

The first step is to create the WebScripts for the new page. Create the WebScript descriptor file…

DocLib.get.desc.xml

<webscript>
  <shortname>Document Library Example </shortname>
  <description>This provides an example of building the standard Document Library using the doclib.lib.js library file.</description>
  <family>Aikau</family>
  <url>/DocLib</url>
</webscript>

Now let’s create the template…

DocLib.get.html.ftl

<@processJsonModel/>

The properties file is slightly more involved…

DocLib.get.properties

surf.include.resources=org/alfresco/share/imports/share-header.lib,org/alfresco/aikau/{aikauVersion}/libs/doclib/doclib.lib

This file just contains an instruction to import two other properties files:

  • org/alfresco/share/imports/share-header.lib
  • org/alfresco/aikau/{aikauVersion}/libs/doclib/doclib.lib

This process is described in more detail in this previous blog post.

The last WebScript file required is the JavaScript controller… this is where most of the code goes:

DocLib.get.js

The first thing is to import the required controller files…

<import resource="classpath:/alfresco/site-webscripts/org/alfresco/share/imports/share-header.lib.js">
<import resource="classpath:/alfresco/site-webscripts/org/alfresco/share/imports/share-footer.lib.js">
<import resource="classpath:alfresco/site-webscripts/org/alfresco/aikau/{aikauVersion}/libs/doclib/doclib.lib.js">

Now you need to import the services and widgets that the header uses…

var services = getHeaderServices();
var widgets = getHeaderModel(msg.get("aikau.doclib.title"));

The header services need to be combined with the services required by the Document Library. These can be retrieved by calling getDocumentLibraryServices.

services = services.concat(getDocumentLibraryServices());

Now use the getDocLib function to create the model for the Document Library. The main data to provide is the site id which is available from a template argument and the name of the folder in which the Document Library files can be found within the site folder (typically “documentLibrary”).

var docLib = getDocLib({
  siteId: page.url.templateArgs.site,
  containerId: "documentLibrary"
});

This model needs to be added to the header model….

widgets.push(docLib);

Finally we need to call getFooterModel passing in the header and Document Library services and widgets. This is required because the footer model wraps everything else on the page.

model.jsonModel = getFooterModel(services, widgets);

Make the Document Library a Site Page

In this previous post I describe the process for adding Aikau pages in general – so please refer to that for a slightly more in-depth description of the process.

Create a new Surf Page definition that will provide the title and description of the page as shown when customizing sites.

AikauDocLib.xml

<?xml version='1.0' encoding='UTF-8'?>
<page>
  <title>Aikau Document Library</title>
  <description>The Aikau Document Library</description>
</page>

Now create an extension module to ensure that the site page is an option when customizing sites.

Aikau-document-library.xml

<extension>
  <modules>
    <module>
      <id>Aikau Document Library Site Page</id>
      <auto-deploy>true</auto-deploy>
      <evaluator type="default.extensibility.evaluator"/>
      <configurations>
        <config evaluator="string-compare" condition="SitePages" replace="false">
          <pages>
            <page id="AikauDocLib">dp/ws/DocLib</page>
          </pages>
        </config>
      </configurations>
    </module>
  </modules>
</extension>

Now you need to pull these files together into a single JAR and copy them to the “share/WEB-INF/lib” folder.

AikauDocLib4

Restart Share and go to any site and customize it – you should see the “Aikau Document Library” in the list of available pages:

AikauDocLib1

Drag it into the “Current Site Pages” list and click “OK”

AikauDocLib2

Now you should have a new link for the “Aikau Document Library” (if you have a lot of site pages, try looking under the “More” drop-down menu!). Click on the link and you’ll be taken to your the Aikau Document Library:

AikauDocLib3

What Are The Benefits and Limitations?

One of the main reasons for creating an Aikau version of the Document Library was to make customization much simpler. Through the use of the Aikau model it is significantly easier to make fine-grained changes to the Document Library. Some things you could do for example would be:

  • Add custom views
  • Edit existing views (add or remove the metadata that is displayed)
  • Filter the displayed actions or add entirely new actions
  • Render only specific sections of the Document Library (the tree, breadcrumb trail or list for example)
  • Edit the menu options that are displayed

The Aikau version also has a few features that are not included with the original Document Library:

  • Drag-and-drop upload new version
  • Inline document preview
  • Inline commenting
  • Inline content creation

As of Aikau 1.0.68 the Document Library uses a new non-modal upload file design. See screenshot below:

AikauDocLib5

The main limitation is that there is not yet support for all the actions that you would find in the existing Document Library (you can review the missing actions in the previously linked epic).

The other potential limitation is the lack of integration with the forms runtime. This means that when editing properties for custom types the XML forms configuration will not be represented.

Despite these issues the Aikau Document Library should still be useful for many use cases – especially where serious customization of the existing Document Library is required.

Developing With Aikau – Another Perspective

$
0
0

I’ve recently been moved out of the Aikau team in order to provide some assistance to a feature team that are using Aikau. This change in role has given me a very useful insight into the problems that developers have when using Aikau. When working on Aikau I only ever get to see a fragment of the overall implementation – I get very little context so I never know if the overall implementation is being done in a sensible way.

It’s important to remember that we never think of Aikau as being “done”. Our widgets are always open to further iteration to either add more capabilities, refactor them for better performance, improve the design and fix any bugs. We also don’t consider them to be an exhaustive set by any means – we know that more widgets will be needed.

What we don’t know is what bugs exist, what features could be added and what widgets are missing. We rely on our feature teams, customers, partners and community to tell us what is required.

When I started working on the feature I was given in the new team I almost immediately identified one bug and 3 features (1,2,3) that were required. This wasn’t a brand new requirement for my new feature team but these requirements hadn’t been identified.

Trying to act like a good community citizen I raised these as issues on JIRA and then being a model community citizen I created pull requests to fix the problem and add the features following the well defined acceptance criteria.

Of course it’s much easier to do this when you have an awareness of what is available and how things are meant to work in a framework when you have been involved in the development of that framework. Having said that I really want to encourage you to just ask the question and start the dialog with us.

It should hopefully be clear from the closed issues that we’re more than happy to answer questions when they’re asked.

The flip side of the coin is to not start a dialog but to simply complain about something without trying to dig into the details like with this blog post published last week. Whilst I understand that something might not be immediately obvious when trying to use Aikau (we’re well aware that documentation could be improved, we just haven’t been allocated the resources to do enough about it) we will try and help you if we can – even if that help is simply explaining why something is the way it is.

We aren’t promising to implement all your feature requests (far from it in fact!) but we are committed to genuine bugs in our coding (meaning a defect in the intended behaviour of an individual widget or service).

We’re starting to see increased Community interaction – more issues raised, more traffic, more GitHub stars. What we’d really like to see is more pull requests – and if something is blocking you from making a pull request then we’d like to know what that impediment is so that we can remove it.

This is going to be especially important during my reassignment as it means that we might not be able to implement community requested features as we have in the past – but we will endeavour to try to stay on top of the bugs that you raise.

Thanks again for your ongoing support !

Improving Aikau Education

$
0
0

Introduction

In my last blog post I talked about the perspective I’d gained by working in another team at Alfresco that has been using Aikau. For the last 18 months the Aikau team has been so head down in development trying to provide features and fixes for internal teams, customers and the community that we’ve not had much opportunity to focus on reviewing and improving the educational material that is available for Aikau.

Interestingly with the advent of the new Angular based UI framework and the conclusion of a number of major Alfresco projects that use Aikau the heat is now off us and I’ve had some time to start looking at what resources are available and how we can improve the situation.

At this point I think it’s important to state that as far as I’m aware Aikau development is going to continue and that if you want to develop a user interface for Alfresco – particularly if you want to customize or add new pages to Share – then Aikau is still the recommended framework.

Alfresco is still actively using Aikau (most notably for Records Management in Share) which is hugely important for its business. The use of Aikau is never going to be the headline feature in an Alfresco release, but it’s usually there in the background getting the job done.

Eating Our Own Dog Food

I decided to have a go at reproducing some existing YUI2 based features of Share using Aikau to try and showcase how rapid development can be – but more importantly to try to understand where the gaps might be in available education.

I’ve started with the “People” page and you can watch me creating this page from scratch in a brand new client in the video below. It’s a bit rough around the edges, for which I make no apologies – but hopefully it will be informative.

 

Feedback Wanted !

The full disclosure is that the first time I went through the process I found that some of the JSDoc could be better, we could provide some additional widgets and that the UserService needed updating – and I took care of these issues before recording the demo.

However, I would urge that anyone attempting to do any development that has similar problems to report them as a GitHub issue so that they can be addressed.

I’d also love your feedback on whether or not this medium is effective or not, whether I should record more demos and what they should be focused on. I’ve already got an idea for a follow up in developing some custom widgets to go on the page – but it might be better to work through an entirely different use case – Data Lists perhaps?

I’d also welcome any suggestions on other approaches we could take to help people get up to speed with Alfresco development using Aikau.

Accessing the Code

I’ve created a GitHub repository containing the application that I built in the video. I’ve tagged the commit with the code (and will continue to tag each commit if I do more examples) so that it’s easy to try out the code and experiment with it yourself.

Viewing all 43 articles
Browse latest View live


Latest Images