[commits] [Wiki] created: Doc/Dev/HordeAjaxApplications

Wiki Guest wikiguest at horde.org
Tue Jul 23 15:59:41 UTC 2013


guest [158.181.84.94]  Tue, 23 Jul 2013 15:59:41 +0000

Created page: http://wiki.horde.org/Doc/Dev/HordeAjaxApplications

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

== Convention ==
Conventions:
$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:

<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 */
);
</code>

== 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
<code>
<?php
// phpdoc omitted
class $App_Ajax_Application extends Horde_Core_Ajax_Application {}
</code>

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
<code>
var $AppCore = {
/* What is strictly required here? */
}
document.observe('dom:loaded', $AppCore.onDomLoad.bind(AppCore));
// more observers as needed
</code>

=== 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
<code>
**
  * 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 at horde.org>
  * @package Horde
  */
</code>


== 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
<code>
<?php
// phpdoc here
class $App_Ajax_Imple_$Foo extends Horde_Core_Ajax_Imple {
// or
class $App_Ajax_Imple_$Foo extends Horde_Core_Ajax_Imple_$Bar {
</code>

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:

<div id="kronolithCal"></div><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
<code>
<?php
class Nag_CompleteTask_Controller extends Horde_Controller_Base
{
     public function processRequest(Horde_Controller_Request $request,  
Horde_Controller_Response $response)
     {
         /* Toggle the task's completion status if we're provided with a
          * valid task ID. */
         $requestVars = $request->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']);
         }
     }
}
</code>

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

For example
<code>
<?php
/**
  * Setup default routes
  */
$mapper->connect('/t/complete',
     array(
         'controller' => 'CompleteTask',
     ));

</code>

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?




More information about the commits mailing list