HT-SIMPLE-AJAX is an Ajax library for the HUNCHENTOOT web server. It allows to call ordinary Lisp functions from within an html page using javascript and asynchronous client/server communication.
It is a heavily simplified (150 lines of code) version of HT-AJAX that is compatible with newer versions (>1.1) of HUNCHENTOOT. It was initially developed for GTFL and therefore provides only one type of Ajax processor (which resembles the 'simple' processor of HT-AJAX).
HT-SIMPLE-AJAX comes with a BSD-style license so you can basically do with it whatever you want.
Download shortcut: http://martin-loetzsch.de/ht-simple-ajax/ht-simple-ajax.tar.gz.
HT-SIMPLE-AJAX together with an example and this documentation can be downloaded from http://martin-loetzsch.de/ht-simple-ajax/ht-simple-ajax.tar.gz. The current version is 0.5.
HT-SIMPLE-AJAX depends on the HUNCHENTOOT (version >= 1.2.x) web server, which itself requires quite a number of other libraries.
If you don't want to download all these libraries manually, you can use Quicklisp or ASDF-INSTALL:
(ql:quickload "ht-simple-ajax")
(asdf-install:install 'ht-simple-ajax)
Once everything is installed, HT-SIMPLE-AJAX is compiled and loaded with:
(asdf:operate 'asdf:load-op :ht-simple-ajax)
This is a brief walk-through of ht-simple-ajax. You can try out the whole example in demo.lisp (also contained in the release).
First we create an ajax processor that will handle our function calls:
(defparameter *ajax-processor* (make-instance 'ajax-processor :server-uri "/ajax"))
Now we can define a function that we want to call from a web page. This function will take 'name' as an argument and return a string with a greeting:
(defun-ajax say-hi (name) (*ajax-processor*) (concatenate 'string "Hi " name ", nice to meet you."))
We can call this function from Lisp, for example if we want to test it:
HT-SIMPLE-AJAX> (say-hi "Martin") "Hi Martin, nice to meet you."
Next, we setup and start a hunchentoot web server:
(defparameter *my-server* (start (make-instance 'easy-acceptor :address "localhost" :port 8000)))
We add our ajax processor to the hunchentoot dispatch table:
(setq *dispatch-table* (list 'dispatch-easy-handlers (create-ajax-dispatcher *ajax-processor*)))
Now we can already call the function from a http client:
$ curl localhost:8000/ajax/SAY-HI?name=Martin <?xml version="1.0"?> <response xmlns='http://www.w3.org/1999/xhtml'>Hi Martin, nice to meet you.</response>
Alternatively, you can also paste the url above in a web browser
To conveniently call our function from within javascript, the ajax processor can create a html script element with generated javascript functions for each Lisp function:
HT-SIMPLE-AJAX> (generate-prologue *ajax-processor*) "<script type='text/javascript'> //<![CDATA[ function ajax_call(func, callback, args) { // .. some helper code } function ajax_say_hi (name, callback) { ajax_call('SAY-HI', callback, [name]); } //]]> </script>"
So for our example, the javascript function ajax_say_hi was generated. name is the parameter of the Lisp function (if there are multiple parameters, then they will also appear here) and callback is a function that will be asynchronously called when the response comes back from the web server. That function takes 1 argument, which is the xml DOM object of the response.
Finally, we can put everything together and create a page that calls our function. For rendering html, we will use cl-who in this example (note that ht-simple-ajax can be used with any other template/ rendering system):
(define-easy-handler (main-page :uri "/") () (with-html-output-to-string (*standard-output* nil :prologue t) (:html :xmlns "http://www.w3.org/1999/xhtml" (:head (:title "ht-simple-ajax demo") (princ (generate-prologue *ajax-processor*)) (:script :type "text/javascript" " // will show the greeting in a message box function callback(response) { alert(response.firstChild.firstChild.nodeValue); } // calls our Lisp function with the value of the text field function sayHi() { ajax_say_hi(document.getElementById('name').value, callback); } ")) (:body (:p "Please enter your name: " (:input :id "name" :type "text")) (:p (:a :href "javascript:sayHi()" "Say Hi!"))))))
Direct your web browser to http://localhost:8000 and try it out!
You can also directly look at ht-simple-ajax.lisp, it's fairly simple.
[Standard class]
ajax-processor
Maintains a list of lisp function that can be called from a client page.
:server-uri defines the absolute url for handling http ajax requests (default "/ajax").
:content-type defines the http content type header for XML responses (default "text/xml; charset=\"utf-8\"").
:reply-external-format determines the format for the character output stream (default hunchentoot::+utf-8+).
[Function]
create-ajax-dispatcher processor => dispatcher function
Creates a hunchentoot dispatcher function that handles incoming ajax requests. processor is an instance of ajax-processor.
[Macro]
defun-ajax name params (processor) &body body => no values
Declares a defun that can be called from a client page. processor is an instance of ajax-processor.
See example above.
[Function]
generate-prologue processor => string
Creates a <script> ... </script> html element that contains all the client-side javascript code for the ajax communication. Include this script in the <head> </head> element of each html page. processor is an instance of ajax-processor.
All credits should go to the original author of HT-AJAX, who unfortunately doesn't maintain that library anymore.
The layout and structure of this page is heavily inspired by (or directly copied from) DOCUMENTATION-TEMPLATE.
Last change: 2013/04/17 23:17:00 by Martin Loetzsch