How does it work?

We've now looked at the functionality of the details page for records and the Series, Category, and Folder containers. In this "How does it work?" section, we'll investigate in greater detail how some of the internals for the record Details page work.

The Details page

To investigate the Details page, let's first start with the URL for the page. The format for the URL is something like this:

http://localhost:8080/share/page/site/rm/document-details?nodeRef=workspace://SpacesStore/3d3a5066-59bf-45cd-b025-4e5484c9b9af

We can see that the pageid used within this URL is document-details. We can then look up the page description file and find that it is the file tomcatwebappsshareWEB-INFclassesalfrescosite-datapagesdocument-details.xml.

The page descriptor file references the<template-instance> as document-details. If we look that up, we find the file tomcatwebappsshareWEB-INFclassesalfrescosite-data emplate-instancesdocument-details.xml.

From the template instance descriptor file, we find that the template path is org/alfresco/document-details. From that, we locate the FreeMarker and JavaScript template files for the page. The files are document-details.ftl and document-details.js in the directory tomcatwebappsshareWEB-INFclassesalfresco emplatesorgalfresco.

The JavaScript controller for the Details page

The JavaScript controller file document-details.js for the Details page is quite short. It relies heavily on the code from the file documentlibrary.js that it imports. Recall that we have already reviewed the file documentlibrary.js when we discussed the Document Library.

The file documentlibrary.js has code that recognizes that we are running in the Records Management site. That code sets the variable doclibType to the string "dod5015" and adds it to the model. The file document-details.js also stores the variable jsType in the model with the value of "Alfresco.RecordsDocumentDetails":

<import resource="classpath:/alfresco/templates/org/alfresco/ documentlibrary.js">
function toJSType(doclibType)
{
var type = "Alfresco.DocumentDetails";
switch (String(doclibType))
{
case "dod5015":
type = "Alfresco.RecordsDocumentDetails";
break;
}
return type;
}
model.jsType = toJSType(doclibType);

The FreeMarker template for the Details page

Now let's look at the FreeMarker template file. The layout for the Details page is somewhat similar to the Document Library and Category Details pages that we've looked at previously. The document-details.ftl page is also used by the standard document Details page by sites other than the Records Management site. When we examine the document-details.ftl, we can see at the beginning of the file that there are client-side JavaScript files imported.

Included files for the Details page

The files imported include:

  • components/blog/postview.css
  • templates/document-details/document-details.css
  • components/blog/blogdiscussions-common.js
  • components/blog/blog-common.js
  • modules/documentlibrary/doclib-actions.js
  • templates/document-details/document-details.js
  • templates/document-details/${doclibType}document-details.js

There are a number of files related to blog entries referenced, but these files are outside the context of the record Details page. The four main include files of interest are:

  • templatesdocument-detailsdocument-details.js
  • templatesdocument-detailsdod5015-document-details.js
  • templatesdocument-detailsdocument-details.css
  • modulesdocumentlibrarydoclib-actions.js

Initialize the RecordsDocumentDetails object

Skipping to the bottom of the file document-details.ftl, we see the following code that will be executed when the page is loaded on the client:

<script type="text/javascript">//<![CDATA[
new ${jsType}().setOptions(
{
nodeRef: new Alfresco.util.NodeRef("${url.args.nodeRef}"),
siteId: "${page.url.templateArgs.site!""}",
rootNode: new Alfresco.util.NodeRef("${rootNode}")
});
//]]></script>

We have just seen when we discussed the JavaScript controller that the variable jsType evaluates to Alfresco.RecordsDocumentDetails. An object of this type is instantiated on page load. The Alfresco.RecordsDocumentDetails object is defined in the file dod5015-document-details.js, which we just saw included on this page.

This new object is created with elements initialized for nodeRef, siteId, and rootNode members. The nodeRef is passed in from the URL.

FreeMarker components on the Details page

In the main body of the web page, as defined by FreeMarker, we can see a number of components defined by the use of the<@region> tags:

