Alfresco Share (share.war) is a web application that runs on the Java Platform. In a development environment it is usually deployed and run on top of Apache Tomcat. Share is built up of a main menu that leads to pages, which is similar to most other web applications that you might come across. However, there is one special page type called Dashboard that contains Dashlets. A Dashboard page can be configured by the end-user, who can add, remove, and organize the Dashlets on the page.Share pages and Dashlets are implemented with something called Web Scripts, which is basically Rest-based APIs. These APIs are called Surf Web Scripts when you are dealing with the Alfresco Share web application. There is also Repository Web Scripts that are used to extend the Alfresco Repository web application (i.e. alfresco.war) with Rest-based APIs. We usually refer to the Surf Web Scripts as Presentation Web Scripts and the Repository Web Scripts as Data Web Scripts.
The Share Web Scripts, pages, and Dashlets are implemented with a user interface (UI) development framework called Surf. This framework was originally developed by Alfresco, then donated to the Spring Source foundation, and finally brought back into Alfresco. It provides a way of breaking a HTML page into re-usable component parts. Surf is built on top of the Spring Web MVC technology, which in turn uses the Spring Framework.
Developers can also add completely new pages and Dashlets to the Share UI when content should be viewed or handled in a specific way. Sometimes it is also required to modify existing pages. To customize the Share UI developers use so called Extension Points, which are supported ways of injecting new custom code that should alter the functionality of the Share web application.
The following picture gives an overview of the Alfresco Share application architecture, note that not all available extension points are illustrated in this picture:
You can focus solely on Aikau if the only thing you are going to do is add new stuff to the Share UI. However, if you need to alter behaviour of existing pages, then you might also need to get up to speed on the details of the Surf page model, as only the following stuff has been converted to Aikau:
- Share Header Menu and Title (4.2)
- Live Search (5.0)
- Filtered Search Page (5.0)
- Search Management Page (5.0)
- Site Management Page (5.0)
- Analytics and Reporting Widgets (5.0)
- Document List prototype (5.0)
The following sections get into a bit more details around Surf pages and Aikau pages.
Server Side Framework (Alfresco Surf)
Each page template defines one or more regions for things like header, footer, body, navigation etc, see the following picture:
To be able to reuse regions we can scope them to page, template, or global usage:
Each region is implemented as a reusable component. A component implementation is done with a Surf Web Script, which is the same thing as the REST-based request and response model, the predominant Web Service design model. The component Web Scripts will typically return HTML fragments that make up different parts of the page:
With all these different objects we might expect there to be some form of model that makes up the whole Surf UI development framework. It looks like this:
/WEB-INF/classes/alfresco /site-data /chrome /components ... global.header.xml /component-types /configurations /content-associations /extensions /page-associations /pages ... documentlibrary.xml ... search.xml ... task-details.xml ... /page-types /template-instances 1-column.xml 2-columns.xml 3-columns.xml ... content-viewer.xml ... search.xml ... /template-types /themesThe Site Data model defines the page in XML, like in the following example for Search (alfresco/tomcat/webapps/share/WEB-INF/classes/alfresco/site-data/pages/search.xml):
<?xml version='1.0' encoding='UTF-8'?> <page> <title>Search</title> <title-id>page.search.title</title-id> <description>Search view</description> <description-id>page.search.description</description-id> <template-instance>search</template-instance> <authentication>user</authentication> <components> <!-- Title --> <component> <region-id>title</region-id> <url>/components/title/search-title</url> </component> <!-- Search --> <component> <region-id>search</region-id> <url>/components/search/search</url> </component> </components> </page>Here we can see that some components have been defined inline in the search page definition, instead of in the /components directory as separate files. The name of the page definition file is implicitly setting the page id to search. A corresponding template instance file is expected to be present in the template-instances directory. In our case it will be a file called search.xml:
<?xml version='1.0' encoding='UTF-8'?> <template-instance> <template-type>org/alfresco/search</template-type> </template-instance>It will have a link to the physical template that contains the layout of the page. The template files are located under a different directory called /templates, which is on the same level as the site-data directory:
/WEB-INF/classes/alfresco /site-data /templates /org /alfresco 1-column.ftl 2-columns.ftl 3-columns.ftl ... content-viewer.ftl ... search.ftl ...The search.ftl template file looks like this with the regions etc:
<#include "include/alfresco-template.ftl" /> <@templateHeader /> <@templateBody> <@markup id="alf-hd"> <div id="alf-hd"> <@region scope="global" id="share-header" chromeless="true"/> </div> </@> <@markup id="bd"> <div id="bd"> <div class="yui-t1"> <div id="yui-main"> <@region id="search" scope="page" /> </div> </div> </div> </@> </@> <@templateFooter> <@markup id="alf-ft"> <div id="alf-ft"> <@region id="footer" scope="global" /> </div> </@> </@>The search page reuses the global header and footer components and then defines a page specific region called search. The Web Scrip to call for the search component is already defined in the page definition XML above (i.e. /components/search/search). The controller file for the search Web Script looks like this (alfresco/tomcat/webapps/share/WEB-INF/classes/alfresco/site-webscripts/components/search/search.get.js):
Client Side Frameworks (Surf Pages and Aikau Pages)
To get an idea of the differences between the old school Surf pages, and the new Surf pages called Aikau, we will implement a simple page in both client side frameworks. The thing that might be a bit confusing to start with is that Aikau pages are also old school Surf pages under the hood. An Aikau page actually uses a predefined Surf page as a starting point. Now let's start with an old school Hello World page and see how we can add it to the Share UI.
Hello World Old School Surf Page
The following steps are needed to add a Surf Page:
- Add a Surf Page definition file (XML)
- Add a Template Instance file (XML)
- Add a physical Template file (FTL)
- Add a properties file (.properties) - Optional but good practice
- Add Web Script(s) that fetches content to display (if you have page scoped regions and use an existing template)
Next we will have a look at how to implement the same Hello World page with Aikau.
Hello World Aikau Page
To implement the Hello World page in Aikau we have to go through the following steps:
- Add a Web Script descriptor (XML)
- Add a Web Script template (FTL)
- Add a Web Script controller (JS) with page layout/model
- Add Widget to display content
- Choose what Surf Page you want to use as a basis (dp, hdp, rdp etc)
Extension Points in Alfresco Share
As you can imagine, there are loads of extension points that you can use in the Alfresco Share UI to build a customized version of the user interface. In this article we have looked at the major ones, which are old school Surf Pages, Aikau Surf pages, Aikau widgets, Web Scripts, Surf Module extensions, and Dashlets. I know we did not explicitly look at how to implement Dashlets, but it is the same thing as implementing a Web Script.
There are many more extension points though, for example the Document Library page in a site can be extended via something called Document Library Actions. It is important to know about these supported extension points, and follow them, as otherwise your code might not work in a future release of Alfresco, and you might have trouble getting the support you need.
Here is a list of each supported extension point in Alfresco Share, for a comprehensive description of each one go to the Share Extension Points section (OOTB = Out-of-the-box functionality):