Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > 2011 > August
2011

SurfBug

Posted by ddraper Aug 31, 2011

Introduction

In my previous blogs I've been introducing some of the new extensibility features that are currently available in the current Alfresco Community source and that will be available in Alfresco Enterprise 4.0. In many of these blogs I've demonstrated the use of a new Spring Surf debug tool called 'Surf Bug' without providing much additional information about it. In this blog I'm going to describe Surf Bug in greater detail.

 

Background

When I first started working on the Alfresco Share user interface the most immediate challenge was identifying the various components that comprise each page. It's was something of an art to find the source file in which the actual HTML on any given page is defined - and that was after you understood how a Spring Surf page is built!

 

This posed a major challenge for anyone extending a page in Alfresco Share as the first task was always identifying the  files that actually needed extending. In order to assist with this problem we have introduced 'SurfBug' which (as its name suggests) took its inspiration from the FireFox add-on 'FireBug' and when enabled is designed to highlight Components or Sub-Components that comprise the current page and provide information on the files and properties that define them.

 

SurfBug is a part of Spring Surf rather than Alfresco Share and as such is actually available to any Spring Surf application. It is enabled by the 'surfBugStatus' WebScript (i.e. accessed through '<application context>/service/surfBugStatus').

 

Toggle Surf Bug

 

