Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > Authors ddraper
1 2 3 4 5 Previous Next

Alfresco Content Services (ECM)

104 Posts authored by: ddraper

Introduction

This post is going to describe how you can build next-generation web client technologies into Share and standalone web-clients. I’ve taken a pre-existing tutorial that I found on the Smashing Magazine web site and have adapted it for use in Surf. This is simply a demonstration that Share does not prohibit the use of any of these technologies and the method shown here is by no means the only way in which this task could be accomplished. The intention here is to shed further light on some of the Surf concepts.

 

You might be wondering why would you want to do this? Why not just go the whole hog and re-implement everything on a Node stack?

 

One reason is that you might simply want to add an existing page into Share and that you don’t want to have to reimplement all the features that Share currently provides. It’s also important to remember that through its use of Surf, Share is able to take care of a host of issues that you never need worry about - a single point of authentication to an Alfresco Repository across multiple REST APIs (CMIS, WebScripts, Public API) being the most obvious.

 

Rather than working with Share though, in this instance we’re going to create a standalone client using the Aikau Maven Archetype. We’re not going to be using Aikau, but it’s worth being aware that the archetype will build you a client that has everything you need to authenticate against an Alfresco Repository.

 

I’m not going to go through the details of the next-generation concepts as these are well documented in the Smashing Magazine article and you can read up on them there if you’re not familiar with them yourself.

 

Essentially we’re going to be writing ES6 JavaScript that is transpiled to ES5 via Babel, compiled into a single module (with associated source maps) using WebPack and minimized using Uglify. The whole JavaScript build process will be taken care of using Gulp and will all be wrapped within a Maven build.

 

Short Cut to Code

If you don't want to manually follow all the steps you can find the source code that you would otherwise build in this GitHub repository.

 

Pre-Requisites

You have Node.js, NPM and Maven installed

 

Create a new client

Execute the following command in a location where you want to create your project

mvn archetype:generate -DarchetypeCatalog=https://artifacts.alfresco.com/nexus/content/groups/public/archetype-catalog.xml -DarchetypeGroupId=org.alfresco -DarchetypeArtifactId=aikau-sample-archetype -DarchetypeVersion=RELEASE

 

Enter suitable suitable group and artifact ids and accept the remaining defaults (for example, I’ve used “org.alfresco” as the groupId and “next-gen” as the artifactId).

 

Building from an archetype is described in more detail in the Aikau tutorial.

 

Install gulp and webpack globally

Run the following command:

npm install -g gulp, webpack

 

Create Build Files

Create your package.json file in the root of the project

{
  'name': 'next-gen',
  'version': '0.0.1',
  'devDependencies': {
    'babel': '^5.8.23',
    'babel-core': '^5.8.24',
    'babel-eslint': '^4.1.1',
    'babel-loader': '^5.3.2',
    'eslint': '^1.4.1',
    'gulp': '^3.9.0',
    'gulp-babel': '^6.1.2',
    'gulp-rename': '^1.2.2',
    'gulp-sourcemaps': '^1.5.2',
    'gulp-uglify': '^1.4.1',
    'webpack': '^1.12.1',
    'webpack-stream': '^2.1.0'
  }
}

 

Create a webpack.config.js file in the root folder:

module.exports = {
  entry: './src/js/index.js',
  output: {
    library: 'legoQuotes',
    libraryTarget: 'umd',
    filename: 'lib/legoQuotes.js'
  },
  externals: [
    {
      lodash: {
        root: '_',
        commonjs: 'lodash',
        commonjs2: 'lodash',
        amd: 'lodash'
      }
    }
  ],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          compact: false
        }
      }
    ]
  }
};

 

Create a gulpfile.js file in the root folder:

var gulp = require( 'gulp' );
var webpack = require( 'webpack-stream' );
var sourcemaps = require( 'gulp-sourcemaps' );
var babel = require('gulp-babel');
var rename = require( 'gulp-rename' );
var uglify = require( 'gulp-uglify' );

