Friday, October 31, 2008

Learning Surf 5 - Opening a content editor

In this blog entry, I will build on the tutorial in my last blog entry where I added a new button to the toolbar of the Document Library section of the Share application. When we click on this 'create' button, a dialog box should open (light box) with a form to create a new content item. When we press 'ok', a new content item should be created with the given name in the current folder.

Step 1 - Create a form webscript

My model example will be the document library 'create folder' web script in Share. This ui webscript contains a form to create a new folder. It is opened from clicking the 'New Folder' button on the Document Library section of Share. This function opens a form in a popup dialog like I want.

To create the web script ui form template, I will start by copying the create-folder.get.*.* webscript files from $SLINGSHOT_SRC_DIR/config/alfresco/site-webscripts/org/alfresco/modules/documentlibrary to $SLINGSHOT_SRC_DIR/config/alfresco/site-webscripts/org/alfresco/components/documentlibrary and rename them to 'create-content.get.*.*'. This creates three files:
  • create-content.get.desc.xml,
  • create-content.get.html.ftl
  • create-content.get.properties
Inside of create-content.get.desc.xml, we need to change the URI of the webscript to /components/documentlibrary/create-content and its description. create-content.get.desc.xml should now read:

<webscript>
<shortname>content-createform</shortname>
<description>Displays a form to create html content</description>
<url>/components/documentlibrary/create-content</url>
</webscript>



Now we have a new ui webscript component 'create-content' that we can call within a dialog that will render a form. The form contains labels for creating a folder so we can modify the create-content.get.properties with custom messages for this dialog:

## Titles
title=Create Content
header=New Content Details

## Labels
label.name=Name
label.title=Title
label.description=Description
Step 2 - Registering the new Web Script

Since we have created a new ui web script at /components/documentlibrary/create-content we need to register it. We simply go to 'http://localhost:8080/share/service/index' and click the 'refresh web scripts' button. This will scan for new web scripts. See the web scripts hello world quick start wiki page for more details. This page also shows a count of the total web scripts registered. We should see this increase by one. To verify the webscript is registered, we can click 'Browse by Web Script UI' and find our new component at '/components/documentlibrary/create-content'. Clicking on our uri, we see a details page describing the component. This information is taken from the 'create-content.get.desc.xml' file.

To test our new component, we can enter its url: 'http://localhost:8080/share/service/components/documentlibrary/create-content'. This will error in the web script because it requires the htmlid parameter to exist. If we enter 'http://localhost:8080/share/service/components/documentlibrary/create-content?htmlid' this will satisfy the requirement and the form should render.

Step 3 - Opening the form in a dialog

In my previous blog entry, we added a button to the toolbar of the Document Library named 'Create' which currently opens a popup message saying feature is not implemented. We will modify the 'Create' button behavior on Document Library toolbar to open this new create-content form in a dialog. In the previous blog, we created the onFileCreate action handler function of $SLINGSHOT_SRC_DIR/source/web/components/documentlibrary/toolbar.js to open a simple popup indicating the feature was not created yet. We will change this behavior by looking at the 'onFolderCreate' function as an example of opening a template in a dialog.

We will copy the body of DLTB_onFolderCreate into the body of DLTB_onFileCreate and change the line

templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "modules/documentlibrary/create-folder",
To read
templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "components/documentlibrary/create-content",
Where the final function should read:
  onFileCreate: function DLTB_onFileCreate(e, p_obj)
{
var actionUrl = YAHOO.lang.substitute(Alfresco.constants.PROXY_URI + "slingshot/doclib/action/folder/site/{site}/{container}/{path}",
{
site: this.options.siteId,
container: this.options.containerId,
path: this.currentPath
});

var doSetupFormsValidation = function DLTB_oNF_doSetupFormsValidation(p_form)
{
// Validation
// Name: mandatory value
p_form.addValidation(this.id + "-createFolder-name", Alfresco.forms.validation.mandatory, null, "keyup");
// Name: valid filename
p_form.addValidation(this.id + "-createFolder-name", Alfresco.forms.validation.nodeName, null, "keyup");
p_form.setShowSubmitStateDynamically(true, false);
};

if (!this.modules.createFolder)
{
this.modules.createFolder = new Alfresco.module.SimpleDialog(this.id + "-createFolder").setOptions(
{
width: "30em",
// templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "modules/documentlibrary/create-folder",
templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "components/documentlibrary/create-content",
actionUrl: actionUrl,
doSetupFormsValidation:
{
fn: doSetupFormsValidation,
scope: this
},
firstFocus: this.id + "-createFolder-name",
onSuccess:
{
fn: function DLTB_onNewFolder_callback(response)
{
var folder = response.json.results[0];
YAHOO.Bubbling.fire("folderCreated",
{
name: folder.name,
parentPath: folder.parentPath,
nodeRef: folder.nodeRef
});
Alfresco.util.PopupManager.displayMessage(
{
text: this._msg("message.new-folder.success", folder.name)
});
},
scope: this
}
});
}
else
{
this.modules.createFolder.setOptions(
{
actionUrl: actionUrl,
clearForm: true
});
}
this.modules.createFolder.show();
},