Enabling SurfBug and refreshing a page will overlay red boxes on the screen indicating the location of the Components or Sub-Components on the page (the information shown is based upon the Surf application configuration - if the Component interfaces is being fulfilled by the 'org.springframework.extension.surf.type.AdvancedComponentImpl' class (which is the default) then Sub-Component information will be shown. When you mouse click on a box, a pop-up will be displayed that hopefully provides all the information about the Sub-Component that you could possibly need.

 

Surf Bug Data

 

Things To Note

SurfBug is not guaranteed to show every Sub-Component on the page if the DOM elements for that page have been manipulated in certain ways (e.g. you won't see highlights for the Sub-Components that make the pop-up panels for site creation, file upload, etc) and since the highlights are absolutely positioned on the page (to avoid affecting the DOM structure) they are not guaranteed to be in pixel perfect position - the rough position of a highlight and the information contained in its pop-up should hopefully be sufficient though!

 

You should also not attempt to drive an applications user interface with SurfBug enabled. The most effective way we've found of using it is to navigate to the page you're interested in, toggle SurfBug on from another tab in your browser and then refresh the application page. If you need to move onto another page - simply toggle SurfBug back off, reload the page, navigate and switch back on.

 

One other important point is that Surf Bug gets enabled for the entire application - NOT just for the user that enables it. It's intended to be used in development, not production. It's 'admin' protected so regular users won't be able to switch it on, but if it gets enabled then every user will see the highlights until it's switched off again.

 

Information Provided

The following table provides a breakdown of the information that SurfBug provides:

 

Page ID:The ID of the Page being displayed
Template ID:The ID of the Template being displayed
Template Type:Typically this is the path of the FreeMarker template used to render the Spring Surf Template referenced by the Page.
Component Details
ID:The ID of the Component that the Sub-Component belongs to.
Definition Location:The runtime path of the file containing the configuration for the Component
GUID:Generated unique id of the component
Region-id:The id of the region the template into which the component has been bound
Source-id:The id of the object at which the component is defined (this will typically be a Page id, a Template id or will be 'global')
Scope:The scope at which the Component has been defined (this will typically be 'global', 'page' or 'template').
Custom Properties:Any custom properties that have been configured for the component. These are not used by Spring Surf to perform any rendered but may be used by the Component itself if it is parameterized in any way (this may be the case for Components backed by JSPs, WebScripts or FreeMarker).
Sub-Component Details
ID:The id of the Sub-Component - this is always prefixed by the parent Component id and a '#' indicates the start of Sub-Components identification
Contributing Paths:The runtime paths of all the files that have provided input into this Sub-Component (a Sub-Components property, index and evaluation configuration can all be updated by zero or more extension modules). If no extensions have been applied then this will only contain a single path.
Index:The specifically set index of the Sub-Component within the Component. This is the final index after all extensions have been applied. If nothing is shown it means that the default is being used.
Processor:The processor that has been used to render the Sub-Component. If this Sub-Component has been generated from legacy configuration then this could be either WebScript, WebTemplate or JSP (or some custom processor) - but AdvancedComponents only currently support WebScript processors and if the Sub-Component is not legacy generated then this will be blank.
Evaluated URI:The URI used to render the Sub-Component. This is the URI that is generated as a result of processing all Evaluations across all extensions - so is not necessarily the value configured in the source configuration file.
Evaluated By:This is the id of the first successful Evaluation and therefore the one that returned the 'Evaluated URI' field. If this is blank it means that no Evaluations were performed on the Sub-Component.
WebScript Location:If the Sub-Component was rendered by a WebScript then this will show the runtime path of the WebScript descriptor file. The other WebScript files (template, controller, etc) will be co-located.
WebScript Details:This provides a link to the WebScript information which will be opened in a new tab/window.
Evaluated Properties:The properties for the Sub-Component as returned by a successful Evaluation. Properties can be overridden by Evaluations to change how a Sub-Component is rendered.
Extensibility Directives:A list of the extensibility directives that have been applied to the Sub-Component.

Introduction

Having covered the basics of the new extensibility features that are currently available in the latest Alfresco Community source and will be available in Alfresco Enterprise 4.0 this module will focus in greater detail on module structure and their deployment.

 

Background

If you've been working through the previous tutorials you might have noticed that when deploying your modules (via http://localhost:8080/share/page/modules/deploy - if you're using the defaults) some additional options are displayed to the right of the screen when clicking on a module. This is the module deployment configuration and it provides the opportunity to override the default configuration of an extension.

 

Screenshot of module deployment highlighting the evaluator options

 

Even if a Module is deployed the function it provides may not be applicable to every request. Therefore a Module can be configured to use an 'evaluator' that determines whether or not it should be used which is invoked on each request.

 

A deployed module will always be evaluated on every request.  A developer can optionally provide default Evaluator configuration but if it is omitted then Spring Surf will automatically apply the default application Evaluator (as defined in the Spring application context). By default Spring Surf defines a default application Evaluator that always results in the module being applied to each request. When you deploy any module you have the option of keeping the default Evaluator (which will either be the application default or will be have been explicitly defined in the configuration) or selecting your own.

 

Module Evaluators are just Spring beans like Sub-Component Evaluators and technically a single bean can be both a Module and Sub-Component Evaluator providing it implements both the 'org.springframework.extensions.surf.extensibility.ExtensionModuleEvaluator' and 'org.springframework.extensions.surf.extensibility.SubComponentEvaluator' interfaces.  However, a Module Evaluator takes precedence over a Sub-Component Evaluator in the sense that it will be evaluated first, and if the evaluation fails then the Sub-Components in the module will not even get the opportunity to be evaluated. Essentially though they are intended to perform the same function, i.e. compare data in the current request with against a set of configured parameters to see if the request meets the evaluation criteria.

 

The default Module Evaluator is configured in the Spring application context with the id 'default.extensibility.evaluator' that maps to the Class 'org.springframework.extensions.surf.extensibility.impl.ApproveAllModulesEvaluator' which (as its name suggests) will always evaluate to true. Another Evaluator available 'out of the box' has the bean id 'config.approval.evaluator'.  If you select this as the Evaluator when deploying a Module you will see that it asks for a single property with the key 'apply' which determines whether or not the Module gets applied (e.g. if you set the value as 'true' then the Module will always be applied, if you set it to anything else then the Module will never be applied).

 

Tutorial

Try this out with one of the previously created modules. It is not necessary to restart the server - simply browse to the module deployment WebScript UI, select the 'config.approval.evaluator' and set the 'apply' property to 'false' and when you refresh the previously affected Alfresco Share page you will see that the module is no longer be applied (NOTE: You must click the 'update' button to apply the change to the  module and then click the 'Apply Changes' button to persist your  changes).

 

Screen shot showing alternative evaluator selected

 

To achieve the same objective through configuration update the module configuration to contain the following (NOTE: only a fragment of the module config is shown - see the earlier blogs for the complete configuration):

 

<module>
    <id>Blog Module (New Content)</id>
    <evaluator type='config.approval.evaluator'>
        <params>
            <apply>false</apply>
        </params>
    </evaluator>

 

There are only a limited number of 'out-of-the-box' Evaluators available so it is likely that you may want to create your own. This process is very similar to creating a Sub-Component evaluator. First create the following Java class:

 

package blog.demo;

import java.util.Map;
import org.springframework.extensions.surf.RequestContext;
import org.springframework.extensions.surf.extensibility.ExtensionModuleEvaluator;

public class BlogModuleEvaluator implements ExtensionModuleEvaluator
{
    public static final String USER_PROP = 'user';

    public boolean applyModule(RequestContext context, Map<String, String> evaluationProperties)
    {
        String currUser = context.getUser().getId();
        String targetUser = evaluationProperties.get(USER_PROP);
        return (targetUser != null && targetUser.equals(currUser));
    }

    public String[] getRequiredProperties()
    {
        return new String[] { USER_PROP};
    }
}

 

Add the following line to your 'spring-surf-extensibility-context.xml' file:

 

<bean id='blog.module.evaluator' class='blog.demo.BlogModuleEvaluator'/>

 

Re-build and deploy your extension JAR and when you refresh the module deployment page after re-starting the web server you should be able to select your new module. Notice that the String array returned from the 'getRequiredProperties' method is used by the UI to provide a default set of properties to supply. These properties are currently not automatically validated in anyway so it's up to the Evaluator developer to check that all the data they require has been provided.

 

Screen shot showing deployment using custom evaluator

 

The custom Module Evaluator we've created will only apply the module for the user specified in the deployment configuration, so if you set the 'user' property to be 'admin' and then log onto Alfresco Share as 'admin' you will not see the title bar on the User Dashboard page (see example screenshots).

 

Screen shot showing the title bar hidden for user admin

 

Screen shot showing title bar shown for user "Dave"

Having released v0.2 of the Node Browser Component for Share this week and having put a bit of work into refactoring the underlying code, it seemed like a good time to write a quick guide to creating Administration Console Components for Share.



Like dashlets, Admin Console components are easily defined using a single web script, along with some supporting resources, and are therefore are automatically picked up by the framework once added to Share, with no additional configuration needed.



Alfresco's Engineering team have added a number of new console components to the upcoming Swift release, and in addition to the Node Browser Share Extras provides two other additional components that you can add to your existing 3.3 or 3.4 installations.



  • Complenting the Node Browser, Florian Maul's JavaScript Console allows custom JavaScript code to be executed against the repository to display information or make changes. Loading and saving of scripts to and from the Data Dictionary is supported, as well as syntax highlighting and custom space contexts.


  • Secondly the Create Bulk Users component allows administrators to create multiple users in the repository, based on CSV/TSV or JSON data, and is capable of auto-generating usernames and passwords, sending email notifications and logging of all user created.







Each of the three add-on pages has information on checking out a copy of the source code, which you can use as a basis for creating your own components. You should also grab a copy of the Sample Project bundle, which can be used as a template for your projects.



But before you dive into the code, it's useful to have an understanding of the different parts that make up a component. So let's step through each of them in turn, using the Create Bulk Users component as an example.



1. Web-tier web script



Technically, this is the only required part of the component. The component is bound into the application via this web script, which must be declared as a member of the admin-console family within its .desc.xml file. It should also define a single, unique URL, have a unique path and provide a HTML template to render the component's UI.



The following XML is from the descriptor file (create-users.get.desc.xml) for the Create Bulk Users component, which should illustrate this.

<webscript>

   <shortname>Admin Console Create Users</shortname>

   <description>Administration Console - Create Users Console</description>

   <url>/extras/components/console/create-users</url>

   <family>admin-console</family>

</webscript>


Although it's obviously possible to provide a JavaScript controller for the web script, it's normally not necessary if you're using a client-side module to encapsulate your business logic, as we'll explore in the next section.



A HTML template (create-users.get.html.ftl in this example) is responsible for laying out out the basic skeleton mark-up of the component, including instantiation of any client-side modules being used.



Although technically optional you will normally also need a corresponding .head.ftl template (create-users.get.head.ftl in this example) to include your own basic, custom CSS file as well as any client-side JavaScript files the component requires.



You can see these templates and all other files that make up this web script in the Create Bulk Users source code under config/alfresco/site-webscripts.



2. Client-side component



It's recommended that you use a client-side component for all but the most basic console components, since it will allow you to handle interactions with the user using standard script-based controls and widgets, and in a manner consistent with other admin console components.



Like dashlets that utilise client-side code, your client-side component will normally be defined in a dedicated .js file, which should be part of the static files (in addition to your CSS) supplied with your component.



The component should be defined using the standard Share pattern



  1. Components are JavaScript classes, defined within a specific namespace, which can be instantiated in page components when needed


  2. Components declare a constructor, then extend a base class using YAHOO.extend() and add their own class methods


  3. Component definitions are contained within a function closure



But whereas dashlet classes would typically extend Alfresco.component.Base, admin console components extend Alfresco.ConsoleTool, which adds some additional fields and methods to support multiple panels and the YUI History Manager.



The component constructor is also slightly more complex than for a dashlet component, since to support the panel approach it is necessary to define within the constructor at least one inner panel class, plus an instantiation of each class.



Panels provide different views of a console component, and whereas simple components such as the Create Bulk Users Console have only one panel, it allows more complex components such as the Node Browser to define more than one (in this case one for the search panel and another for the node view panel).



Like the main component, the pattern used to define the panel class is the constuctor + YUI.extend() method, with panels extending the base class Alfresco.ConsolePanelHandler.



Although this might seem complex, once understood, it provides a consistent pattern which can be applied again and again to define as many admin console components as you need.



So wrapping all of this up, the general pattern for admin console client-side components is something like the following, as illustrated for the Create Bulk Users component.

// Ensure Extras namespace exists

if (typeof Extras == 'undefined' || !Extras)

{

   var Extras = {};

}

(function() // Function closure

{

   ...

   Extras.ConsoleCreateUsers = function(htmlId) // Component constructor

   {

      ...

      FormPanelHandler = function FormPanelHandler_constructor() // Form panel constructor

      {

         FormPanelHandler.superclass.constructor.call(this, 'form');

      };

      YAHOO.extend(FormPanelHandler, Alfresco.ConsolePanelHandler, // Extend Alfresco.ConsolePanelHandler

      {

         onLoad: function onLoad() // Fired on initial panel load

         {

            ...

         }

         ...

      });

      new FormPanelHandler(); // Instantiate panel instance

      return this;

   };

   ...

   YAHOO.extend(Extras.ConsoleCreateUsers, Alfresco.ConsoleTool,

   {

      options: // Console component configurable options

      {

         ...

      },

      onReady: function ConsoleCreateUsers_onReady() // Fired when component ready

      {

         ...

      },

      ...

   });



})(); // End function closure


Much of the code is stripped out here to convey the overall structure. In reality you would have other statements mixed in with the functions above, and all public classes, constructors and methods should be documented with appropriate JSDoc.



To explorer this some more, it's recommended that you take a look at the client-side JavaScript files inside the JavaScript Console and Create Bulk User Console add-ons. You will find these files in the checked-out source code under the directory source/web.



3. Web-tier Spring configuration and message bundle



Most of the strings that appear in the admin console component UI should be externalised in your web script .properties file, and will be accessible from the Freemarker template of the web script via the root-scoped msg() function.



However, the name of your component also appears in the component list on the left hand side of the Admin Console, and since the page component responsible for rendering this does not have access the messages defined in your web script, it is necessary to provide a globally-scoped message bundle to provide some text for a label and a description of our component.



You can define your message bundle in any valid .properties file, but for the sake of convention I normally give mine a unique name and place them in the package alfresco/messages in my configuration. This is the file used for the Create Bulk Users component, which you can find in the source code under config/alfresco/messages/create-bulk-users.properties.

tool.create-users.label=Create Bulk Users

tool.create-users.description=Create repository users from CSV or JSON data


The message names should comply with this standard structure, with the part between the periods (.) being the same as the name of the console component's web script, minus the method part. Since the name of the web script was create-users.get, the message names required are tool.create-users.label are and tool.create-users.description.



Lastly, a small piece of Spring configuration is needed to bind the message bundle into the application. This file must have a unique name with the suffix -context.xml, and be placed within the package org/springframework/extensions/surf. See the file config/org/springframework/extensions/create-bulk-users-context.xml in the Create Bulk Users source code for an example.



4. Repository components



Lastly, it's likely that your admin console component will require some custom repository logic to perform your administration tasks. Normally this would take the form of one or more repository-tier web scripts, but other components such as a custom data model could also be required.



Fortunately the source directory structure used by the Sample Project in Share Extras (and by the three admin console add-ons) allows these to be placed in the same project, and you will find the repository web script create-users.post used by the Create Bulk Users component in the source code under config/alfresco/templates/webscripts.



Summary



You should now have an idea of the basic parts involved in an admin console components such as the three examples provided by Share Extras, and how they interact with each other.



You can study these examples to help you gain further understanding of how each of the four parts are implemented in practice, by checking out the source code for them. The JavaScript Console and Create Bulk Users examples are the simplest, so start there and look at the Node Browser if you need a multi-panel example.



The Sample Project provides a good skeleton project for you to define your own add-ons. Although the example code provided in it implements a web script, you can easily delete these and add your own files to define an admin console component, based on one of the three examples.



As well as giving you a basic directory structure, the project also gives you an Ant build script that you can use to build, test and distribute your add-on.



If you have any feedback, please leave a comment below.

Introduction

In the previous two blog posts I've introduced extension module customizations for i18n properties files and JavaScript controllers. In this post I'm going to describe how Spring Surf has been updated to allow FreeMarker templates to be customized through the use of new extensibility directives. These features are currently available in the latest Alfresco Community source and will be available in Alfresco Enterprise 4.0.

 

Background

Customizing the i18n properties file was relatively trivial to implement because ultimately it becomes a map and is easy to update. Giving additional JavaScript controllers the opportunity to update the template model was also reasonably straightforward. However.... providing the opportunity for extension files to update a FreeMarker template was a much more significant challenge. Essentially the objective was to provide a way of dynamically editing HTML through configuration.

 

The approach we have taken to solve this problem may not solve all your customization problems immediately, but what we have implemented should pave the way for future extensibility enhancements in later releases. We've also provided an extensibility platform to provide your own solutions to the problem.

 

Essentially we have changed Spring Surf so that instead of writing templates directly to the output stream we write to an in-memory model and then allow extensions to manipulate that model before it gets flushed to the output stream. The mechanism for updating the model is through the use of new and updated FreeMarker template directives.

 

Wherever an extensibility directive is used in a bass template it can be manipulated by a corresponding extension file. There are a initial set of actions:

 

  • remove (completely remove the directive contents from the model)
  • replace (replace the directive contents in the model with something new)
  • before (place a new directive immediately before the target directive contents)
  • after (place new directive contents immediate after the target directive contents)
  • In the current code we provide 2 directives that support extensibility: <@region> and <@markup>.

 

The <@region> directive was used extensively in previous versions of Alfresco Share to define the Regions into which Component are bound - we have simply updated its implementation to work with the extensibility model. The <@markup> directive model is entirely new and is simply used to demarcate sections of HTML in a template.

 

In the first 2 blog posts I described how you can add and remove content from Alfresco Share by modifying the Components (and their Sub-Components). This approach relies on their being a Component available that will be bound to a Region in the template.

 

Using this alternative mechanism makes it possible to add new regions and also completely remove regions to prevent Components from being bound. This is significantly different because it is a much more volatile approach but could be useful in certain circumstances. If you want to remove some content and prevent another module from either restoring or adding to it, you can remove it entirely from the model so that it cannot be changed.

 

Tutorial

In an earlier blog I demonstrated how to add a new content to an Alfresco Share page by providing an additional Sub-Component as an extension. This could have also been done using a <@region> directive extension.

 

Enable Surf Bug and click on the Title bar.  Note the 'Template Type' property which in this case is 'org/alfresco/dashboard'. This means that the file we need to extend is 'dashboard.ftl' in the 'org.alfresco' package.

 

Screen shot showing Surf Bug data for Title on User Dashboard

 

Update the 'blog-demo.xml' file to add the following module definition:

 

<module>
    <id>Blog Module (Add Region)</id>
    <customizations>
        <customization>
            <targetPackageRoot>org.alfresco</targetPackageRoot>
            <sourcePackageRoot>blog.demo.customization</sourcePackageRoot>
        </customization>
    </customizations>
</module>

 

Create a file called 'dashboard.ftl' and place it in the package 'alfresco.templates.blog.demo.customization'. The file should contain the following:

 

<@region id='additional-content' target='title' action='before' scope='global' />

 

Note that the package we've added the file to is prefixed by 'alfresco.templates'. This is the source package at which Spring Surf Class Loader starts looking for template files. It is vitally important to include this prefix to your package or your extension won't be found.

 

We need to create a new Component to bind to our new Region. We're going to be lazy and use the legacy configuration style (although we could use the new style, this way is shorter and suitable for our purposes).

 

Create a file called 'global.additional-content.xml' and place it in the 'alfresco.site-data.components' package. The file should contain the following:

 

<component>
    <region-id>additional-content</region-id>
    <source-id>global</source-id>
    <scope>global</scope>
    <uri>/blog/demo/new-content</uri>
</component>

 

Note that we're re-using the same Web Script created in the first extensibility blog. If you haven't completed the tutorial in that blog then the Component won't find the Web Script specified by the <uri> element.

 

Re-build and re-deploy the JAR and restart the Alfresco Share web server and you should see the additional content.

 

Screen shot showing customized user dashboard

 

If you want to test out the other customization operations then you can update the 'dashboard.ftl' as follows:

 

To place the new content AFTER the title bar:

 

<@region id='additional-content' target='title' action='after' scope='global' />

 

To REPLACE the content of the title bar with the new content:

 

<@region id='additional-content' target='title' action='replace' scope='global' />

 

To REMOVE the title bar region completely:

 

<@region id='additional-content' target='title' action='remove' />

 

<@markup> Directives

At the time of writing there are currently no uses of the <@markup> directive anywhere in Alfresco Share. It's hoped that the Alfresco Community will make suggestions/contributions as to where they would best be added. They can wrap any section of FreeMarker source in either a WebScript or TemplateInstance to identify sections of the template that can be customized. If you have any suggestions then please post to the Community forums.

Introduction

In the last blog I introduced extension module 'customizations' and demonstrated how they could be used to override an i18n properties file to change the label on the User Dashboard. In this post I'm going to be demonstrating how to change the behaviour of a Web Script by augmenting its JavaScript controller. The extensibility features used are currently available in the latest Alfresco Community source and will be in Alfresco Enterprise 4.0.

 

Tutorial

In this tutorial I'm going to demonstrate how to provide an extension to the JavaScript controller file for the Web Script behind the 'Web View' dashlet so that the Alfresco.com web site will be displayed if the user hasn't specified another.

 

Making this kind of change does require some insider knowledge of how Alfresco Share is coded. Fortunately we can use a combination of SurfBug and the Web Scripts service UI to find out everything you need to know. There's no guarantee that you will be able to do everything you want using this method - but it would definitely be worth exploring as a first port of call.

 

First of all we need to add the 'Web View' dashlet to the User Dashboard:

  1. Log on to Alfresco Share
  2. Click the 'Customize Dashboard' button
  3. Click on 'Add Dashlets'
  4. Drag the 'Web View' dashlet from the available list and drop it into one of the dashboard columns
  5. Click 'OK'


Initially the dashlet will display the message 'No web page to display' as it has not been configured.

Screen shot showing the default Web View dashlet

 

Working in the Alfresco Engineering team meant that I already knew that I'd be able to make the customization I wanted - but by enabling SurfBug (http://localhost:8080/share/page/surfBugStatus - if you're using the default port) and clicking on the Web View dashlet you can find the Web Script URI ('/components/dashlets/webview') that renders it and by browsing for Web Scripts by URI (http://localhost:8080/share/page/index/uri/) you can access all the information (including the source of the JavaScript controller). This was explored in greater detail in the last blog if you need a refresher on how to find this information.

 

By inspecting the source of both the controller and the template you can work out what model properties the template is using and whether or not you can provide an extension to update the model after the base controller but before the template in order to create the desired result.

 

Screen shot showing the Web Script info for the Web View dashlet

 

Having identified that the dashlet is rendered by a Web Script using the controller ' webview.get.js' in the 'org.alfresco.components.dashlets' package we can define a new module with a customization to apply to it.

 

Edit the 'blog-demo.xml' file and add the following module configuration:

 

<module>
    <id>Blog Module (Web View JavaScript controller change)</id>
    <customizations>
        <customization>
            <targetPackageRoot>org.alfresco.components.dashlets</targetPackageRoot>
            <sourcePackageRoot>blog.demo.customization</sourcePackageRoot>
        </customization>
    </customizations>
</module>

 

Although we're targeting a different package, we're going to map it to the same package as we used for the properties customization in the last blog post.

 

Create a file called 'webview.get.js' containing the following:

 

if (model.isDefault == true)
{
    model.webviewTitle = 'Alfresco!';
    model.uri = 'http://www.alfresco.com';
    model.isDefault = false;
}

 

Place the new file in the 'webscripts.blog.demo.customization' package, rebuild and deploy your JAR, restart the web server and deploy your new module. When you login to Alfresco Share you should see that the Web View dashlet now displays the Alfreco.com website.

 

Screenshot showing the customized Web View dashlet

 

Your ability to customize Alfresco Share pages in this way will be somewhat limited to how they have been coded - but it's worth exploring as an option. In the future we will endeavor to create Web Script controllers with respect to potential extensions, but as the existing controllers weren't created with this in mind it's really pot luck as to whether you can achieve what you want.

 

However, there's another customization file type that you can also use... in the next blog post I'll be demonstrating how to customize Web Script FreeMarker templates.

 

 

Place the new file in the 'blog.demo.customization' package, rebuild and deploy your JAR, restart the web server and deploy your new module. When you login to Alfresco Share you should see that the Web View dashlet now displays the Alfreco.com website.
Alguns entusiastas do Alfresco iniciamos um projeto em que estamos trabalhando em uma tradução Alfresco para a versão 3.4.x. para Português (Brasil).

Se você quiser saber mais sobre este projeto, se você quer comentar, colaborar, ajudar ou simplesmente

baixar o mais recente pacote de tradução, visite-nos em:


Introduction

In previous blog posts I have described how to customize Alfresco Share through the use of Component extensions. This is only one of the new extensibility features that are currently available in the Alfresco Community source (and will be included in Alfresco Enterprise 4.0). In this post I'll start describing the changes we've made to Spring Surf in order to further simplify customization use cases starting with demonstrating how to customize Web Script i18n properties.

 

Tutorial

This tutorial describes how to override the default i18n properties for the User Dashboard title bar. It will show how to use the SurfBug and the Web Scripts UI to find the Web Scripts that need to be targeted and then demonstrate how to create the necessary extension module configuration and files to achieve the customization.

 

1. Logon to Alfresco Share and navigate to the user dashboard.

2. Open a new browser window or tab and enable SurfBug (http://localhost:8080/share/page/surfBugStatus - if you're using default port settings on your local machine)

3. Refresh the dashboard page and click on the title to see the information about the Component/Sub-Component that is rendering it

4. Make a note of the 'url' value in the Component details (which should be '/components/title/user-dashboard-title')

 

Screen shot showing Alfresco Share user dashboard with Surf Bug pop up

 

5. Open a new browser window or tab at the Web Scripts Home page (http://localhost:8080/share/service/index) and click on 'Browse by Web Script URI'

6. Find and click on '/components/title/user-dashboard-title' to see the information about the Web Script that is rendering the title bar.

 

Screen shot showing how to search for a Web Script by URI

 

7. Click on the link next to 'Id' to see all the information about the Web Script.

Screen shot showing Title Web Script basic information

 

8. The key piece of information that we're looking for here is the package that the Web Script belongs in which is 'org.alfresco.components.title' because we're aiming to customize the code defined in that package.

Screen shot showing detailed information on the Title Web Script

 

9. Edit your 'blog-demo.xml' (created in the previous blog post tutorials) and add the following module definition:

 

<module>
    <id>Blog Module (i18n property change)</id>
    <customizations>
        <customization>
            <targetPackageRoot>org.alfresco.components.title</targetPackageRoot>
            <sourcePackageRoot>blog.demo.customization</sourcePackageRoot>
        </customization>
   </customizations>
</module>

 

10. On the page showing the information about the Web Script scroll down to find the section on the i18n properties file which will show both the fully qualified name of the file along with its contents.

Screen shot showing detailed information about the Title Web Script

 

Create a new file called 'user-dashboard-title.get_en.properties' and place it in package 'webscripts.blog.demo.customization' package that we defined as the 'sourcePackageRoot' element in the module configuration. The file should contain the following:

 

header.dashboard=Customized Title Bar!

 

There's a couple of important things to note here!

1. The file name is NOT exactly the same... although a Web Script  will broaden the locale of it's search (i.e. from 'en_GB' to 'en' to  the default properties file - extensions will NOT)

2. The source package has been prefixed with 'webscripts.' - this is a requirement of the class loader used to find Web Script files.

 

11. Re-build the JAR, copy it to 'webapps/share/WEB-INF/lib' (or the equivalent directory for your web server), restart the web server and deploy the new module (hopefully you should be used to this process by now - if not, see the earlier blog posts for more details).

 

Logon to Alfresco Share you should now see that the title bar now says 'Customized Title Bar!'https://community.alfresco.com/api/core/v3/attachments/12032/data

Screen shot showing the customized title bar

 

Background Information

When you create a 'customization' you are creating a mapping from a package to you want to update to a package that you are providing. When any file is processed in that package all mapped extension module packages are searched for a matching file name. Typically a Web Script might be represented by a JavaScript controller, an i18n properties file and a FreeMarker template. They must all be defined in the same package with a similar file name prefix as the Web Script descriptor file to which they are related. This package mapping allows us to target multiple files in a single customization rather than specifying every file individually. It also allows us to broaden our target. For example we could have targeted 'org.alfresco' - but it is important to note that the remainder of the package will be applied to the source (so the extensibility framework would be looking for a matching file in the 'blog.demo.customization.components.title' package).

 

When you provide an i18n properties file extension the properties in the extension file are merged into the 'base' file (any duplicates are replaced with those from the extension file). If multiple modules extend the same properties file then the last module in the deployment list will 'win'.

 

It is not necessary to provide an extension file for every base in the Web Script - only those that you wish to extend. For example - if a Web Script has controller, properties and template files you don't need to provide extensions to all 3 if you just wish to override some i18n properties.

 

It's also possible to provide an extension file to a Web Script that does not have that base file. For example, it is entirely possible to extend a Web Script with a JavaScript controller or i18n properties file even if those files are not in the base.

 

In the next post I'll demonstrate how to extend a Web Script JavaScript controller.

Filter Blog

By date: By tag: