3.7 Creating a module to add a HTML editor
We have created a form to add some blog items. It is of course not very user friendly to let users input HTML via a simple textarea. For that, we will use an existing HTML editor. We choose for TinyMCE here, because it has a jQuery plugin and is simple to plugin. We will create this as a separate module in our application and in this section, we'll show how to do that.
Creating the module structure
When creating our application by using the archetype, we have already added one module as default 'module1'. Beside this folder, we'll create a new module 'tinymce' with this folder structure:
-- myblog
|-- pom.xml
|-- conf
|-- wiring.xml
|-- module1
| ...
|-- tinymce
|-- src
| |-- main
| |-- kauri
| | |-- spring
| | |-- services.xml
| |-- tiny_mce
| | |-- jquery.tinymce.js
| | |-- tiny_mce.js
| | |-- .... rest of tinyMCE code
| |-- router.groovy
|-- pom.xml
Configure the tinymce module
- pom.xml : define the parent and artifact name
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0,http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.kauriproject</groupId>
<artifactId>myblog</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>kauri-tinymce</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>MYBLOG ::: TINYMCE</name>
<build>
</build>
</project>
- services.xml: make sure the restervice is exported
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:kauri="http://kauriproject.org/runtime/1.0#springext"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://kauriproject.org/runtime/1.0#springext
http://www.kauriproject.org/schemas/runtime/springext.xsd">
<context:annotation-config />
<kauri:module restletContext="context" classLoader="classloader" handle="module"/>
<kauri:import-service id="routing" service="org.kauriproject.routing.RoutingService"/>
<kauri:export-restservice ref="main"/>
<bean id="main" factory-bean="routing" factory-method="createRouter">
<constructor-arg ref="context"/>
<constructor-arg ref="module"/>
</bean>
</beans>
- for our own convenience, we'll make sure that we don't need to specify the tiny_mce directory name when we load the scripts. We can accomplish this by adding this snippet to the router.groovy of our tinymce module (located at src/main/kauri/router.groovy):
builder.router {
directory(
uri: "/",
listingAllowed: true,
root: "module:/tiny_mce/"
)
}
Wire it in the myblog application
To wire the new module inside the blog application, we add the tinymce artifact to the wiring.xml and mount the rest service on the correct path:
<artifact id="tinymce" groupId="org.kauriproject" artifactId="kauri-tinymce" version="1.0-SNAPSHOT">
<inject-restservice name="jquery" ref="jquery:main"/>
<mount name="main" path="/tinymce"/>
</artifact>
Because the other artifact 'module1' depends on this one, make sure to define 'tinymce' before 'module1'
In the root pom.xml, add the module:
<modules>
<module>module1</module>
<module>tinymce</module>
</modules>
Use it in the form
TinyMCE is now available via the service protocol, so we can load the tiny mce jquery script via this URI:
<script type="text/javascript" src="${publicUri('service:/tinymce/jquery.tinymce.js')}"></script>
When the script is loaded we can call tinymce on the textarea of the form:
$('form textarea').tinymce({
script_url : '${publicUri('service:/tinymce/tiny_mce.js')}',
theme : "simple"
});
Note that this will call tinymce for all textarea controls in your form. If you use this elsewhere, be more specific in the jQuery selector
To make sure the tinymce module copies its content to the textarea before submission of the form, we have to call the triggerSave method.
itemForm.prevalidation( function () {
tinyMCE.triggerSave(true, true);
$('form textarea').change();
});
Result
Page template {id}-edit.html now looks like this:
<?xml version="1.0"?>
<html t:inherit="module:/templates/layout.xml"
xmlns:t="http://kauriproject.org/template">
<t:init>
<t:variable name="id" value="${request.attributes.id}" />
<t:if test="${id != 'new'}">
<t:variable name="item" src="service:/data/items/${id}" overwrite="false" accept="application/json"/>
</t:if>
</t:init>
<t:block name="title">${item.title}</t:block>
<t:block name="extraHeaders">
<t:superBlock/>
<script type="text/javascript" src="${publicUri('service:/tinymce/jquery.tinymce.js')}"></script>
<script type="text/javascript">
jQuery(document).ready(function() {
var fconf = {
"createURI": "${publicUri('service:/data/items/')}",
type: {
members: {
'id' : {
'base' : 'integer',
'control' : {
'initial' : {
'enable' : false
}
}
},
'title': 'string',
'content': {
'base': 'string',
'control' : 'textarea-control'
},
'date' : 'date'
}
}
}; / *end fconf */
/* create form */
if(${id == 'new'})
fconf.createURI = "${publicUri('service:/data/items/')}";
else
fconf.dataURI = "${publicUri('service:/data/items/')}${id}";
var itemForm = new jQuery.org.kauriproject.forms.Form("item-form", fconf);
itemForm.setCreateMode(${id == 'new'});
if(${id != 'new'})
itemForm.setWireValue(${item});
$('form textarea').tinymce({
script_url : '${publicUri('service:/tinymce/tiny_mce.js')}',
theme : "simple",
});
itemForm.prevalidation( function () {
tinyMCE.triggerSave(true, true);
$('form textarea').change();
});
itemForm.submitSuccess = function (data, success) {
window.location = "${publicUri('service:/main/items/all.html')}";
};
});
</script>
</t:block>
<t:block name="content">
<form id="item-form">
</form>
</t:block>
</html>
Which results in:

You'll see at this point a date parse error when you load one of your entities, in the validation section we'll show how to solve this
Previous