Obsolete Pages{{Obsolete}}
The official documentation is at: http://docs.alfresco.com
3.03.13.2ExamplesDeveloper GuideAlfresco Share
IMPORTANT |
The procedures outlined below are for Share v3.x only and should not be used for v4.0 and newer. |
The Document Library in Alfresco Share comes shipped with a number of default actions, automatically filtered by file type and user permissions.
DocLib_default_actions.png
The Document Library ('DocLib') formats the list of actions so that the overflow appears under the 'More' link.
There are various parts that make up a typical action:
Obviously, not all actions require all parts and some actions may need more (e.g. interaction with third party services). For the purposes of this article, we'll be concentrating on a simple, repository-based action that requires no further user input.
(see documentlist.get.html.ftl)
This is the mark-up for the 'Move to...' action.
...
<a rel='delete' href='#' class='action-link' title='${msg('actions.document.move-to')}'>
${msg('actions.document.move-to')}</a>
...
It's parent container DIV indicates that this action belongs to an action set for documents. The actual action set assigned to a particular asset is determined by the repository data webscript action-sets.lib.js and is beyond the scope of this article.
The action DIV's class attribute refers to the client-side JavaScript function which will be invoked when the user selects the action. This class also gives the link it's icon via a CSS rule.
Note the rel attribute on the A tag which indicates that the user must have delete permissions for this action.
The final point is the i18n message labels which are applied to the label and the link's title, used in 'Simple View' mode.
(see documentlist.get.config.xml)
In Alfresco V3.2 onwards, the available actions are now specified via configuration instead of HTML mark-up.
The equivalent XML for the 'Move to...' action is now:
<actionSet id='document'>
...
<action id='onActionMoveTo' type='action-link' permission='delete' label='actions.document.move-to' />
...
</actionSet>
The configuration entries are processed at run-time to render HTML mark-up as before, but are now much more intuitive.
(see documentlist.get.properties)
Convention is to label the action in an appropriate way depending on it's action set>
actions.document.move-to=Move to...
(see documentlist.css)
The only style required for the action's icon as a background image:
.doclist .onActionMoveTo a
{
background-image: url(images/move-to-16.png);
}
(see documentlist.js and doclib-actions.js)
The 'Move to' action uses a dialog to obtain the required destination where the user wants to move the document. The details of the function aren't important here, just the function signature and how the function obtains the actual file being actioned.
/**
* Move single document or folder.
*
* @method onActionMoveTo
* @param row {object} DataTable row representing file to be actioned
*/
onActionMoveTo: function DL_onActionMoveTo(row)
{
var file = this.widgets.dataTable.getRecord(row).getData();
...
},
The data webscript can be called by utilizing the genericAction() function provided by the Alfresco.module.DocLibActions module, via the DocumentList's modules.actions class variable. We'll be using this method in the example below...
(see move-to.post.json.js)
To ease development of data webscripts, the Share DocLib provides a small framework to help build actions. The data webscript should follow this basic pattern:
<import resource='classpath:/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/action/action.lib.js'>
/**
* Move multiple files action
* @method POST
*/
/**
* Entrypoint required by action.lib.js
*
* @method runAction
* @param p_params {object} Object literal containing files array
* @return {object|null} object representation of action results
*/
function runAction(p_params)
{
var results = [];
var files = p_params.files;
...
return results;
}
/* Bootstrap action script */
main();
The output template is trivial:
(see move-to.post.json.ftl)
In this example, we'll create a new action taken from the JavaScript API Cookbook, which will copy a document to a backup folder.
For the source (svn) case, the root folder for these web-tier webscripts is root/projects/slingshot/config/alfresco/site-webscripts/org/alfresco/components/documentlibrary and for the deployed option is webapps/share/WEB-INF/classes/alfresco/site-webscripts/org/alfresco/components/documentlibrary. Client-side assets can be found at root/projects/slingshot/source/web/components/documentlibrary and webapps/share/components/documentlibrary respectively.
First of all, we'll create the mark-up for the action by editing the documentlist.get.html.ftl presentation template. Our new action will apply to documents only, so add the following DIV tag to the 'document' action set:
As before, create this action with no linebreaks in the HTML.
<a rel='' href='#' class='action-link' title='${msg('actions.document.backup')}'>
${msg('actions.document.backup')}</a>
We'll configure the new action by editing the documentlist.get.config.xml file. Our new action will apply to documents only, so add the following XML element to the 'document' action set:
<action id='onActionBackup' type='action-link' permission='' label='actions.document.backup' />
Add the following i18n labels to documentlist.get.properties
actions.document.backup=Backup
message.backup.success='{0}' successfully backed up.
message.backup.failure=Couldn't backup '{0}
Add a suitable image to the images subfolder (call it 'backup-16.png'):
backup-16.png
(Icon credit famfamfam.com Silk Icons)
Add a new CSS file called backup-action.css in the client-side folder, next to documentlist.css to add a new CSS rule for the new action:
.doclist .onActionBackup a
{
background-image: url(images/backup-16.png);
}
Add a blank JavaScript file called backup-action.js, also in the client-side folder where you just created the new CSS file. We'll be populating this file a bit later.
To ensure both these files are served to the web browser, you need to add two lines (and a suitable comment is recommended) to the documentlist.get.head.ftl presentation template.
<link rel='stylesheet' type='text/css' href='${page.url.context}/components/documentlibrary/backup-action.css' />
<script type='text/javascript' src='${page.url.context}/components/documentlibrary/backup-action.js'></script>
If you are deploying to version 3.3 or greater and are compressing your client-side JavaScript assets (as you should be), then the @link
and @script
macros are provided in Freemarker to automatically include compressed versions of your files where necessary. In this case the following lines should be used instead.
At this point, you can deploy your changes and load up the Document Library to check that your new action appears correctly.
Clicking the action won't do anything yet, as the action handler code is smart enough not to try and call the onActionBackup function that we haven't defined yet.
At this point, it makes sense to create the repository webscript which will actually be making the backup copy. This is so we can determine exactly what parameters the webscript might need, so we can call it correctly from the client.
We'll add our repository actions to the Web Scripts Extensions area of the Data Dictionary in the Repository (not the file system). In order to provide the correct relative path for the include files, create the following space hierarchy under Web Scripts Extensions:
/org
/alfresco
/slingshot
/documentlibrary
/action
Create the following three files, which will form our backup repository action:
<webscript>
<shortname>backup</shortname>
<description>Document List Action - Backup document(s)</description>
<url>/slingshot/doclib/action/backup/site/{site}/{container}</url>
<format default='json'>argument</format>
<authentication>user</authentication>
<transaction>required</transaction>
</webscript>
<import resource='classpath:/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary/action/action.lib.js'>
/**
* Backup multiple files action
* @method POST
*/
/**
* Entrypoint required by action.lib.js
*
* @method runAction
* @param p_params {object} Object literal containing files array
* @return {object|null} object representation of action results
*/
function runAction(p_params)
{
var results = [];
var files = p_params.files;
var file, fileNode, result, nodeRef;
// Find destination node
var destNode = p_params.rootNode.childByNamePath('/Backup');
if (destNode == null)
{
destNode = p_params.rootNode.createFolder('Backup');
}
// Must have destNode by this point
if (destNode == null)
{
status.setCode(status.STATUS_NOT_FOUND, 'Could not find or create /Backup folder.');
return;
}
// Must have array of files
if (!files || files.length == 0)
{
status.setCode(status.STATUS_BAD_REQUEST, 'No files.');
return;
}
for (file in files)
{
nodeRef = files[file];
result =
{
nodeRef: nodeRef,
action: 'backupFile',
success: false
}
try
{
fileNode = search.findNode(nodeRef);
if (fileNode === null)
{
result.id = file;
result.nodeRef = nodeRef;
result.success = false;
}
else
{
result.id = fileNode.name;
result.type = fileNode.isContainer ? 'folder' : 'document';
// copy the node to the backup folder
result.nodeRef = fileNode.copy(destNode);
result.success = (result.nodeRef !== null);
}
}
catch (e)
{
result.id = file;
result.nodeRef = nodeRef;
result.success = false;
}
results.push(result);
}
return results;
}
/* Bootstrap action script */
main();
Copy the three files to the space you created in the Data Dictionary. Then browse to the Web Scripts Home, (http://<server>/alfresco/service/index) and click Refresh Web Scripts.
The final piece is to wire-up the action link to some client-side JavaScript which will call our new webscript, passing in the file we want to create a backup of.
Open-up the backup-action.js client-side JavaScript file we created earlier and copy the following code into it:
/**
* DocumentList 'Backup' action
*
* @namespace Alfresco
* @class Alfresco.DocumentList
*/
(function()
{
/**
* Backup single document.
*
* @method onActionBackup
* @param row {object} DataTable row representing file to be actioned
*/
Alfresco.doclib.Actions.prototype.onActionBackup = function DL_onActionBackup(row)
{
var file = this.widgets.dataTable.getRecord(row).getData();
this.modules.actions.genericAction(
{
success:
{
message: this._msg('message.backup.success', file.displayName)
},
failure:
{
message: this._msg('message.backup.failure', file.displayName)
},
webscript:
{
name: 'backup/site/{site}/{container}',
method: Alfresco.util.Ajax.POST
},
params:
{
site: this.options.siteId,
container: this.options.containerId
},
config:
{
requestContentType: Alfresco.util.Ajax.JSON,
dataObj:
{
nodeRefs: [file.nodeRef]
}
}
});
};
})();
Note for v3.2 onwards: The actions implementation has moved to a different namespace and it's no longer necessary to call getRecord(). Rather use 'file' attribute directly in the argument, not 'row'.
Alfresco.doclib.Actions.prototype.onActionBackup = function DL_onActionBackup(file)
{
this.modules.actions.genericAction(
...
Note if the above is not being called when the action is clicked on (seen with v3.3 onwards for instance) then it may need changing to:
Alfresco.DocumentList.prototype.onActionBackup = function DL_onActionBackup(file)
The _msg function has also been renamed to simply 'msg', i.e.
success:
{
message: this.msg('message.backup.success', file.displayName)
},
failure:
{
message: this.msg('message.backup.failure', file.displayName)
},
Note how we're sending the file to be backed up to the data webscript: we pass it as an array of nodeRefs. This allows the data webscript to support backing up multiple files, which we could add by customizing the DocLib's toolbar to provide the 'Backup' action for multi-file selections.
From version 3.3 onwards it is recommended that compressed variants of all client-side JavaScript files are included with the original files. Compression substantially reduces the file sizes of these assets, with a resultant increase in the performance of the application.
The compressed .js files should be placed in the same directory structure as the regular files, but with a -min.js
suffix. YUI Compressor is recommended to perform the compression - it provides an executable JAR file which can be used to generate compressed variants as follows (for this example)
java -jar yuicompressor-2.4.2.jar backup-action.js > backup-action-min.js
If you have used the @script
macro in your modifications to documentlist.get.head.ftl above then you must include a compressed version in this way, otherwise your action will not work.