gulp.task('default', function() {
  return gulp.src( 'src/js/index.js' )
    .pipe( babel() )
    .pipe( webpack( require( './webpack.config.js' ) ) )
    .pipe( gulp.dest( './src/js/dist' ) )
    .pipe( sourcemaps.init( { loadMaps: true } ) )
    .pipe( uglify() )
    .pipe( rename( 'legoQuotes.min.js' ) )
    .pipe( sourcemaps.write( './' ) )
    .pipe( gulp.dest( './src/js/dist/' ) );
  });

 

For more information on what these files do, you should read the Smashing Magazine article - the purpose of this blog is not to explain these things, simply to show how they can be used with Share/Surf.

 

Create JavaScript resources

This should be placed in the “src/js” folder of your project - note that it is intentionally not in the “src/main” folder as we are going to build the JavaScript separately from the rest of the project. The files you want are:
 

    • benny.js 
    • emmet.js 
    • index.js 
    • LegoCharacter.js 
    • utils.js 
    • wyldstyle.js


These can be found in the linked source from the Smashing Magazine article, they are only provided for something to build!

 

Create CSS resources

Copy the 'style.css' from the linked source into a new folder called 'css' in 'src/main/webapp/'. We could use WebPack to bundle up CSS resources but we're going to let Surf take care of this as we'll see later.

 

Maven Updates

We now want to update our pom.xml to allow us to build our next-gen resources as part of the Maven build. Add the following to the <build> <plugins> element:

<plugin>
  <artifactId>maven-antrun-plugin</artifactId>
  <version>1.8</version>
  <executions>
    <execution>
      <id>Installation</id>
      <phase>validate</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <target>
          <echo>NPM Package Installation</echo>
          <exec executable='npm' dir='${project.basedir}'>
            <arg line='install' />
          </exec>
          <echo>Run Gulp Build</echo>
          <echo>Build and overlay JS</echo>
          <exec executable='gulp' dir='${project.basedir}'>
          </exec>
        </target>
      </configuration>
    </execution>
  </executions>
</plugin>

 

Here we’re using the Maven Ant Run plugin to get all the required Node packages (defined in the package.json file) and call Gulp to perform the build.

 

So somewhat impressively we’re using Ant, Maven and Gulp!

 

Next we want to ensure that we copy our JavaScript and required Node modules into the web application that we’re going to build. Add the following plugin configuration after the previous entry that you just added:

<plugin>
  <artifactId>maven-resources-plugin</artifactId>
  <version>2.7</version>
  <executions>
    <execution>
      <id>copy-node-modules</id>
      <phase>validate</phase>
      <goals>
        <goal>copy-resources</goal>
      </goals>
      <configuration>
        <outputDirectory>${basedir}/target/aikau-sample/node_modules</outputDirectory>
        <resources>
          <resource>
            <directory>${basedir}/node_modules</directory>
          </resource>
        </resources>
      </configuration>
    </execution>
    <execution>
      <id>copy-javascript</id>
        <phase>validate</phase>
        <goals>
          <goal>copy-resources</goal>
        </goals>
        <configuration>
          <outputDirectory>${basedir}/target/aikau-sample/js</outputDirectory>
          <resources>
            <resource>
              <directory>${basedir}/src/js</directory>
            </resource>
          </resources>
        </configuration>
      </execution>
    </executions>
</plugin>

 

Finally we need to make one more change. The Aikau archetype configures the Jetty plugin to use the “src” rather than “target” location to enable fast development, but for a cleaner build we are copying the “node_modules” into target so need to change the plugin configuration appropriately.

 

Update the <webApp> section so that all instances of “src/main/webapp” are replaced with “target/aikau-sample”

 

Create Surf Objects

We now have our build in place, so it’s time to create the required Surf objects.

 

Surf has a complex but powerful set of objects for constructing pages. One of the goals of Aikau was to hide these objects away from developers to allow them to focus on creating pages with just WebScripts. We’re now going to build some of these objects and it may become apparent why we wanted to hide this complexity away.

 

The first thing we need to create is a Page object. This is defined as XML file and the key thing you can define in this file is what level of authentication the user requires to access the page. Here we’re going to use “none” because we want to avoid a login step - however, you could just as easily set the value to be “user” or “admin”.

 