A lot more needs to be done. But at this point we should test our code.
To build and deploy, I use ant 'incremental-slinghot-tomcat' which should create the share.war and deploy to $APP_TOMCAT_HOME.

Clicking on the 'Create' button of Document Library, this is what we should now see:




Currently, this web script dialog should create a folder, not a content item that we want. We will modify this in the next step.

Step 4 - Modifying the Create Content dialog to accept content

In the dialog we are creating, some things to notice about the construction of the Alfresco.SimpleDialog object in our 'onCreateContent action handler function:
  • The 'actionURI' defined at the beginning of the function will be used to invoke the RESTful service on the content repository. Currently this is pointing to the create folder function, but we will change this to create new content.
  • There are two validators added 'manditory' and 'nodeName' to the name field of the createContent form. We will keep this behavior.
There is actually no 'content' entered for the new content. In creating a new folder, only the metadata 'name', 'title' and 'description' are needed. To create new content, we would also like to add the actual content. We will do this initially as plain text. Later, we will try to use a WYSIWYG editor.

To add the 'content' section, we will modify 'create-content.get.html.ftl' and add the following section:

         <div class="yui-gd">
<div class="yui-u first"><label for="${args.htmlid}-content">${msg("label.content")}:</label></div>
<div class="yui-u"><textarea id="${args.htmlid}-content" name="content" rows="3" cols="20" tabindex="3" ></textarea></div>
</div>



Here we have added a new div section to contain a textarea html form element with the name '-content'. This text area will allow us to enter plain text to supply content to our new document. Later we will modify this to use the yui html editor. The complete 'create-content.get.html.ftl' template should look like the following:

<div id="${args.htmlid}-dialog" class="create-folder">
<div class="hd">${msg("title")}</div>
<div class="bd">
<form id="${args.htmlid}-form" action="" method="post">
<div class="yui-g">
<h2>${msg("header")}:</h2>
</div>
<div class="yui-gd">
<div class="yui-u first"><label for="${args.htmlid}-name">${msg("label.name")}:</label></div>
<div class="yui-u"><input id="${args.htmlid}-name" type="text" name="name" tabindex="1" />&nbsp;*</div>
</div>
<div class="yui-gd">
<div class="yui-u first"><label for="${args.htmlid}-title">${msg("label.title")}:</label></div>
<div class="yui-u"><input id="${args.htmlid}-title" type="text" name="title" tabindex="2" /></div>
</div>
<div class="yui-gd">
<div class="yui-u first"><label for="${args.htmlid}-description">${msg("label.description")}:</label></div>
<div class="yui-u"><textarea id="${args.htmlid}-description" name="description" rows="3" cols="20" tabindex="3" ></textarea></div>
</div>
<div class="yui-gd">
<div class="yui-u first"><label for="${args.htmlid}-content">${msg("label.content")}:</label></div>
<div class="yui-u"><textarea id="${args.htmlid}-content" name="content" rows="3" cols="20" tabindex="3" ></textarea></div>
</div>
<div class="bdft">
<input type="button" id="${args.htmlid}-ok" value="${msg("button.ok")}" tabindex="4" />
<input type="button" id="${args.htmlid}-cancel" value="${msg("button.cancel")}" tabindex="5" />
</div>
</form>
</div>
</div>
You may also have noticed that we added a new label 'content', so we will have to update our create-content.get.properties file to include it.
label.content=content
Now that our form has the new '-content' field, we can extract content entered from it, and use it to pass to a remote webscript to create this content. To accomplish the creation of a new file, we need to create a new service. This will be the subject of my next blog entry.

1 comment:

Unknown said...

In order to view Alfresco Webscript, go to "http://localhost:8080/alfresco/service/index", aren't you?