Transcript Document

Latest Share Customization Techniques
Dave Draper (@_DaveDraper)
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 3.1
• 2009
• 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
Anatomy of a Surf Page
Page
FreeMarker Template
Template-Instance
Regions
Region
Chrome
Components
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 <@region> and <@markup> directives in
FreeMarker templates to be replaced or removed
• Allows new <@region> and <@markup> directives to be
added before or after existing directives
Please request for the
<@markup> 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
<configurations> element
• Generates a custom configuration model for each request
• Uses underlying ConfigService implementation
• Available in 4.0 service packs
<extension>
<modules>
<module>
<id>Site_Conditional_Flash</id>
<evaluator type="site.module.evaluator">
<params>
<sites>noflash</sites>
<sitePresets>.*</sitePresets>
</params>
</evaluator>
<configurations>
<config evaluator="string-compare"
condition="DocumentLibrary" replace="true">
<file-upload>
<adobe-flash-enabled>false</adobe-flash-enabled>
<in-memory-limit>262144000</in-memory-limit>
</file-upload>
</config>
</configurations>
</module>
</modules>
</extension>
Example taken from:
http://blogs.alfresco.com/wp/ddraper/2012/03/05/share-configuration-extensibility/
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:
•
•
•
•
•
•
•
•
<@region>
<@markup> (can be nested)
<@outputCSS>
<@outputJavaScript>
<@script>
<@link>
<@relocateJavaScript>
<@standalone>
How Extensibility Model is Built Up
<!– This is the start a template-->
<@markup id=“MARKUP_1”>
<span>Some text</span>
Unbound
Open
Content
</@>
<!– End of a template -->
Close
Unbound
Adding Content
Unbound
“MARKUP_1”
<@markup id=“add”
Open
Content
target=“MARKUP_1”
Close
action=“after”>
<span>Some MORE text</span>
</@>
Unbound
Open
Content
Close
ExtensibilityModel
Writer
Unbound
Open
flush()
Unbound
write()
Open
Content
Content
Close
Close
Unbound
Unbound
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
WebScripts
head.get.head.ftl
head.get.html.ftl
Styles1.css
body1.get.head.ftl
Functions1.js
body1.get.html.ftl
${head}
body2.get.head.ftl
Styles2.css
Functions2.js
body2.get.html.ftl
ExtensibilityModel
Unbound
Open
<@outputJavaScript/>
<@outputCSS/>
JavaScript / CSS import
Deferred
Close
Open
<@link/>
<@script/>
Content
Close
Unbound
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”
<@markup id=“css”>
<@link href=“…” group=“…”/>
</@>
<@markup id=“js”>
<@script src=“…” group=“…”/>
</@>
<@markup id=“widgets”>
<@inlineScript group=“…”/>
<@createWidgets group=“…”/>
<@inlineScript group=“…”/>
</@>
<@markup id=“html”>
<@uniqueIdDiv/>
…
</@>
</@>
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
•
<@markup id=“myWidgetSrc” target=“js” action=“after”>
• Customize JavaScript controller to replace widget instantiation
object
•
•
Use widgetUtils.findObject(model.widgets , “id”, <id>)
Change “name” attribute to reference new JavaScript widget
Module
<module>
<id>Custom DocumentList Widget</id>
<customizations>
<customization>
<targetPackageRoot>
org.alfresco.components.documentlibrary
</targetPackageRoot>
<sourcePackageRoot>
blog.demo.customization
</sourcePackageRoot>
</customization>
</customizations>
</module>
Example taken from:
http://blogs.alfresco.com/wp/ddraper/2012/05/22/customizing-share-javascript-widget-instantiation-part-1/
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:
http://blogs.alfresco.com/wp/ddraper/2012/05/22/customizing-share-javascript-widget-instantiation-part-1/
Custom FreeMarker template
<@markup id="custom-documentlist-dependencies" target="js" action="after" scope="global">
<@script src="${url.context}/res/doclib/extension/custom-documentlist.js"
group="documentlibrary"/>
</@markup>
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";
}
}
Example taken from:
http://blogs.alfresco.com/wp/ddraper/2012/05/22/customizing-share-javascript-widget-instantiation-part-1/
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 3rd 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 3rd party
customizations
• Handles CSS @import statements
• All CSS @imports 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 3rd 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