6.0.0-git
2018-12-11
Last Modified 2018-11-23 by Ralf Lang (B1 Systems GmbH)

Documentation of Horde Ajax Applications mostly from poking around existing examples.

The Horde Ajax framework facilitates creating javascript-heavy single page applications but is also useful in other contexts.
It contains of a horde-wide server-side entry point ajax.php and per-application definitions which handlers are used.
On the client side, HordeCore.js provides the tools to call these endpoints and automatically add security tokens to the request.

Convention

$app (lowercase, for example "passwd")
$App (First Uppercase, for example "Passwd")

Javascript libraries used

JavaScript for "dynamic" and "traditional" mode uses PrototypeJS
JavaScript for "smartmobile" mode uses jQuery Mobile

Using jquery alongside prototype

This is generally not accepted upstream.
jQuery can be made coexist with dynamic/traditional mode's PrototypeJS

For non-upstream custom code:

var $j = jQuery.noConflict();
$j(document).ready(
/* Do jquery stuff here. $.* is prototype, $j.* is jQuery. Some plugins may not like this, but DataTables, JQuery UI and mainstream stuff work */
);

Files and Classes of a Horde Ajax Application

Horde_Ajax_Application class

Bare Minimum for a Horde Ajax Application (on top of a skeleton Horde_Registry_Application):
A File $app/lib/Ajax/Application.php with a class

<?php
// phpdoc omitted
class $App_Ajax_Application extends Horde_Core_Ajax_Application {}
?>

Horde_Core_Ajax_Application documentation

Making an ajax call to Horde

Implement $App_Ajax_Application and load at least one handler class $App_Ajax_Application_Handler in the _init function.
https://github.com/horde/kronolith/blob/master/lib/Ajax/Application.php
https://github.com/horde/kronolith/blob/master/lib/Ajax/Application/Handler.php

Call HordeCore.doAction(action, params, opts) from JS:
action is corresponding to one method name in one of the loaded handlers.
options is a json object with parameters.

doAction takes care of authentication details transparently.

Real Life Example:
https://github.com/horde/kronolith/blob/master/js/kronolith.js#L296

  HordeCore.doAction('searchEvents', {
                cals: Object.toJSON(cals),
                query: query,
                time: this.search
}, {
 callback: function(r) {

}

The handlers have no parameters. They expect named parameters in $this->vars->$name corresponding to the params in the doAction call's second argument.

Return values:
Normally, you would return an array structure of serializable data. It will automatically be sent to browser as a json structure. You can also return a string (like HTML) or a Horde_Core_Ajax_Response object for more advanced use cases.

Application-specific javascript code

Most apps which sport completely distinct dynamic and traditional views (kronolith, hermes) also have $app/js/$app.js

var $AppCore = {
/* What is strictly required here? */
}
document.observe('dom:loaded', $AppCore.onDomLoad.bind(AppCore));
// more observers as needed

View Selection

Common, but not strictly required:

Logic in $app/index.php to decide if traditional, ajax or other modes should be loaded.

TODO: Example

Horde Ajax Request Service

The Horde Base App provides a common receiver for ajax requests by Ajax_Applications.
It only works for AUTHENTICATED user requests.

Fails silently for malformed requests and unauthenticated users
It loads the app, passes the call's variables to $App_Ajax_Application and runs the ->doAction() method on this class.
Finally it returns a Response.

The default response type is JSON

TODO: Does this only work for pretty URL rewriting mode?

TODO: pretty example

horde/services/ajax.php

**
 * Processes an AJAX request and returns a JSON encoded result.
 *
 * Path Info:
 * ----------
 * http://example.com/horde/services/ajax.php/APP/ACTION
 *
 * 'APP' - (string) The application name.
 * 'ACTION' - (string) The AJAX action identifier.
 *
 * Reserved 'ACTION' strings:
 * 'logOut' - Logs user out of Horde.
 *
 * Copyright 2010-2012 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.horde.org/licenses/gpl.
 *
 * @author  Michael Slusarz <slusarz@horde.org>
 * @package Horde
 */

$App_Ajax_Application_Handler

A Handler inherits from Horde_Core_Ajax_Application_Handler and can manage external/public (unauthenticated??) calls
extends Horde_Core_Ajax_Application_Handler

Seems like the difference between Horde 5 and Horde 4 is that each action has its own Handler class rather than a methods in the $App_Ajax_Application class?

Client side js infrastructure

important hordecore.js HordeCore class methods:

  • doAction(action, params, opts) - client side method for ajax requests against Horde_Ajax_Application
  • submitForm(form, opts) - ajax request to submit a form

Depending on the presentation type (Dynamic, Smartmobile), the PageOutput php helper injects some default javascript environment.

  • HordeCore.conf provides configurable or runtime-generated information
  • HordeCore.conf.TOKEN is the request token to identify the client session when calling the Ajax framework for more data
  • HordeCore.conf.URI_AJAX is the URL to the Ajax service endpoint for the current app
  • HordeCore.text provides a hash of messages translated to the current environment

If you need to provide dynamic initialization data specific to your app, use the PageOutput addInlineJsVars method in your application page.

The big picture

  • When do I use a service/ajax.php handler as opposed to a rampage.php Controller ?
  • Imples seem to be used to return snippets? "Don't use imples; they are archaic and can generally be rewritten using the Ajax framework instead"

Single Page Applications (Hermes, Imp, Kronolith)

Single Page Applications generally try to keep the user in one location. Different "pages" of the app are simulated by using hash anchors appended to the url: http://www.horde.org/application/index.php#newCalendar

The javascript of the application responds to these URLs by unhiding the appropriate part of the HTML and filling it with data, possibly collected via AJAX calls to the Horde server application. As long as the browser does not reload, application state is present in the local javascript/dom. The local javascript application sends messages to the server and receives answers - for example "delete item FOO - OK" or "send me the current item list - Here is the list".

In Kronolith and Hermes,
Static snippets of HTML like dialogs (without the data) are called slices - they live in /template/ and have a .inc filename extension.

A function go(fullloc, data) allows to change into different screens.