<@templateBody>
<div id="alf-hd">
<@region id="header" scope="global" protected=true />
<@region id=doclibType + "title" scope="template" protected=true />
<@region id=doclibType + "navigation" scope="template" protected=true />
</div>
<div id="bd">
<@region id=doclibType + "actions-common" scope="template" protected=true />
<@region id=doclibType + "actions" scope="template" protected=true />
<@region id=doclibType + "path" scope="template" protected=true />
<div class="yui-g">
<div class="yui-g first">
<#if (config.scoped['DocumentDetails']['document- details'].getChildValue('display-web-preview') == "true")>
<@region id=doclibType + "web-preview" scope="template" protected=true />
</#if>
<#if doclibType?starts_with("dod5015")>
<@region id=doclibType + "events" scope="template" protected=true />
<#else>
<div class="document-details-comments">
<@region id=doclibType + "comments" scope="template" protected=true />
<@region id=doclibType + "createcomment" scope="template" protected=true />
</div>
</#if>
</div>
<div class="yui-g">
<div class="yui-u first">
<@region id=doclibType + "document-metadata-header" scope="template" protected=true />
<@region id=doclibType + "document-metadata" scope="template" protected=true />
<@region id=doclibType + "document-info" scope="template" protected=true />
<@region id=doclibType + "document-versions" scope="template" protected=true />
</div>
<div class="yui-u">
<@region id=doclibType + "document-actions" scope="template" protected=true />
<@region id=doclibType + "document-links" scope="template" protected=true />
<#if doclibType?starts_with("dod5015")>
<@region id=doclibType + "document-references" scope="template" protected=true />
</#if>
</div>
</div>
</div>
<@region id="html-upload" scope="template" protected=true />
<@region id="flash-upload" scope="template" protected=true />
<@region id="file-upload" scope="template" protected=true />
</div>
…
</@>

Based on the Region ID and Scope, we can trace through descriptor files to find the following summary of region tags, excluding the regions for the upload dialogs that are not available from the context of the records Details page. Note that the regions corresponding to document comments are not available on the records Details page:

Region

Scope

URL

Header

global

/components/header

dod5015-title

template

/components/title/collaboration-title

dod5015-navigation

template

/components/navigation/collaboration-navigation

dod5015-actions-common

template

/components/documentlibrary/dod5015/actions-common

dod5015-actions

template

N/A

dod5015-path

template

/components/document-details/dod5015/path

dod5015-web-preview

template

/components/preview/web-preview

dod5015-events

template

/components/fileplan/events

dod5015-document-metadata-header

template

/components/document-details/document-metadata-header

dod5015-document-metadata

template

/components/form

dod5015-document-info

template

/components/document-details/document-info

dod5015-document-actions

template

/components/document-details/dod5015/document-actions

dod5015-document-links

template

/components/document-details/document-links

dod5015-document-references

template

/components/document-details/dod5015/document-references

Footer

global

/components/footer

The region dod5015-actions-common is used to pull in some additional include files for use on the page. The file tomcatwebappsshareWEB-INFclassesalfrescosite-webscriptsorgalfrescocomponentsdocumentlibrarydod5015-actions-common.get.header.xml has the following contents:

<#include "../component.head.inc">
<!-- DoD 5015.2 Actions -->
<@script type="text/javascript" src="${page.url.context}/components/documentlibrary/actions.js"> </@script>
<@script type="text/javascript" src="${page.url.context}/components/documentlibrary/dod5015- actions.js"></@script>
<!-- Simple Dialog -->
<@script type="text/javascript" src="${page.url.context}/modules/simple-dialog.js"></@script>
<!-- DoD 5015.2 Copy-To, Move-To, File-To -->
<@link rel="stylesheet" type="text/css" href="${page.url.context}/modules/documentlibrary/site-folder.css" />
<@script type="text/javascript" src="${page.url.context}/modules/documentlibrary/site- folder.js"></@script>
<@script type="text/javascript" src="${page.url.context}/modules/documentlibrary/dod5015-copy-move- file-to.js"></@script>
<!-- DoD 5015.2 File Transfer Report -->
<@script type="text/javascript" src="${page.url.context}/modules/documentlibrary/dod5015-file- transfer-report.js"></@script>

We can then see where on the final rendered page the component for each region will be placed, as shown in the following screenshot:

FreeMarker components on the Details page

Let's now look in more detail at some of the page components. We don't have space to go through all of them, but let's pick a few that have some interesting characteristics.

The web preview component

The files that define the web preview component can be found in the directory tomcatwebappsshareWEB-INFclassesalfrescositer-webscritpsorgalfrescocomponentspreview.

Web preview include files

The file web-preview.get.head.ftl defines the additional files to be included to support the display of the page on the client:

<#include "../component.head.inc">
<@link rel="stylesheet" type="text/css" href="${page.url.context}/components/preview/web-preview.css" />
<@script type="text/javascript" src="${page.url.context}/components/preview/web- preview.js"></@script>
<@script type="text/javascript" src="${page.url.context}/js/flash/extMouseWheel.js"></@script>
The web preview controller JavaScript

The file web-preview.js is run when both the page and the web preview component are initialized. The code in this file checks to make sure that a valid node reference was passed in:

// Check mandatory parameters
var nodeRef = args.nodeRef;
if (nodeRef == null || nodeRef.length == 0)
{
status.code = 400;
status.message = "Parameter 'nodeRef' is missing.";
status.redirect = true;
}

Next, it attempts to find the metadata associated with this record from the node reference:

