CartoWeb implements an AJAX layer, enabling asynchronous update of the HTML GUI.
To enable your project with AJAX, it is recommended that you build your project based on demoCW3 or test_main projects (CartoWeb version 3.3.0 or higher). A project based on demoCW3 won't need any tuning. A project based on test_main will require the following:
- Enable AJAX in your client.ini (or client.ini.in):
If you have a project running since version 3.2.0 or before, and want to enable AJAX, you'll need to:
- Enable AJAX in your
client.ini(orclient.ini.in) - Adapt your
cartoclient.tpl,mainmap.tpland all redefined plugin templates (if they are based on test_main or demoCW3 project templates from CartoWeb version <= 3.2.0).
Add the ajaxOn directive and set it to true in your
/project/[yourProjectName]/client_conf/client.ini or
/project/[yourProjectName]/client_conf/client.ini.in
ajaxOn = true
There are several steps needed to add ajax support to a plugin :
- PHP
- javascript
- template
Your plugin php class must implements the Ajaxable interface.
class ClientYourPlugin extends ClientPlugin implements Ajaxable { ...
You can then add two functions:
- ajaxGetPluginResponse
- ajaxHandleAction
ajaxGetPluginResponse will send back your plugin's response.
It behaves the same way as the usual renderForm function.
instead of doing :
$template->assign($some_content);
you do :
$ajaxPluginResponse->addHtmlCode('some_variable_name', $some_content);
$ajaxPluginResponse->addVariable('another_variable_name', $some_content);
HtmlCode and Variable are pretty much
the same thing, it only differentiates
the treatments between html output and javascript variables.
ajaxHandleAction is where you specify which plugin(s) is
activated when an action is triggered through your plugin.
The content is usualy a switch on the action name:
switch ($actionName) {
case 'YourPlugin.SomeAction':
$pluginEnabler->disableCoreplugins();
$pluginEnabler->enablePlugin('images');
$pluginEnabler->enablePlugin('yourplugin');
break;
case 'YourPlugin.AnotherAction':
$pluginEnabler->disableCoreplugins();
$pluginEnabler->enablePlugin('yourplugin');
break;
}
You must explicitly enable your plugin
$pluginEnabler->enablePlugin('yourplugin');
otherwise your plugin will not send back anything.
disableCoreplugins(); explicitly deactivate all coreplugin. It means nothing
will be sent back to the browser.
You can activate plugin case by case, for example:
$pluginEnabler->disableCoreplugins();
$pluginEnabler->enablePlugin('images');
will only enable the images coreplugin and the map will then be refreshed.
Create a new javascript file named YourPlugin.ajax.js
Place it in plugins/yourPlugin/htdocs/js/
Add it to your cartoclient.tpl header:
<script type="text/javascript" src="{r type=js plugin=yourPlugin}YourPlugin.ajax.js{/r}"></script>}
be careful to not place it before {include file="cartoclient_ajaxHeader.tpl"}, you will get a javscript error because the plugin's javascript code use some objects which are defined only in files inluded via the cartoclient_ajaxHeader.tpl file.
The YourPlugin.ajax.js contains basicaly two parts, one to trigger the action and another to handle the answer and update your html/javascript
AjaxPlugins.YourPlugin = {
handleResponse: function(pluginOutput) {
/* Plugin general behaviour */
if (pluginOutput.variables.variable_name) {
// do something with your variable
alert(pluginOutput.variables.another_variable_name);
}
AjaxHandler.updateDomElement('target_id', 'innerHTML',
pluginOutput.htmlCode.some_variable_name);
}
};
}
The answer sent by PHP is handled in handleResponse. Here you recover the variables and htmlCodes.
The function updateDomElement will handle all the html insertion. It takes 3 parameters:
- the target id of the existing element in your current html which will serve as container for the new content.
- the insertion methode, always 'innerHTML'.
- the new content.
In this part, you simply define all your actions and what to do before, when and after the actions are triggered.
AjaxPlugins.YourPlugin.Actions = {};
// always empty, it only define a Actions object which will store our various actions.
AjaxPlugins.YourPlugin.Actions.SomeAction = {
buildPostRequest: function(argObject) {
return AjaxHandler.buildPostRequest();
},
.
onBeforeAjaxCall: function(argObject) {
Logger.note('Output something in the JSTraceDebugger window');
callSomeJavascriptFunctions();
},
onAfterAjaxCall: function(argObject) {
Logger.note('Output something in the JSTraceDebugger window');
callSomeJavascriptFunctions();
},
onBeforeAjaxCallGeneral: function(argObject) {
Logger.note('Output something in the JSTraceDebugger window');
callSomeJavascriptFunctions();
},
onAfterAjaxCallGeneral: function(argObject) {
Logger.note('Output something in the JSTraceDebugger window');
callSomeJavascriptFunctions();
},
oneCustomFunction: function() {
Logger.note('Output something in the JSTraceDebugger window');
// you can also define functions
...
}
};
AjaxPlugins.YourPlugin.Actions.AnotherAction = {
buildPostRequest: function(argObject) {
return AjaxHandler.buildPostRequest();
}
};
Warning
BE CAREFUL FOR CLOSING "," and ";" !!!!
these are json syntax and it is a bit different than your usual javascript.
buildPostRequestis always executed, it simply parses your html and recover all the inputs (text, hidden, select, radio, checkbox, password, textarea) values and send them to the server.onBeforeAjaxCallandonAfterAjaxCallare optional. These functions are called before and after the action. For example if you want to modify some inputs value just before it's being sent to the server. Or you want too add some post-treatments. Note thatonAfterAjaxCallis called AFTER the response is being treated in the normalhandleResponsestage (see Section 21.2.4.1, “Ajax Answer Handling”).onBeforeAjaxCallGeneralandonAfterAjaxCallGeneralare optional. These functions are called EVERYTIME an AJAX call is triggered by ANY plugins. If you add these functions in your plugin, the functions will be called even if the action was triggered by another plugin.onBeforeAjaxCallGeneralis called BEFOREonBeforeAjaxCall.onAfterAjaxCallGeneralis called AFTERonAfterAjaxCall.
If the html fragment your are inserting must implement on-the-fly javascript event, you can attach some event on existing elements via the attachAction function:
AjaxHandler.attachAction('target_element_id', 'type_of_event', 'callback_function', json_defined_arguments);
for example:
AjaxHandler.attachAction('pan_n', 'click', 'Location.Pan', {source: 'button'});
You can define custom functions as well, see the oneCustomFunction above. But
you will need to explicitly call these functions from buildPostRequest,
onBeforeAjaxCall or onAfterAjaxCall.
The function is called like this: this.oneCustomFunction();
You can output some notice or warning in the JSTraceDebugger windows by adding:
Logger.note('Some text that will appear in the debugger');
You can also use 'send', 'header', 'error', 'warn', 'trace' or 'confirm'.
They have slightly different styling. See file Logger.js for details.
You may want to call some functions or define some variables on page load. To do so simply add your plugin into the AjaxPlugins.initializablePlugins array, like this:
// add your plugin to the list of Ajax initializable plugins AjaxPlugins.initializablePlugins.push(AjaxPlugins.YourPluginName);
Add this after your main
AjaxPlugins.YourPluginName = {...};
To trigger the actions defined in YourPlugin.ajax.js, you simply call them like this:
<input type="button" value="{t}ok{/t}" onclick="return CartoWeb.trigger('YourPlugin.AnotherAction');" />
}
or if you want to provide a non-ajax fallback, you can do it like that:
<input type="button" value="{t}ok{/t}" onclick="return CartoWeb.trigger('YourPlugin.AnotherAction', 'doSubmit()');" />
}
Warning
Adapting your templates is a tricky bit. Unless you customized your templates thoroughly, we recommend that you start over again your templates customization using demoCW3 or test_main as a basis, as these projects templates are AJAX ready.
We recommend that you diff your cartoclient.tpl, mainmap.tpl and all redefined plugin templates with the upstream. This is the best way to be up to date, especially if you use the latest CVS version of CartoWeb.
Tip
Original templates patch: http://bugzilla.maptools.org/attachment.cgi?id=126&action=view