Create a file called “next-gen-page.xml” in the “src/main/webapp/WEB-INF/surf-config/pages/” folder. It should contain the following XML.

<?xml version='1.0' encoding='UTF-8'?>
<page>
  <id>ngp</id>
  <template-instance>next-gen-template-instance</template-instance>
  <authentication>none</authentication>
</page>

 

The Page references a Template-Instance to be rendered. This is the next file to declare. Create a file called “next-gen-template-instance.xml” in the “src/main/webapp/WEB-INF/surf-config/template-instances” folder. It should contain the following XML:

<?xml version='1.0' encoding='UTF-8'?>
<template-instance>
  <template-type>next-gen-template-type</template-type>
</template-instance>

 

The Template-Instance references a Template-Type - this needs to be declared. Create a file called “next-gen-template-type.xml” in the “src/main/webapp/WEB-INF/surf-config/template-types” folder. It should contain the following XML:

<?xml version='1.0' encoding='UTF-8'?>
<template-type>
  <title>Next Gen Page</title>
  <processor mode='view'>
    <id>webscript</id>
    <uri>/next/gen/page/template</uri>
  </processor>
</template-type>

 

A Template-Type can have a number of different processor modes. We really only care about the “view” mode (the other modes were created for WCM purposes that are not widely used anymore). Surf supports a number of different processors out-of-the-box and it is possible to configure in additional processors. Here we’re using a WebScript processor and are providing the URI to match against a WebScript.

 

This WebScript needs to be defined. In the “src/main/webapp/WEB-INF/webscripts” folder create the following files:

 

next-gen-page.get.desc.xml

<webscript>
  <shortname>Template For Next Gen Pages</shortname>
  <family>Page Templates</family>
  <url>/next/gen/page/template</url>
</webscript>

 

next-gen-page.get.html.ftl

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Lego Quote Module Example</title>
  </head>
  <body>
    <div class='container'>
      <blockquote id='quote'></blockquote>
      <button id='btnMore'>Get Another Quote</button>
    </div>
    <script src='${url.context}/node_modules/lodash/index.js'></script>
    <script src='${url.context}/node_modules/babel-core/browser-polyfill.js'></script>
    <script src='${url.context}/js/dist/legoQuotes.min.js'></script>
    <script>
      (function(legoQuotes) {
        var btn = document.getElementById('btnMore');
        var quote = document.getElementById('quote');

        function writeQuoteToDom() {
          quote.innerHTML = legoQuotes.getRandomQuote();
        }

        btn.addEventListener('click', writeQuoteToDom);
        writeQuoteToDom();
      })(legoQuotes);
</script>

</body>
</html>

 

Create Reusable Page Structure

We don’t want to have to create all of these files (page, template-instance, template-type, WebScript) for every single page in our application (of course if you’re building a Single Page Application then you’re only going to need to do this once). So instead we’re going to abstract the WebScript file contents into an include template and then make it possible to parametrize a WebScript to run as is done in Aikau.

 

Let’s update the template file so that is looks like this:

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Next Gen Example</title>
    <script src='${url.context}/node_modules/lodash/index.js'></script>
    <script src='${url.context}/node_modules/babel-core/browser-polyfill.js'></script>
    <@outputJavaScript/>
    <@outputCSS/>
  </head>
  <body>
    <#assign regionId = page.url.templateArgs.webscript?replace('/', '-')/>
    <@autoComponentRegion uri='/${page.url.templateArgs.webscript}'/>
  </body>
</html>


In this example we are using 3 custom FreeMarker directives that Surf provides:
 

    • <@outputJavaScript/> 
    • <@outputCSS/> 
    • <@autoComponentRegion>


The first two mark the location where page specific JavaScript and CSS will be output - in a moment we’ll show how to define what should be output.

 

The <@autoComponentRegion> is used to automatically create a Surf Region and a Surf Component for the WebScript that we’re going to use to define the page. The URI for the WebScript to use is taken from the same UriTemplate that is configured for Aikau pages.

 

