6.0.0-beta13
4/10/26

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

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

  • Javascript libraries used

JavaScript for "Dynamic" and "traditional" mode uses prototype.js
JavaScript for "SmartMobile" mode uses query-mobile.js

++ using jquery alongside prototype
This is generally not accepted upstream.
jQuery can be made coexist with dynamic/traditional mode's prototype.js

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

Inherited methods:

doAction (see below)
logOut
responseType (set response type for the request)
getSessionLogoutUrl
listGroups
parseEmailAddress
chunkContent (process and return a template part from $app/templates/chunks/$chunk.php)
setPrefValue

++ AppCore.js file

Most apps which sport completely distinct dynamic and traditional views (kronolith, hermes) also have $app/js/$app.js including a Class $AppCore
In Imp, the class name is

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. gollem does not have this.

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

**

++ What is an imple?
An Imple inherits from Horde_Core_Ajax_Imple and implements php code tied to a javascript request
(how is this related to a services/ajax call?)

Horde_Core ships some imple's, apps define theirs in $app/lib/Ajax/Imple/Foo.php

Imple methods:
(Not much documentation available. Maybe we find a good example)

/**
* Attach the object to a javascript event.
*/
abstract public function attach();

/**
* TODO
*
* @param array $args TODO
*/
abstract public function handle($args, $post);

Example:

''This example is probably not the way they do it today as I read it some time ago from a very dated 2/2012 git checkout''

Kronolith_Ajax_Imple_Embed returns a javascript calendar widget for use in external sites
The attach() method is implemented as noop.
The handle() method takes some arguments and returns a processed js/html snippet

Kronolith users should paste a snippet like this into their website to use the calendar widget:

<script src="/services/ajax.php/kronolith/embed?token=c_T1Vso1zfaSOMEMAGICHERENHKWmg1&calendar=internal_70fhZCYOURSISDIFFERENTRWNDA&container=kronolithCal&view=month" type="text/javascript"></script>
So this finally calls services/ajax.php , starts/authenticates (HOW?) the kronolith app, passes the "embed" action and the URL parameters to Kronolith_Ajax_Application which runs doAction(); (How does doAction trigger the imple?)

++ $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?

  • Horde_Controllers

Horde Controllers seem to be somewhat independent from the stuff described above
Controllers need Horde_Routes and need rewrite rules

Ajax application controllers do not live in lib but in
$app/app/controllers/

Example:

class Nag_CompleteTask_Controller in nag/app/controllers/CompleteTask.php

getRequestVars(); if (isset($requestVars['task']) && isset($requestVars['tasklist'])) { $nag_task = new Nag_CompleteTask(); $result = $nag_task->result($requestVars['task'], $requestVars['tasklist']); } else { $result = array('error' => 'missing parameters'); } $requestVars = $request->getGetVars(); if (!empty($requestVars['format']) && $requestVars['format'] == 'json') { $response->setContentType('application/json'); $response->setBody(json_encode($result)); } elseif ($requestVars['url']) { $response->setRedirectUrl($requestVars['url']); } } } ?>

A Horde Controller based app needs a config/routes.php file.

For example

connect('/t/complete', array( 'controller' => 'CompleteTask', )); ?>

defines a route for a call like www.myhorde.de/nag/t/complete to be handled by the CompleteTask controller seen above.

The endpoint script is horde/rampage.php - rampage.php currently seems to handle only authenticated calls.

The controller is passed the request (in this case, a json request) and handles it (with a json answer in this case)

  • Client side js infrastructure

TODO

  • 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?