Customizing Share JavaScript Widget Instantiation (Part 1)

cancel
Showing results for 
Search instead for 
Did you mean: 

Customizing Share JavaScript Widget Instantiation (Part 1)

ddraper
Intermediate II
0 17 9,145

Introduction

The engineering team at Alfresco has been working hard over the past year or so to make it easier to customize the Share user-interface.  We've now started work on what I’d consider to be the last major piece of the extensibility puzzle – customizing the instantiation of client-side JavaScript widgets for each WebScript rendered Component.

The only way it was previously possible to change the widget(s) instantiated for a WebScript rendered Component was to copy and paste the supporting code to the “web-extension” path and then make the necessary changes to that copy. The major downside of this approach was that it generated an additional maintenance task to keep the copied code up-to-date with any changes that resulted from upgrades, service packs and hot-fixes.

The approach that we’re taking is to move all the logic and metadata about widget instantiation out of the FreeMarker template and to move it into the JavaScript controller as it is inherently easier to customize.  The metadata will be stored as a standardized object structure in the model which will then be processed by a new custom directive in the FreeMarker template to output the JavaScript code necessary to instantiate the specified widgets.

This allows us to utilize the existing JavaScript controller extension capabilities so that extension modules can modify the default metadata object(s) to change the following:

    • The name of the JavaScript widget to be instantiated
    • The arguments passed when instantiating the widget
    • The variable that the instantiated widget is assigned to
    • Whether or not i18n messages are set for the widget
    • Whether or not additional options are applied to the widget
    • The additional options that should be applied to the widget


As part of these changes we will also be updating the FreeMarker template to use a common “boiler-plate” structure to ensure consistency across WebScript rendered Components. We will utilize updated resource handling features in Surf to move all the CSS and JavaScript dependency requests into the template and remove the associated *.head.ftl file.  A consistent pattern of <@markup> directives will be used throughout the template to further enhance customization options.


The first WebScripts converted are those on the Document Library page as these as this is the area most frequently customized – these changes have already been committed to the latest Community source code in SVN.

Example

Let’s consider a simple example of what can be done….

Say we want to pop-up a message every time that a Document Library filter is changed.  The obvious place to handle this would be at the end of the “onFilterChanged” function in the “documentlist.js” file. Up until now we had the following options:

    1. Edit the local copy of “documentlist.js” (and then have to maintain any changes to it that result from fixes and upgrades)
    2. Create a custom DocumentList JavaScript subclass and then copy and paste the “documentlist.get” WebScript to instantiate it instead of the default Alfresco implementation (and then have to maintain any changes to the WebScript that result from fixes and upgrades).


Now though we have a slightly better option – we can create our subclass as with option 1, but we can create an Extension Module to the WebScript to both import our new library file and to instantiate our custom widget.

Our module configuration looks like this:

<module>
  <id>Custom DocumentList Widget</id>
  <description>Instantiate a custom DocumentList widget</description>
  <customizations>
    <customization>
      <targetPackageRoot>org.alfresco.components.documentlibrary</targetPackageRoot>
      <sourcePackageRoot>blog.demo.customization</sourcePackageRoot>
    </customization>
  </customizations>
</module>‍‍‍‍‍‍‍‍‍‍

This identifies the WebScript package that we want to target – in this case it’s the Document Library related WebScripts. We then create our custom Document List widget in our Extension JAR (“META-INF/doclib/extension/custom-documentlist.js”):

// Declare namespace...
if (typeof Blog == undefined || !Blog) { var Blog = {}; }
if (!Blog.custom) { Blog.custom = {}; }
(function()
{
  // Define constructor...
  Blog.custom.DocumentList = function CustomDocumentList_constructor(htmlId)
  {
    Blog.custom.DocumentList.superclass.constructor.call(this, htmlId);
    return this;
  };

  // Extend default DocumentList...
  YAHOO.extend(Blog.custom.DocumentList, Alfresco.DocumentList,
  {
    onFilterChanged: function CustomDL_onFilterChanged(layer, args)
    {
      // Call super class method...
      Blog.custom.DocumentList.superclass.onFilterChanged.call(this, layer,args);

      // Pop-up a message...
      Alfresco.util.PopupManager.displayMessage({
        text: 'Filter Changed!'
      });
    }
  });
})();


‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

Then we create an extension to the “documentlist.get.html.ftl” template to create a dependency to the file containing our custom widget (“webscripts/blog/demo/customization/documentlist.get.html.ftl” in our extension JAR):

 

<@markup id='custom-documentlist-dependencies' target='js' action='after' scope='global'>
  <@script src='${url.context}/res/doclib/extension/custom-documentlist.js' group='documentlibrary'/>
</@markup>‍‍‍


Finally we create an extension to the “documentlist.get.js” controller to change the widget that is instantiated ('webscripts/blog/demo/customization/documentlist.get.js'):

 

// Find the default DocumentList widget and replace it with the custom widget
for (var i=0; i<model.widgets.length; i++)
{
  if (model.widgets[i].id == 'DocumentList')
  {
    model.widgets[i].name = 'Blog.custom.DocumentList';
  }
}‍‍‍‍‍‍‍‍


Finally, deploy the module, restart Alfresco and each time you change a filter in the Document Library you should see the popup.

Extended Document List

17 Comments
blog_commenter
Active Member
Hi,

Do you know in which enterprise version those mechanisms will be available ? In a 'major' version (4.1.0 for example) or in a minor version (4.0.3) ?

Regards.
ddraper
Intermediate II
Hi Bertrand,

Because we need to make changes to almost every WebScript in Share then I'm fairly confident that these will not be available until the next 'major' release - although I don't actually make these decisions so I can't be 100% sure. I do know that although the Surf changes are complete, we have only just started updating the Share WebScripts so it will be a long time before they're all finished.

Regards,
Dave
blog_commenter
Active Member
Hi,

This is very interesting to us when we are soon to customise Share with JavaScript. But I have a doubt this is not better than the 'dependencies' configuration we use in the share-config-custom.xml....? Could not you have used such thing for the extended filter in this blog post?

Thanks
ddraper
Intermediate II
Hi Faizaan,

Striking the right balance between a sensible example and something concise and easily understandable is quite tricky... the objective of this first post in the series is to show how to instantiate a different JavaScript class than the default. I could have done anything else in my custom JavaScript class and it didn't necessarily even have to extend the Alfresco.DocumentList widget - the main obstacle we're trying to overcome is the ability to change the JavaScript object instantiated, what you do in your own JavaScript code is entirely up to you.

It is entirely possible to write and include a separate JavaScript file that augments the existing definition - but this approach would almost certainly require some in-depth JavaScript knowledge and wouldn't lend itself to extension on extension.

There's lots more to come in this series of blogs - hopefully the next post will be published in the next few days.

Regards,
Dave
blog_commenter
Active Member
[...] the first post of this series I showed how to extend the “documentlist.get.html.ftl” and [...]
blog_commenter
Active Member
[...] refactoring and extensibility hooks (see blogs by David Draper and Erik [...]
blog_commenter
Active Member
Hello,

Can you please show the file structure of the JAR?
Also, the  part - in what file does it go and where?
And do you deploy the JAR in $TOMCAT/shared(ib or in share/WEB-INF/lib?

Thanks
ddraper
Intermediate II
Hi Zlatko, I've responded to you question on the Alfresco forums here: https://forums.alfresco.com/en/viewtopic.php?f=48&t=46438
blog_commenter
Active Member
Hi Dave,



we often only need to override a CSS or JS include defined in *.get.head.ftl.



I tried to solve this using approach you've described in this topic, but it didn't work.



Here what I did:

1. Added a customization for comment-list component:

                                 

          org.alfresco.components.comments               

                               my.comments

              

      

2. Added a file: webscripts.my.comments.comments-list.get.head.ftl which includes my additional CSS: include:





But my customization has been never called by Surf.



Or should I add  in the  core file: org.alfresco.components.comments.comments-list.get.head.ftl



and override it in my

webscripts.my.comments.comments-list.get.head.ftl

?



Ideally would be to have an easy-to-use extension point for every 'head.ftl' of Alfresco Share presentation widgets (webscripts).



Best regards

Vitali
ddraper
Intermediate II
Hi Vitali,



Apologies, but I have to ask the obvious questions first...

1) Are you running on 4.2 Community or from a nightly or personal build of the latest code?

2) Are you creating and deploying an extension module? (and are you sure it's deployed successfully?)

3) Are you targeting the correct <@markup> elements and are you using the right actions?



It is possible to effectively have an extension applied to *every* WebScript if you just make the target package 'org.alfresco' since all Alfresco WebScripts are defined beneath that package.

Also (it's not recommended as they're now deprecated) but you can still create extensions to the .head.ftl files (but this will just save you the effort of having <@markup> directives)



If you could maybe post some code to the forums and reply with a link then I might be able to see what's going wrong for you?



Regards,

Dave
blog_commenter
Active Member
Additionally to my previous post, following appears in the Alfresco log:

2013-02-03 06:47:01,002  WARN  [extensibility.impl.ExtensibilityModelImpl] [http-8080-exec-23] The 'replace' action was attempted to used when defining the base model by directive:ID: commnts-list-custom-includes-impl, ACTION:replace
blog_commenter
Active Member
Hi Dave,



as suggested, this forum post with all details to this problem has been created:

https://forums.alfresco.com/forum/end-user-discussions/alfresco-share/markup-directive-headftl-haven...



Best regards

Vitali
blog_commenter
Active Member
[...] the first post of this series I showed how to extend the “documentlist.get.html.ftl” and [...]
blog_commenter
Active Member
I had some problems getting this demo to work, partly to do with Alfresco 4.2 using documentlist-v2.get... instead of documentlist.get... I have posted a working example on the Alfresco forums here: https://forums.alfresco.com/comment/142142#comment-142142
blog_commenter
Active Member
Hi,



I have tried to do the custom-documentlist.js. Module is created successfully but 'Filter changed' message is not coming. Could you please post the structure of the files.



My Requirement is , if i apply aspect the top menu's and document url should disable. If you have any idea.Please share.



Thanks in advance.
blog_commenter
Active Member
hi,



I have tried to do the custom-documentlist.js. Module is created successfully but 'Filter changed' message is not coming. Could you please post the structure of the files.



My Requirement is , if i apply aspect the top menu's and document url should disable using custom-documentlist.js. If you have any idea.Please share.



Thanks in advance
ddraper
Intermediate II
@arunakumar - apologies, but I don't have the time at the moment to reproduce this and update the blog post. Perhaps you can try raising the issue on the Alfresco forums or IRC channel and see if someone can help you there.