var json = remote.call("/api/metadata?nodeRef=" + nodeRef);
if (json != null && json.toString().trim().length() != 0)
{
var node = {},
n = eval('(' + json + ')'),

This will make a remote call into the Alfresco repository to retrieve metadata for the current node. The URL for the service request will be of the form:

http://localhost:8080/alfresco/service/api/metadata?nodeRef=workspace://SpacesStore/3d3a5066-59bf-45cd-b025-4e5484c9b9af.

http://localhost:8080/alfresco/service/api/metadata?nodeRef=workspace://SpacesStore/3d3a5066-59bf-45cd-b025-4e5484c9b9af.

Next, the code tries to extract the cm:content property from all object metadata for the record:

mcns = "{http://www.alfresco.org/model/content/1.0}",
content = n.properties[mcns + "content"];

The value for the content variable contains a string of concatenated properties for the stored file. For example, the information will look as follows:

contentUrl=store://2010/9/1/12/3/08ac3a0d-0ccf-44f8-a65d- 1ef4666076d5.bin| mimetype=application/pdf| size=108932| encoding=utf-8| locale=en_US_

Embedded in this string, the contentUrl refers to the directory where the Alfresco content store is located. Also encoded in the string are values for the mimetype, size, encoding, and locale.

The JavaScript code then continues to check to see if an image or Flash preview of the document is available for viewing:

// Call repo for available previews
json = remote.call("/api/node/" + nodeRef.replace(":/", "") + "/content/thumbnaildefinitions");
var previews = eval('(' + json + ')'),

A call to the Alfresco repository is made here to see what types of renditions are available for this record. It does this by using the following web service URL:

http://localhost:8080/alfresco/service/api/node/workspace/SpacesStore/3d3a5066-59bf-45cd-b025-4e5484c9b9af/content/thumbnaildefinitions

In this example, the response to the web service JSON looks like the following:

[ "doclib",
"webpreview",
"avatar",
"medium",
"imgpreview"
]

We see that a web preview rendition for this document is already available. This isn't the first time that this document has been viewed on the Details page. The first time that someone accesses the Details page for the record, the Flash web preview file is created.

The rest of the web-preview.js controller file constructs a node object to be returned as part of the model.

The web preview FreeMarker template

The file web-preview.get.html.ftl contains the markup that describes the display of the web preview component. The top of this file contains JavaScript run on the client when the web preview component is loaded that creates an Alfresco.WebPreview object:

<#if (node?exists)>
<script type="text/javascript">//<![CDATA[
new Alfresco.WebPreview("${args.htmlid}").setOptions(
{
nodeRef: "${node.nodeRef}",
name: "${node.name?js_string}",
icon: "${node.icon}",
mimeType: "${node.mimeType}",
previews: [<#list node.previews as p>"${p}"<#if (p_has_next)>, </#if></#list>],
size: "${node.size}"
}).setMessages(
${messages}
);
//]]></script>
</#if>

The remainder of the file is the FreeMarker markup for the layout of the component:

<div class="web-preview shadow">
<div class="hd">
<div class="title">
<h4>
<img id="${args.htmlid}-title-img" src="${url.context}/components/images/generic-file-32.png" alt="File" />
<span id="${args.htmlid}-title-span"></span>
</h4>
</div>
</div>
<div class="bd">
<div id="${args.htmlid}-shadow-swf-div" class="preview-swf">
<div id="${args.htmlid}-swfPlayerMessage- div">${msg("label.preparingPreviewer")}</div>
</div>
</div>
</div>
Client-side JavaScript

On the client, the JavaScript file that provides the dynamics for the web preview component is the file componentspreviewweb-preview.js. This JavaScript file contains the definition of the object Alfresco.WebPreview.

The JavaScript will check to see if the content is already an image or Flash SWF format that can be viewed as-is or whether a Flash rendition is needed to be viewed. The previewer is capable of viewing both images, Flash or FLEX, so documents with content of this file format type need not have their content converted to Flash in order to preview them.

Alfresco converts office documents, in either Microsoft Office or OpenOffice formats, to PDF using the OpenOffice SDK. Those intermediate PDF files are then converted to Flash SWF objects using the PDF2SWF utility that is part of SWFTools. In the same way, if there is a file format that needs to be previewable, it can be added if there is a tool that exists to convert the file into either PDF or SWF formats.

A service call is then made back to the Alfresco repository to retrieve the Flash preview content. If the preview doesn't already exist, it will be generated. An example of what that service call looks like is the following:

http://localhost:8080/share/proxy/alfresco/api/node/workspace/SpacesStore/3d3a5066-59bf-45cd-b025-4e5484c9b9af/content/thumbnails/webpreview?c=force&noCacheToken=12833886

The actual web preview is enabled by a Flash SWF file that is embedded in the page.

Note

The ActionScript source code for the Alfresco SWF previewer component is not available in the WAR file of a standard Alfresco installation. It can be found in the Alfresco Subversion source code repository under rootprojectsslingshotsourceaswebpreviewer.

Alfresco community source code can be downloaded from this Subversion URL: http://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD/.

The software that detects and checks for a valid version of the Flash player in the browser and embeds the Alfresco Flash previewer object on the web page is called SWFObject.

Note

Alfresco uses SWFObject 1.5 that is part of YUI 2.0. SWFObject is written by Geoff Stearns and released under the MIT license. The SWFObject JavaScript Flash Player is hosted on the code.google.com website at http://code.google.com/p/swfobject/.

The code in the file web-preview.js that embeds the previewer looks like this:

var so = new YAHOO.deconcept.SWFObject(Alfresco.constants.URL_CONTEXT + "components/preview/WebPreviewer.swf", swfId, "100%", "100%", "9.0.45");
so.addVariable("fileName", this.options.name);
so.addVariable("paging", previewCtx.paging);
so.addVariable("url", previewCtx.url);
so.addVariable("jsCallback", "Alfresco.util.ComponentManager.get('" + this.id + "').onWebPreviewerEvent");
so.addVariable("jsLogger", "Alfresco.util.ComponentManager.get('" + this.id + "').onWebPreviewerLogging");
so.addVariable("i18n_actualSize", this.msg("preview.actualSize"));
so.addVariable("i18n_fitPage", this.msg("preview.fitPage"));
so.addVariable("i18n_fitWidth", this.msg("preview.fitWidth"));
so.addVariable("i18n_fitHeight", this.msg("preview.fitHeight"));
so.addVariable("i18n_fullscreen", this.msg("preview.fullscreen"));
so.addVariable("i18n_fullwindow", this.msg("preview.fullwindow"));
so.addVariable("i18n_fullwindow_escape", this.msg("preview.fullwindowEscape"));
so.addVariable("i18n_page", this.msg("preview.page"));
so.addVariable("i18n_pageOf", this.msg("preview.pageOf"));
so.addVariable("show_fullscreen_button", true);
so.addVariable("show_fullwindow_button", true);
so.addParam("allowScriptAccess", "sameDomain");
so.addParam("allowFullScreen", "true");
so.addParam("wmode", "transparent");

The code embeds the Flash control into the web page and passes into it the filename, that is, the record name in the repository. It also sets a flag to indicate whether the file is multi-page and requires paging. The url is a path to the Flash or image rendition of the record to view. Text labels are set as well as some parameters to specify how the component will be viewed, such as with or without the Full Window mode.

The metadata component

The dod5015-metadata component is interesting in that it simply displays the standard metadata form for the record. From the file tomcatwebappsshareWEB-INFclassesalfrescosite-datacomponents emplate.dod5015-document-metadata.document-details.xml, we see that the standard form component is parameterized with properties that define the itemId, formId, and mode:

<?xml version='1.0' encoding='UTF-8'?>
<component>
<scope>template</scope>
<region-id>dod5015-document-info</region-id>
<source-id>document-details</source-id>
<url>/components/form</url>
<properties>
<itemKind>node</itemKind>
<itemId>{nodeRef}</itemId>
<formId>rm</formId>
<mode>view</mode>
</properties>
</component>

The form identified with the tag<form id="rm"> and of the document type cm:content is defined in the file tomcatwebappsshareWEB-INFclassesalfrescodod-5015-form-config.xml.

The events component

The dod5015-events component is defined by the files tomcatwebappsshareWEB-INFclassesalfrescosite-webscriptsorgalfrescocomponentsfileplanevents.get.*. The file events.get.head.ftl includes the client-side JavaScript file componentsfileplanevents.js.

The file events.get.html.ftl defines the FreeMarker layout for the component. The layout is divided into three<div> components, one to show the events that have completed, one to list events that have not yet completed, and another for a pop-up dialog that is normally hidden but pops up to collect information from the user when the event is manually completed.

There is no JavaScript controller file for this component. Most of the work for this component is done by the client-side JavaScript file events.js.

We can see in the code in the events.js file that a data webscript is called to find the next available events for this record:

url: Alfresco.constants.PROXY_URI_RELATIVE + "api/node/" + this.options.nodeRef.uri + "/nextdispositionaction"

This will resolve to a URL of the form:

http://localhost:8080/share/proxy/alfresco/api/node/workspace/SpacesStore/0ee56658-9518-4b2e-a679-8c2fd8aa0b59/nextdispositionaction

In this example, the JSON webscript response looks like the following:

{
"data":
{
"url": "/alfresco/s/api/node/workspace/SpacesStore/0ee56658- 9518-4b2e-a679-8c2fd8aa0b59/nextdispositionaction",
"name": "destroy",
"label": "Destroy",
"eventsEligible": false,
"asOf": "2020-10-01T12:23:19.828-07:00",
"events":
[
{
"name": "obsolete",
"label": "Obsolete",
"complete": false,
"automatic": true
},
{
"name": "no_longer_needed",
"label": "No longer needed",
"complete": false,
"automatic": false
},
{
"name": "superseded",
"label": "Superseded",
"complete": false,
"automatic": true
}
]
}
}

The JavaScript code then iterates through these events to render the Events component:

The events component

The references component

This component provides more good examples on how to build Alfresco pages using Spring-Surf. Multiple new pages are used to implement this functionality. Clicking on the Manage button of this component will bring up a new page with pageid rmreferences. Then, clicking on the New References button of that page brings up yet another page with pageid new-rmreference.

In a similar way to that described above and in earlier chapters, it is possible to trace through the chain of files from the pageid's to the components, JavaScript controller code, and FreeMarker templates for these pages to see how they have been constructed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset