We will first learn how to create a standalone application using the Surf framework without the use of Alfresco. For this you need to download surf.war
and keep it in your web or application server. For this chapter, you can place the WAR file in the<install-alfresco>/tomcat/webapps
folder. This doesn't mean that we are using Alfresco for our development. You can also place the WAR file in any standalone server. Start your server. You will find that the surf.war
file has exploded and the surf
folder is created. You can see the following structure created by default:
Follow the steps below to create a sample page:
<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-data/configurations
folder. default.site.configuration.xml
file. Insert the highlighted code as mentioned below to create our home page:<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<title>Sample Site Configuration</title>
<description>Sample Site Configuration</description>
<source-id>site</source-id>
<properties><root-page>index</root-page></properties>
</configuration>
<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-data/pages
folder. root-page
tag. Create the index.xml
file. Insert the following code:<?xml version='1.0' encoding='UTF-8'?> <page> <id>index</id> <title>CIGNEX | Open Source ECM, BPM , E Commerce , Portals </title> <description>Sample Cignex home page</description> <template-instance>index</template-instance> <authentication>none</authentication> </page>
<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-data/template-instances
folder. template-instance
tag. Create the index.xml
file. Insert the following code:<?xml version='1.0' encoding='UTF-8'?> <template-instance> <template-type>index</template-type> </template-instance>
<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/templates
folder. template-instance
tag. Create the index.ftl
file. Insert the following code:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>${page.title}</title> </head> <body> Home Page </body> </html>
http://<server-name>:<port>/surf
.You will face a caching issue while using the Surf framework. In order to save server restart during development of an application, you can disable cache for the time period.
/WEB-INF/classes/alfresco/web-framework-application-context.xml
file. 0
. There are two occurrences and properties to change:<property name="updateDelay"><value>0</value></property>
OR
By reloading the page, the changes will not be reflected. You have to explicitly clear the cache. Browse to the cache as follows:
http://<server-name>:<port>/surf/control/cache/invalidate
The Surf framework binds the component to the specific region of a page and also specifies scope. Using this one can decide the position of the component to be placed in the page.
For instance, the footer should always be at the bottom of the page and the header should always be at the top of the page. As discussed earlier, each component has scopes to be defined. The Surf framework defines three categories of scopes:
Let's try to create a header component, the scope of which will be global. The naming convention for the component is very important. The name is defined as follows:
Scope.regionId.sourceId.xml
According to this, we are going to create global.header.xml
. Here global
is the scope, header
is the region, and global
is the sourceId
. However, we have not used the third parameter, as it is a global scope component and therefore is used on all pages.
global.header.xml
file in the<install-application>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-data/components
folder and insert the following code:<?xml version='1.0' encoding='UTF-8'?> <component> <scope>global</scope> <region-id>header</region-id> <source-id>global</source-id> <url>/component/common/header/header</url> </component>
The<url>
tag is used to call web scripts. You will learn about web scripts in Chapter 10. Refer to the chapter to know more details about the web scripts. Web scripts are placed in the<install-application>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-webscripts
folder.
header
folder inside the components/common
folder. Create a new file header.get.desc.xml
in the header
folder. Insert the following code:<webscript> <shortname>Global Header Component</shortname> <description>Header component used across the whole application</description> <url>/component/common/header/header</url> </webscript>
header.get.html.ftl
, in the same location and insert the following code:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="description" content="Small Corporation" /> <meta name="keywords" content="small, corporation" /> <link rel="stylesheet" type="text/css" href="${app.context}/css/style.css" media="screen" /> <link rel="stylesheet" type="text/css" href="${app.context}/css/base.css" media="screen" /> <div id="site-header"> <table cellpadding="0" cellspacing="0" border="0"> <tr> <td align="left" valign="top" > <img src="/surf/images/logo/cignex-logo.png" alt="Cignex logo" width="159" height="85" border="0" /> </td> </tr> </table> </div> <ul id="menu"> <li><a class="current" href="#">SOLUTIONS</a></li> <li><a href="#">SERVICES</a></li> <li><a href="#">TECHNOLOGY</a></li> <li><a href="#">CUSTOMERS</a></li> <li><a href="#">PARTNERS</a></li> <li><a href="#">RESOURCES</a></li> <li><a href="#">WHAT's New </a></li> <li><a href="#">RESOURCES</a></li> </ul>
Our component is now ready to be placed in the page. In this template we are using stylesheets and images. You can create stylesheets in the<install-application>/tomcat/webapps/surf/css
folder. For images you have to navigate to the<install-application>/tomcat/webapps/surf/images
folder.
http://<server-name>:<port>/surf/service
.
index.ftl
(that you have created earlier within the<install-application>/tomcat/webapps/surfWEB-INF/classes/alfresco/templates
folder within the<body>
tag. Here we are using the region and scope defined in the component created earlier.<@region id="header" scope="global" />
http://<server-name>:<port>/surf/
.In the previous section, we learned about page creation and putting a component into a page. In this section, we shall learn about navigation from one page to another page.
For this, create one more page. Now we are going to link this page to the page we created earlier.
Create the new page. Create the new "template instance" so that the new template can be referenced from a page component. Create the new FTL template file.
news.xml
in the<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-data/pages
folder. Insert the following code:<?xml version='1.0' encoding='UTF-8'?> <page> <id>news</id> <title>What's New</title> <description>Sample Cignex News page</description> <template-instance>news</template-instance> <authentication>none</authentication> </page>
news.xml
in the<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-data/template-instances
folder. Insert the following code:<?xml version='1.0' encoding='UTF-8'?> <template-instance> <template-type>news</template-type> </template-instance>
news.ftl
in the<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/templates
folder. Insert the following code:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>${page.title}</title> ${head} </head> <body> <@region id="header" scope="global" /> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tr> <td valign="top"> <img src="/surf/images/cignex/learn-more-2.gif" border=0 alt="Click To View"> </td> </tr> <tr> <td valign="top"> <img src="/surf/images/cignex/liferay-offer-1.gif" border=0 alt="Click To View"> </td> </tr> <tr> <td valign="top"> <img src="/surf/images/cignex/alfresco-offer-1.gif" border=0 alt="Click To View"> </td> </tr> <tr> <td valign="top"> <img src="/surf/images/cignex/alfresco-challenge_0.gif" border=0 alt="Click To View"> </td> </tr> </table> </body> </html>
By this time one more page is ready. Now we have two pages and one header component in place. We will see how one page can be linked to another page.
<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-data/page-associations
folder. index-news.xml
. With this we are associating index page to news page and vice versa. Insert the following code:<?xml version='1.0' encoding='UTF-8'?> <page-association> <source-id>index</source-id> <dest-id>news</dest-id> <assoc-type>child</assoc-type> <order-id>1</order-id> </page-association>
<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco/site-webscripts/components/common/header
folder. header.get.js
. Insert the following code:// renderer attribute var renderer = instance.properties["renderer"]; if(renderer == null) { renderer = "horizontal"; } model.renderer = renderer; // set up rendering attributes model.rootpage = sitedata.getRootPage(); model.linkbuilder = context.getLinkBuilder();
header.get.html.ftl
file. Insert the following code.<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="description" content="Small Corporation" /> <meta name="keywords" content="small, corporation" /> <link rel="stylesheet" type="text/css" href="${app.context}/css/style.css" media="screen" /> <link rel="stylesheet" type="text/css" href="${app.context}/css/base.css" media="screen" /> <table> <tr> <td> <img src="/surf/images/cignex/cignex-logo.png" border=0 alt="Click To View"> </td> </tr> </table> <#if renderer == "horizontal"> <@horizontal page=rootpage showChildren=true/> </#if> <#macro horizontal page showChildren> <#assign currentPageId = ""> <#if context.pageId?exists> <#assign currentPageId = context.pageId> </#if> <ul id="menu"> <li> <#assign href = linkbuilder.page(page.id, context.formatId)> <#assign classId = ''> <#if page.id == currentPageId> <#assign classId = 'current'> </#if> <a href='http://${href}' id='${classId}'>SOLUTIONS</a> </li> <li> <#assign href = linkbuilder.page(page.id, context.formatId)> <a href='http://${href}' id='current'>SERVICES</a> </li> <li> <#assign href = linkbuilder.page(page.id, context.formatId)> <a href='http://${href}' id='current'>TECHNOLOGY</a> </li> <li> <#assign href = linkbuilder.page(page.id, context.formatId)> <a href='http://${href}' id='current'>CUSTOMERS</a> </li> <li> <#assign href = linkbuilder.page(page.id, context.formatId)> <a href='http://${href}' id='current'>PARTNERS</a> </li> standalone application, Surf framework usedpage navigation, designing<li> <#assign href = linkbuilder.page(page.id, context.formatId)> <a href='http://${href}' id='current'>RESOURCES</a> </li> <#-- Children of Home Page --> <#list sitedata.findChildPages(page.id) as parentPage> <li> <#assign href = linkbuilder.page(parentPage.id, context.formatId)> <#assign classId = ''> <#if parentPage.id == currentPageId> <#assign classId = 'current'> </#if> <a href='http://${href}' id='${classId}'>${parentPage.title}</a> </li> </#list> <li> <#assign href = linkbuilder.page(page.id, context.formatId)> <a href='http://${href}' id='current'>COMPANY</a> </li> </ul> </#macro>
http://<server-name>:<port>/surf/service
.So far we have learned about the creation of a single-tier application. Now if we want to create a two-tier application, we shall create one more web script, which will be calling web scripts that are defined in Alfresco WCM.
Alfresco Surf works hand-in-hand with Alfresco Web Content Management and provides virtualized content retrieval, preview, and test support for User Sandboxes and web projects. Applications built with Alfresco Surf can be deployed from Alfresco Web Project spaces to production servers while taking full advantage of Alfresco WCM's Enterprise class features. These include:
User Sandboxes provide freedom for experimentation and iteration in design. Change anything about your Surf site with the assurance that you can always discard changes or promote the bits you are happy with.
The following example is for integrating WCM web scripts with the Surf application. This Web Script is actually located on the remote Alfresco server and therefore we have to configure Surf to search the location for web scripts.
<install-alfresco>/tomcat/webapps/surf/WEB-INF/classes/alfresco
folder. web-framework-config.xml
file. Insert the following code before</web-framework>
. The highlighted text cignex is the DNS name of the web project. This lets Surf bind to web application resources of the "cignex" web project.<resource-resolver> <id>webapp</id> <name>Alfresco Web Application Resource Resolver</name> <description> Resolves data access for web application assets </description> <class> org.alfresco.web.framework.resource.AlfrescoWebProjectResourceResolver </class> <alias-uri>/files</alias-uri> <store-id>cignex</store-id> </resource-resolver>
webscript-framework-config.xml
. Uncomment the following code that is placed in the file. This configures the remote Alfresco repository as an endpoint.<endpoint> <id>alfresco-system</id> <name>Alfresco - System access</name> <description>System account access to Alfresco</description> <connector-id>alfresco</connector-id> <endpoint-url>http://localhost:8080/alfresco/s </endpoint-url> <identity>declared</identity> <username>admin</username> <password>admin</password> <unsecure>true</unsecure> </endpoint>
The rest of the case study is covered in Chapter 10, in the Alfresco WCM Surf-based Web application integration section.
Now we shall create one more web script that will call other web scripts that are stored in Alfresco WCM to fetch data.
news
folder inside the site-webscripts/components/common
folder. Create a new file news.get.desc.xml
in the news
folder. Insert the following code:<webscript> <shortname>News</shortname> <description>Calls the remote Alfresco web script</description> <url>/component/common/news/news</url> </webscript>
news.get.html.ftl
, in the same location and insert the following code:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="description" content="Small Corporation" /> <meta name="keywords" content="small, corporation" /> <link rel="stylesheet" type="text/css" href="${app.context}/css/style.css" media="screen" /> <link rel="stylesheet" type="text/css" href="${app.context}/css/base.css" media="screen" /> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tr> <td valign="top"> <#list news as n> ${n.Headline} <br> </#list> </td> </tr> </table>
news.get.js
, in the same location and insert the following code:{ // get a connector to the Alfresco repository var connector = remote.connect("alfresco-system"); var jsonFeed = connector.get("http://localhost:8080/alfresco/service/org/cignex/news/getNewsHeadlines.json?storeId=cignex"); var obj = eval('(' + jsonFeed + ')'), if (obj) { model.news = obj["newsItems"]; } }
YUI is a set of utilities and controls, written with JavaScript and CSS, for building richly interactive web applications. It is an open source JavaScript library using techniques such as DOM scripting, DHTML, and AJAX. YUI consists of several CSS components and nearly three dozen JavaScript components, all of which are designed to empower the rapid creation of web applications that run in all of the major web browsers. It provides a rich set of widgets and utilities, such as animation, drag-and-drop, image loader, menu, paginator, uploader, and many others. Mainly, it has six components:
As we discussed earlier, we have a set of predefined controls that we can use by instantiating an object and calling a set of methods on them.
For instance, use the horizontal menu plugin provided by the YUI library and observe how easy it is to make a rich menu.
Modify the file header.get.html.ftl
located at site-webscripts/components/common/header
. Insert the downloaded code from the Packt website. You will notice a change in the menu style.
Alfresco Web Editor is an application developed using the Spring Surf platform. It provides in-context editing capabilities for Alfresco repository content. Because of the in-context editing capability of the Web Editor, it's very easy for any non-technical person to edit Alfresco content directly from the web page. It supports Presentation editing for Surf-based websites.
Alfresco Web Editor is a Surf application incorporating the Alfresco Form Engine. It uses the Form Service default template.
Alfresco Web Editor is packaged as a standalone WAR file (awe.war
). Hence you can deploy it as a standalone application on the same server where Alfresco is running or also can deploy it as a part of any Surf Application remote to the Alfresco server.
First you need to download the Alfresco Web Editor. A file alfresco-enterprise-webeditor-3.3.zip
will consist of the awe.war
file and other required files. To deploy AWE, follow the steps mentioned below:
alfresco-enterprise-webeditor-3.3.zip
file. Refer to the Alfresco wiki to download the community version: http://wiki.alfresco.com/wiki/Alfresco_Community_Edition_3.3. awe.war
file (which is there in the downloaded ZIP file) into the same application server where Alfresco is running.Once you start the Alfresco server, you can navigate to http://localhost:8080/awe
. You will see the login page; provide the same username and password you are using for Alfresco (admin/admin).
The first page you will see will be the metadata page; here you can pass any Alfresco content noderef as itemId
parameter and can update the metadata of that content as shown in the following screenshot:
As mentioned in the introduction of the Alfresco Web Editor, we can also deploy the Web Editor to any Surf Application, which is remote to the Alfresco server. In this section, we will discuss how we can deploy and what are the extra configurations we need to do for using it in a Surf-based application. The Alfresco Web Editor distribution contains all of the required files for configuring it for the Surf-based application.
WEB-INF/lib
directory:yui-2.7.0.jar
spring-webeditor-1.0.0.CI-SNAPSHOT.jar
alfresco-forms-client-3.3.jar
alfresco-webeditor-plugin-3.3.jar
Alfresco Web Editor provides tag library. If you intend to use the tags provided in this library, you need to copy the alfresco-webeditor-taglib-3.3.jar
file in the WEB-INF/lib
folder.
This tag library mainly includes three tags: startTemplate, markContent
, and endTemplate
. We will discuss about these tags later in this chapter.
If you are using the previously mentioned tags, startTemplate, markContent,
and endTemplate
will only render the output if you have configured the Web Editor filter in web.xml
as follows:
<filter> <filter-name>Alfresco Web Editor Filter</filter-name> <description>Enables support for the Alfresco Web Editor</description> <filter-class>org.alfresco.web.awe.filter.WebEditorFilter</filterclass> </filter> <filter-mapping> <filter-name>Alfresco Web Editor Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
You can also set the following two optional parameters to control the contextPath
when the URLs to the Web Editor are generated and for the debug mode:
<init-param> <param-name>contextPath</param-name> <param-value>/quickstart</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param>
The Alfresco Web Editor uses Forms to edit the content and the metadata. By default, it displays the title, description, and content fields. An alternative form can be used by providing a markContent
tag with the formId
attribute.
The node type is presumed to be cm:content
. If you have custom types or wish to specify other properties, you can use the form's configuration techniques.
The Alfresco Web Editor tag library consists of three tags: StartTemplate, markContent
, and endTemplate
.
startTemplate
tagThis tag bootstraps the Web Editor Framework using a script element that executes a Web Script. Place this tag in the head section of the page.
Attributes:
toolbarLocation
This attribute specifies the location of the toolbar.
<awe:startTemplate toolbarLocation="top" />
specifies the location as top in the window for the toolbar.
The possible values are: top, left
, and right
. This is an optional attribute; the default is top
.
markContent
tagThis tag indicates the editable area on the page. This renders an Edit icon; when clicked, it displays a form to edit the content or metadata or both.
Attributes:
id:
This attribute specifies the noderef of the Alfresco node. This is a mandatory attribute.
title:
This attribute specifies a title for the marked editable area. The same title will be used in quick edit drop down, form edit pop-up dialog, and so on.
This is a mandatory attribute.
formId:
This attribute specifies which form will be used when the marked area is edited. This is an optional attribute.
nestedMarker:
This attribute defines whether the editable area is nested within another HTML tag that represents the content being edited. If set to "true" the whole parent element is highlighted when the area is selected in the quick edit drop-down menu. If set to "false", only the edit icon is highlighted.
endTemplate
tagThis tag initializes the Web Editor with details of all of the marked content areas on the page. It also renders a script element that executes the WEF resources web script, which starts the process of downloading all of the assets required to render and display the toolbar and all configured plugins. Place this tag just before the closing body element
Attributes:
This tag doesn't have any attribute.
When you download the Web Editor distribution, you will find one sample application, customer.war
. This is a simple JSP-based application, which uses the tag library provided by AWE.
In this application, we will use the already created content on our custom JSP and will allow users to have an in-context editing facility for that content.
For example, you can create content in Alfresco. Go to Company Home and a specific space where you want to create the content. Use the Add content functionality to upload any file. Here in this example, I have uploaded one HTML file called Cignex_Merge_News.html
to the Alfresco repository.
In the noderefs.jsp
file located at customer/includes
, provide the noderef of the previously created content from the Alfresco Repository as shown next (it is the modified content of noderefs.jsp):
<% String mainTextNodeRef = "workspace://SpacesStore/3b12b9a8-8f9f-414d-8a9d-40047822d1cf"; %>
Note that workspace://SpacesStore/3b12b9a8-8f9f-414d-8a9d-40047822d1cf
is the noderef
of Alfresco content Cignex_Merge_News.html
. To find the nodeRef
of your content, go to the View Details page of the content and click on Alfresco Node Reference.
Also update the body.jsp
located at customer/includes
accordingly.
Once you specify the noderefs as earlier and click onhttp://localhost:8080/customer
, you can see the screen shown in the following screenshot:
This application has custom tags to display the property and content of the specified noderef.
To display any property of the noderef, use a property tag like:
<customer:property nodeRef="<%=mainTextNodeRef%>" property="cm:description" />
To display the content of the noderef, use a content tag like:
<customer:content nodeRef="<%=mainTextNodeRef%>" />
As discussed earlier, the startTemplate
tag will have a toolbarLocation
attribute that specifies the location of the toolbar (the default is "top"). The following screenshot shows the toolbar on the page:
You can directly click on the link available in the drop-down here in the toolbar. Another option is the Edit icon that is also available with the content. The following screenshot shows how you can use the in-context editing feature to edit the content.
When you click on the Edit icon, it will open the window in which you can edit the title, description, or content. This window is using Alfresco's form service. You can specify which form ID you want to use for in-context editing. As described in the earlier section, with the markContent
tag, you can specify the formId
attribute, which specifies the form to use for in-context editing. For example:
<awe:markContent id="<%=<<NODEREF>>%>" formId="description" title="Edit News Description" nestedMarker="true" />
Web Editor Framework consists of core components and UI widgets. The framework allows you to easily develop and add the plugin. This is achievable because of the nature of the framework, which is supplied by the support of hooks around core methods. The web editor is an event-driven framework. Every core method of a plugin fires a before and an after event for that method.
The Core WEF Components are as follows:
The Core WEF Widgets are as follows:
For more details on WEF, refer to the link: http://wiki.alfresco.com/wiki/Web_Editor_Framework.
The Alfresco Surf platform and tools are designed to help users create the next-generation WCM platform that covers both core management aspects and delivery capabilities. The Alfresco Web Editor is a Surf-based application incorporating the Alfresco Form Engine, which facilitates in-context editing of Alfresco repository content.