Latest Share Customization Techniques Dave Draper
Session Agenda (Very quick) overview of Share/Surf Review of customization enhancements What Share customization was like before version 4.0 What was added for Share version 4.0 An explanation of the Surf Extensibility Model What’s New in version 4.2 What’s next for Share
Key Things To Know Share is built on Surf Surf is an extension to Spring MVC “Is Surf moving backing Alfresco?”
History 2007 WebScripts 2008 Surf Share 3.0 and Share 3.2 Surf and WebScripts contributed to Spring 2010 Share 3.4 I joined Alfresco 2011 Surf converted to extensibility model (Share 4.0)
What Was Life Like Back in 2007 No iPhone (not until June anyway) No Android jQuery only just released (version 1.0, Aug 2006) Movies were still in 2D HD-DVD was still a viable option The global economy was still stable Spain were still rubbish at football
Region Chrome Anatomy of a Surf Page Page Template-Instance FreeMarker Template RegionsComponents Component Chrome WebScripts
Share Customization Prior to Version 4.0 Copy and paste to “web-extension” path Maintenance problems
Share Customization in version 4.0 Extensibility Model introduced into Surf Extension Module configuration Sub-Components Customizations SurfBug Document Library specific extension points
Document Library Extension Points Well defined, common, fine-grained use-cases No Surf changes Separate development effort
Extension Modules Three deployment modes: “auto” “enable-auto-deploy-modules” “manual” Evaluated once per request Default evaluation configuration can be overridden during manual deployment
Sub-Component extensions Addressed the problem of 1-1 mapping of Regions to Components Automatically generated from “legacy” Component configuration Allow default (Sub-)Components to be removed or replaced and for new Sub-Components to be added before or after Sub-Component evaluations allow for finer control of rendering
WebScript/Template Customizations Allows additions and overrides to i18n properties Allows model created by JavaScript controller to be manipulated Allows and directives in FreeMarker templates to be replaced or removed Allows new and directives to be added before or after existing directives
Please request for the directives that YOU need to be added to the Share WebScripts!!!
JavaScript Controller Customizations Run after default controller An opportunity to alter the model passed to template
Localization Customizations Update default WebScript properties for each request Most specific locale “wins”
Configuration Customization Configuration can be added to a module using element Generates a custom configuration model for each request Uses underlying ConfigService implementation Available in 4.0 service packs
Site_Conditional_Flash noflash.* false Example taken from:
The Surf Extensibility Model An in-memory buffer (a linked list of elements) FreeMarker directives manipulate elements A new model is opened for each FreeMarker template The following directives use the model: (can be nested)
Unbound Open Content Close Some text How Extensibility Model is Built Up
Adding Content Unbound Open Content Close id=“add” target=“MARKUP_1” action=“after”> Some MORE text Open Content Close “MARKUP_1”
Unbound Open Content Close Writer ExtensibilityModel flush() write() Unbound Open Content Close OutputStream flush()
The Problem: Only coarse grained customizations were possible The Solution: Make it easier to customize client-side JavaScript
How Client-Side Widgets Were Instantiated Region/Component WebScript Descriptor Controller “head” file FreeMarker template Localization Properties JavaScript resource CSS resource
Double Pass WebScript Processing head.get.head.ftl head.get.html.ftl WebScripts body1.get.head.ftl body1.get.html.ftl body2.get.head.ftl body2.get.html.ftl Styles1.css Functions1.js Styles2.css Functions2.js ${head}
Unbound Open Content Close ExtensibilityModel JavaScript / CSS import Deferred Open Close render()
Old Widget Instantiation
Share WebScript Refactor Conversion to a common “boiler-plate” template Client-side JavaScript widget definition moved into JavaScript controller All logic moved from FreeMarker template to JavaScript controller All JavaScript and CSS resource import statements moved into FreeMarker template Deprecation of *.head.ftl files
The “Boilerplate” …
Controller Model “widgets” Elements Object attributes: “id” “name” (required) “initArgs” (defaults to region id) “useOptions” (defaults to “true”) “options” “useMessages” (defaults to “true”) “assignTo”
New Widget Instantiation
Why Refactor? Consistency between WebScripts Easier to instantiate custom client-side JavaScript widgets A step towards performance improvements Moving towards disabling Surf Chrome and WebScript Head processing by default Moving towards JavaScript and CSS resource aggregation by default
Using JavaScript Extension Mechanism Create custom JavaScript widget that extends Alfresco version Use YAHOO.extend() function Override default functions Extend WebScript Customize FreeMarker template to add import for file containing custom widget Customize JavaScript controller to replace widget instantiation object Use widgetUtils.findObject(model.widgets, “id”, ) Change “name” attribute to reference new JavaScript widget
Module Custom DocumentList Widget org.alfresco.components.documentlibrary blog.demo.customization Example taken from:
Custom JavaScript // 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!" }); } }); })(); Example taken from:
Custom FreeMarker template src="${url.context}/res/doclib/extension/custom-documentlist.js" group="documentlibrary"/> Example taken from: Custom JavaScript controller // 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"; }
Surf Configuration Settings “use-checksum-dependencies” “aggregate-dependencies” “calculate-webscript-dependencies” “generate-css-data-images”
Checksum Dependencies Processed by the “dependency.handler” Spring bean org.springframework.extensions.surf.DependencyHandler Default Spring bean definition can be overridden to change debug and production suffices or the checksum digest (defaults to MD5) Production suffices: “-min” “-minified” “” Debug suffices “” “_src” “-debug”
Resource Aggregation Currently disabled by default (Share can be run with it enabled) Enabling may break 3 rd party extensions Improves performance by reducing the number of HTTP requests Includes inline JavaScript Removes all JavaScript from HTML source
Calculate WebScript Dependencies Still enabled by default Can be disabled if you don’t want to use Rich Media AMP Will be disabled by default in some future release Required for legacy extensions Empty *.head.ftl files are still processed so that extension versions are detected Please try to phase out the use of *.head.ftl files !
Generate CSS Data Images An alternative to CSS spriting Too consuming a task to convert Share to CSS sprites Use of CSS sprites would most likely break 3 rd party customizations Handles statements All must appear first in the file Relative paths are generated when image cannot be found Enabled by default
Dojo Support in Surf Surf now includes support for Dojo applications Programmatic implementations only Dojo version 1.7 applications or greater Uses existing resource aggregation capabilities to simulate Dojo build layers Dynamic dependency analysis Supports 3 rd party extensions
Why Have We Done This? Investigating future possibilities for developing Share YUI 2 is no longer being developed Simplify page development Move from coarse-grained, tightly-coupled “flat” widget structure to fine-grained, decoupled, nested widgets Improve customization/extensibility
Why Dojo? AMD (Asynchronous Module Definitions) Simple widget construction Excellent inheritance patterns Pub/Sub model Unit testing framework Comprehensive & consistent widget library Accessibility support Backed by big companies
2012 Summary Configuration customization support added Share WebScript refactoring Repository Extensibility Container Dynamic extension module support Surf Maven Archetype Dojo (1.7+) support in Surf
What Next For Share? It WON’T be replaced It WILL still be based on Surf It WILL feature new pages built on an improved client-side framework
Key Messages and Actions Performance and extensibility are key objectives for Share Share is going to continue to move forward Read the blogs Use the forums Ask questions Request extension points Raise bugs/feature requests on JIRA Come along to the Share Customization Live! session to see this in action
Questions?
FIN
FreeMarker Directive Factory Directive Factory defines the directives that are created (bean id: “directive.factory”) ProcessorModelHelper creates the directives (bean id: “processor.model.helper”) Custom directives can be written and provided to FreeMarker templates: Override default bean definitions to reference custom beans Override.populateTemplateModel() in ProcessorModelHelper to add additional FreeMarker directives Lots of interfaces and abstract classes that can be implemented/extended This approach is used for Alfresco Cloud service