Customizing the Document Library

Post on 05-Dec-2014

9.906 views 4 download

description

The Share Document Library provides a number of out-of-the-box default actions and displays basic, essential metadata for documents and folders. This session will show you how to add custom metadata and status indicators, modify the available actions and wire-up new filters. We'll also look at how the Document Library was extended for the DoD 5015.2 Records Management Fileplan browser. You will need to be familiar with basic Surf concepts as well as JavaScript and Freemarker to follow the webscript customization. Familiarity with YUI 2.x and CSS will aid understanding during this session.

Transcript of Customizing the Document Library

1

Customizing the Document Library

Mike HatfieldSenior Software Engineer, Alfresco

twitter: @mikehatfield

2

Customizing the Document Library

What We’ll Cover

• Architecture• Challenges to customization and extension

• Plans for improvement

• Case Study: the DoD 5015.2 Extensions• Extension Example

• Status Indicators• Custom Actions• Custom Metadata• Filters

3

Architecture

4

Architecture

Heavy Use of YUI for “Web 2.0” Experience

• Many JavaScript frameworks evaluated• Only YUI had a full-time staff, full API documentation, supported

UI widgets

• Many YUI widgets and modules used• DataTable• Treeview• Buttons, Menus, Containers• History Manager for “AJAX back button” support• XHR wrappers, JSON parser

• Most HTML rendering performed client-side• yuilibrary.com is your friend!

5

Architecture

Initial Page Load

• Create all YUI controls• Register event handlers• Extract URL arguments• Bubbling Event “changeFilter”• onChangeFilter: updateDocList()• Webscript URL (via proxy) YUI DataSource• Repository webscripts execute for given filter & params• Bubbling Event “filterChanged”• Render JSON response using DataTable cell renderers

6

Architecture

Subsequent Navigations (e.g Folder)

• Bubbling Event “changeFilter” [new filter params]• onChangeFilter: Build data webscript URL• History Manager multiNavigate()• onHistoryManagerFilterChanged: updateDocList()• Webscript URL (via proxy) YUI DataSource• Repository webscripts execute for given filter & params• Bubbling Event “filterChanged”• Render JSON response using DataTable cell renderers

7

Architecture

YUI DataTable Renderers

• One renderer per data column• Selected file / folder• Status indicator• Thumbnail / icon• Metadata description• Actions

• Render XSS-safe HTML from parsed JSON• elCell.innerHTML = “<div>…</div>”

• YUI wraps output in <table><tr><td> tags

8

Architecture

Actions

• Currently defined in webscript config xml files• Separate configs for browse page, details pages

• Action Sets based on repository business logic• evaluator.lib.js• “document”, “folder”, “locked”, “workingCopyOwner”, etc.

• Two action types• “simple-link” URL via getActionUrls()

• {downloadUrl}, {viewUrl}, {folderDetailsUrl}• “action-link” JavaScript function “id” attribute

• ID attribute defines action icon and JavaScript function

9

Architecture

Actions

• Permissions• Comma-separated list• User AND asset must have ALL permissions for action to appear• “Virtual” permissions as well as role-based

• create, edit, delete, permissions, cancel-checkout• inline-edit, simple-approve, googledocs-edit

• Negative permission via tilde (~)• ~filter-path, ~portlet, ~googledocs-edit

• Label attribute for I18N message

10

Current Extension Points

New Actions

New Actions

New Actions

New Actions

Custom UI

Custom UI

Custom UI

New Filters

New Filters

New Filters

11

Plans for Improvements

• Consolidate scattered action configuration• share-config-custom.xml instead of webscript config• Still possible to restrict & specialise actions on details pages

• New actions via configuration where practicable• jar file for client-side UI assets, I18N• CSS and JS dependencies via config (see Forms & Header)

• Leverage Repository Actions & scripts• Custom Views

• Web-tier rendering• Open CMIS

12

Case Study: DoD 5015.2 Extensions

13

Case Study: DoD 5015.2 Extensions

Custom Actions

Numerous new and overridden actions to support the DoD requirements specification.

14

Case Study: DoD 5015.2 Extensions

Custom Toolbar

Sensitive to current folder type. New and overridden actions.

Custom Filters

Removed unsuitable filters (user filters, tags). One static, one dynamic (populated from list of saved searches on the Repository).

15

Case Study: DoD 5015.2 Extensions

“documentLibrary” container type determines components

16

Case Study: DoD 5015.2 Extensions

17

Template: documentlibrary

documentlibrary.js

connector.get("/slingshot/doclib/container/" + siteId + "/" + containerId);"dod:filePlan"

model.doclibType = fromRepoType("dod:filePlan");“dod5015”

documentlibrary.ftl

<@region id=doclibType + "documentlist" scope="template" protected=true />

Surf Component Binding

template.dod5015-documentlist.documentlibrary.xml

<url>/components/documentlibrary/dod5015/documentlist</url>

18

Creating the Container

DoD 5015.2 Method

documentlibrary.js

page = sitedata.getPage("site/" + siteId + "/dashboard");pageMeta = eval('(' + p.properties.pageMetadata + ')');contentType = doclibMeta.type;

connector.get("/slingshot/doclib/container/" + siteId + "/" + containerId + “?type=“ + toRepoType(contentType));

”dod:filePlan”

presets.xml

<preset id="rm-site-dashboard"> <page id="site/${siteid}/dashboard"> <properties> <pageMetadata>{"documentlibrary":{…, "type":"dod5015"}}</pageMetadata>

19

Creating the Container

Web QuickStart Method

LoadWebSiteDataGet.java

NodeRef docLib = siteService.getContainer(siteId, COMPONENT_DOCUMENT_LIBRARY);

siteService.createContainer(siteId, COMPONENT_DOCUMENT_LIBRARY, WebSiteModel.TYPE_WEBSITE_CONTAINER, null);

ornodeService.setType(docLib, WebSiteModel.TYPE_WEBSITE_CONTAINER);

dashlet

connector.get("/api/loadwebsitedata?site=" + siteId);

20

Case Study: DoD 5015.2 Extensions

YUI Helps

YUI developers added a number of helper functions to allow OO-style JavaScript modules.

• Notice:• constructor• superclass• extend• augment• etc…

21

Component Replacement Approach

• Full override / replacement control on all tiers.

• Your code can be almost completely independent of Alfresco’s.

Pros

• Mandatory component mapping , even for “native” components.

• Still have to copy/paste where <include> cannot be used, e.g. I18N.

• Repository folder type to component prefix issue.

• Not a 100% “clean” override mechanism.

Cons

22

Mandatory Component Mapping

Big Development Overhead

template.dod5015-actions-common.documentlibrary.xml

template.dod5015-documentlist.documentlibrary.xml

template.dod5015-file-upload.documentlibrary.xml

template.dod5015-fileplan.documentlibrary.xml

template.dod5015-flash-upload.documentlibrary.xml

template.dod5015-html-upload.documentlibrary.xml

template.dod5015-navigation.documentlibrary.xml

template.dod5015-savedsearch.documentlibrary.xml

template.dod5015-title.documentlibrary.xml

template.dod5015-toolbar.documentlibrary.xml

template.dod5015-tree.documentlibrary.xml

And that’s just the browse page!

23

Extension Example

• Overview • Customisations

• Status Indicators• Custom Metadata• New Filters• Custom Action

• Based on Alfresco Community 3.4.b• Need to use AMP on the Repository until refactoring work is complete• Share extensions via .jar and web-extension folder

24

Extension Example: Photography

Overview

25

Demo

Out-of-the-box Share

26

Extension: Status Indicators

Provide the user a quick indication of the current status of a folder or document, e.g. aspects applied.

Calculated in evaluator.lib.js

• Repository• evaluator.lib.js

• Share• I18N messages• Indicator images

27

Repository: Override evaluator.lib.js

/* Exif metadata */if (node.hasAspect("exif:exif")){ status["exif"] = true;}

/* Geographic */if (node.hasAspect("cm:geographic")){ status["geographic"] = true;}

28

Share: Indicator images

status[”exif"] = true;status["geographic"] = true;

share.jar!/META-INF/components/documentlibrary/images1. exif-indicator-16.png2. geographic-indicator-16.png

29

Share: Add I18N messages

1. share.jar!/org/springframework/extensions/surf/custom-slingshot-geographic-context.xml<bean id="geographic.custom.resources" class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent">

<property name="resourceBundles"> <list> <value>alfresco.messages.geographic</value> </list> </property></bean>

2. share.jar!/alfresco/messages/geographic.propertiestip.geographic=Geo Locationtip.exif=EXIF Metadata

30

Extension: Custom Metadata

Rendered entirely by the web browser from JSON data.

• Repository• item.lib.ftl• Maybe also JavaScript logic

• Share• I18N messages• Override cell renderer

31

Repository: Override item.lib.ftl

1. alfresco.amp!/WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/item.lib.ftl

<#if node.hasAspect("cm:geographic")>“geolocation”:{ "latitude": ${(node.properties["cm:latitude"]!0)?c}, "longitude": ${(node.properties["cm:longitude"]!0)?c}},</#if>

<#if node.hasAspect(”exif:exif")>“exif”:{ …},</#if>

32

Share: Reference extension JavaScript

1. shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/documentlibrary/actions-common.get.head.ftl

<@script type="text/javascript" src="${page.url.context}/res/components/geographic/geographic-extension.js"></@script>

33

Share: Override cell renderer

1. Override fnRenderCellDescription

share.jar!/META-INF/components/geographic/geographic-extension.js

YAHOO.util.Event.onContentReady("alf-hd", function(){ if (Alfresco.DocumentList) { Alfresco.DocumentList.prototype.fnRenderCellDescription = function

DL_fnRenderCellDescription() { … if (record.exif) { desc += scope.msg(“detail.exposure”) + record.exif.exposureTime;

} … } }}

34

Extension: New Filter

Allow easy filtering by any Repository logic, most commonly a Lucene or Alfresco FTS search query.

• Repository• filters.lib.js

• Share• I18N messages• Filter webscript config

35

Share: Filter webscript config

1. shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/documentlibrary/filter.get.config.xml

<filters> … <filter id="geo" label="link.geo-located" /> <filter id="exif" label="link.exif" /> …</filters>

36

Repository: Filter webscript override

1. alfresco.amp!/WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/filters.lib.js

case "geo": filterQuery = "+PATH:\"" + parsedArgs.rootNode.qnamePath + "//*\""; filterQuery += "+ASPECT:\"cm:geographic\""; filterParams.query = filterQuery break;

case "exif": filterQuery = "+PATH:\"" + parsedArgs.rootNode.qnamePath + "//*\""; filterQuery += "+ASPECT:\"exif:exif\""; filterParams.query = filterQuery break;

37

Extension: Custom Action

Can be configured to only appear if a folder or document is in a particular state and/or the user has the correct permission(s) and/or the page is within a Site context and/or the action is on the browse or details page.

• Repository• evaluator.lib.js• Action processing (optional)

• Share• I18N messages• Action configuration• Client-side logic & images

38

Repository: Override evaluator.lib.js

/* Geographic */if (node.hasAspect("cm:geographic")){ status["geographic"] = true; permissions["geographic"] = true;}

39

Share: Action configuration

1. shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/documentlibrary/documentlist.get.config.xml

2. shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/document-details/document-actions.get.config.xml

3. etc…

<actionSet id="document"> … <action type="simple-link"

id="onActionGeographic" permission="geographic" href="{geographicUrl}" label="actions.document.geographic" />

</actionSet>

40

Share: CSS and JS dependencies

1. shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/documentlibrary/actions-common.get.head.ftl

<@link rel="stylesheet" type="text/css" href="${page.url.context}/res/components/geographic/geographic-extension.css" />

2. share.jar!/META-INF/components/geographic/geographic-extension.css

.doclist .onActionGeographic a{ background-image: url(pin.png) !important;}

41

Share: Proxy JavaScript function

var override = Alfresco.DocumentList || Alfresco.DocumentActions;

// Store reference to getActionUrls() function to allow extension.var getActionUrls_geo = override.prototype.getActionUrls;

override.prototype.getActionUrls = function(recordData){ var actionUrls = getActionUrls_geo.apply(this, arguments);

actionUrls["geographicUrl"] = Alfresco.util.siteURL( "geographic-map?nodeRef=" + recordData.nodeRef);

return actionUrls;};

42

Demo

New Extensions

43

The End Result

44

Roadmap

• Consolidate scattered action configuration• New actions via configuration where practicable• Remove references to non-core Share code• Leverage Repository Actions & scripts• Custom Views

45

Q & A

• Feedback

46

Learn Morewiki.alfresco.com/wiki/Shareblogs.alfresco.com/wp/mikeh/