Let’s now create the WebScript for our page. Create the following files in the “src/main/webapp/WEB-INF/webscripts/pages” folder.

 

First the descriptor: “LegoQuotes.get.desc.xml”

<webscript>
<shortname>LegoQuotes</shortname>
<family>Next Gen Pages</family>
<url>/legoQuotes</url>
</webscript>

 

The key thing to note here is the <url> - we’re going to be using that when we load our page.

 

Now the template, “LegoQuotes.get.html.ftl”

<@link rel='stylesheet' type='text/css' href='${url.context}/res/css/style.css'/>
<@script type='text/javascript' src='${url.context}/res/js/dist/legoQuotes.min.js'/>
<@inlineScript>
  (function(legoQuotes) {
    document.addEventListener('DOMContentLoaded', function(event) {
      var btn = document.getElementById( 'btnMore' );
      var quote = document.getElementById( 'quote' );

      function writeQuoteToDom() {
        quote.innerHTML = legoQuotes.getRandomQuote();
      }

      btn.addEventListener( 'click', writeQuoteToDom );
      writeQuoteToDom();
    });
  })(legoQuotes);
</@>

<div class='container'>
<blockquote id='quote'></blockquote>
<button id='btnMore'>Get Another Quote</button>
</div>


Again, we’re using 3 new FreeMarker directives

    • <@link> 
    • <@script> 
    • <@inlineScript>


The <@link> directive is how we reference CSS files to be output into the location of the <@outputCSS/> directive that we declared in our template.

 

The <@script> directive references JavaScript files to be output into the location of the <@outputJavaScript/>.

 

The <@inlineScript> directive allows us to write snippets of JavaScript that will be inserted at the location of the <@outputJavaScript/> directive.

 

There are two benefits to be aware of here - firstly all JavaScript and all CSS will be combined so that only a single resource of each type will be loaded onto the page - this reduces HTTP handshaking and improves performance.

 

Secondly the generated resources will have a name that is an MD5 checksum matched to their content. This means that these files can be infinitely cached on the browser as if the content changes a different resource name will be generated.

 

The End Result

Now run the following command:

mvn clean install jetty:run

 

Be aware, it will probably take a few minutes to build and startup - please be patient.

 

Once you see the message: “[INFO] Started Jetty Server”, open the URL “http://localhost:8090/aikau-sample/page/ngp/ws/legoQuotes” in your browser and you should see the following:

 

Next-Gen-2

 

You can now click the button to generate random Lego Movie quotes.

 

Summary

In this post I've demonstrated that it is possible to make use of the current crop of tools for building web applications without discarding the benefits that Surf brings to the table with regards to creating clients for Alfresco. In the process I've hopefully been able to provide some useful information on creating Surf objects.

Aikau 101

Posted by ddraper Apr 22, 2016

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!

    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

    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.

    Introducing the Aikau Sandpit

    Posted by ddraper Jan 26, 2016

    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.

    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.

    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 Update August 2015

    Posted by ddraper Sep 1, 2015

    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 

     

     

    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 

     

     

    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

     

    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.

     

    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

     

    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  

     

    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, May 2015

    Posted by ddraper May 12, 2015

    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 

     

    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

     

    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 

     

    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 

     

    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 

     

    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 

     

    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.

    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.

     

     

     

     

     

     

     

     

    'Eddie would go'

    Posted by ddraper Feb 24, 2015

    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!

    By Dave Draper, Kevin Roast, Erik Winlöf and David Webster

    Introduction



    Over the last 4 years (from versions 4.0 through to 5.0) there have been a number of changes in relation to Share development and customization.



    From an outside perspective the decisions that have been made might appear confusing or frustrating depending upon your particular use case of Share. If you've written Share extensions or customizations for previous versions then you might have hit breaking changes between major releases and you might be fearful of it happening again.



    It might seem that we don't care about these issues. We’re sorry if you have experienced such problems but we can assure you that we try our very best to move Share forwards without breaking what has gone before.



    In this post we're going to highlight how things are better than they would have been if different decisions were made.

    Decision #1 - Extensibility model



    Back in 2010 we introduced an extensibility model that enabled us to dynamically change a default Share page via an extension module. This was an initially coarse customization approach that enabled Surf Components to be added, removed or replaced as well as our custom FreeMarker directives to be manipulated.



    This in turn paved the way for us to refactor the Share WebScripts in 4.2 to remove the WebScript .head.ftl files and push the widget instantiation configuration into the JavaScript controller.



    If we hadn't have taken this approach then the method of customization would still be copy and pasting of complete WebScript components to the 'web-extension' path.



    This wouldn't have stopped breaking changes between versions (e.g. the REST API changing, the Component calling a different WebScript, different properties or URL arguments being passed, etc) and would have required constant manual maintenance of those WebScripts with code from service pack fixes as necessary.

    Decision #2 - New Java based client



    We know that a few customers still use heavily customised versions of Explorer and the fact that we've finally removed it from 5.0 is going to cause pain to a few.



    It has been suggested at various points over the last 4 years that we could create a brand new client to replace Share - even though Share does not yet have complete feature parity with Explorer. We recognise now that we need to invest in Share and improve it over time since creating a new client would ultimately introduce more problems than it solves.



    However, when calls were strongest for writing a new client, the recommendation was to move to either GWT or Vaadin. We're fairly sure all those people that lament the fact that this week we're not using Angular would be horrified if they were now stuck with a Java based client that doesn't have feature parity with Share (let alone Explorer).



    A new Java based client would have guaranteed that all those customizations would have to be re-written from scratch.

    Decision #3 - Aikau



    In our opinion it feels like some people miss the point of Aikau. Often we field questions along the lines of:



    • 'Why do we have to use Dojo?' (you don't)


    • 'Why have you written your own JavaScript framework?' (we haven't)


    • 'Why aren't you using Angular/Ember/React/Web Components?' (many good reasons; customization and configuration requirements, framework stability, performance etc.)



    As it was said on the Product Managers Office Hours last week; 'web technologies change every 3 years'. It’s probably even more often than that. In the short time that Share has existed there has been a constant changing of the guard for 'best web development framework'.



    Even if we started again tomorrow with Angular (the current populist choice), we'd be doing so in the knowledge that there will be breaking changes when Angular version 2.0 is released next year and that in a few years we'll (allegedly) all be using Web Components anyway.



    The long and short of it is that unless you're writing an application that is only going to have the lifespan of the carton of milk in your fridge then binding yourself to a single JavaScript library will be a mistake.



    With Aikau we're trying to mitigate that problem through declarative page definition. Yes, you have to write a bit of AMD boilerplate but really the choice of JavaScript framework is entirely in your hands.



    Aikau isn't tied to Share (theoretically it's not even tied to Surf) so if we do ever do switch to a new client then the existing widgets and your custom widgets will still be applicable. We’re also evaluating breaking Aikau out of the Share development life-cycle so that we can make new widgets and bug fixes available faster.

    Will there be more breaking changes?



    We've been talking about re-writing the Document Library using Aikau for a while now (and have a pretty good prototype already) along with the other site pages. However, just as the old header Component still exists in Share, the original pages will still remain so you'll always be able to configure Share to use the current YUI2 Document Library with your customizations.



    There is also a lot of talk about re-writing the rest of Share in Aikau. Whilst we think this is ultimately a good idea we don't think it's worthwhile until we've gone to the trouble of evaluating and improving the current design.... do you really only want a carbon copy of the current Wiki, Blogs and Data List pages? We’ll get there in time, but we're not sure there’s any great rush to get this all done for 5.1.

    Summary



    Ultimately, any web interface needs to keep modifying its underlying technology. Aikau gives us a way to do that with the least possible pain. We understand that some developers have gone through some suffering with breaking changes in the last few releases, but through the use of Aikau we expect this pain to decrease and customisations to become more stable, transferable and powerful.



    We’re working to add transparency to the development process that will hopefully make what we’re working on more obvious and make it easier for external developers to predict what changes there may be in future Share releases.

    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 

     

    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.

    Filter Blog

    By date: By tag: