;;; -*- Mode: LISP; Syntax: COMMON-LISP; Base: 10 -*-
;;;
;;; Copyright (c) 2007, Ury Marshak
;;; The code comes with a BSD-style license, so you can basically do
;;; with it whatever you want. See the file LICENSE for details.
;;;
(in-package #:ht-ajax)
(declaim #.*optimization*)
;;
;;; This is loosely based on the CL-AJAX package by Richard Newman
;;; (http://www.cliki.net/cl-ajax, http://www.holygoat.co.uk/applications/cl-ajax/cl-ajax)
;;; but probably does not deserve the name "port of CL-AJAX for Hunchentoot",
;;; also in any case the code taken from CL-AJAX was heavily modified, so
;;; the bugs are probably mine
(defclass simple-ajax-processor (ajax-processor)
())
(defun prepare-js-simple-init-request ()
"
function init_request() {
// debug_alert(\"Initialising request...\");
var r;
if (window.XMLHttpRequest) { r = new XMLHttpRequest(); }
else {
try { r = new ActiveXObject(\"Msxml2.XMLHTTP\"); } catch (e) {
try { r = new ActiveXObject(\"Microsoft.XMLHTTP\"); } catch (ee) {
r = null;
}}}
if (!r) debug_alert(\"Browser couldn't make a connection object.\");
return r;
}
")
(defun prepare-js-simple-ajax-preamble (server-uri)
"Output a string containing the call function."
(format nil "
function ajax_call_uri(func, callback_spec, args) {
var uri = '~A';
var i;
var response = null;
var callbacks = ajax_parse_callbacks(callback_spec);
if (uri.indexOf('?') == -1)
uri = uri + '?';
else
uri = uri + '&';
uri = uri + ajax_encode_args(func, args);
var re = init_request();
re.open('GET', uri, true);
re.onreadystatechange = function() {
if (re.readyState != 4) return;
if (((re.status>=200) && (re.status<300)) || (re.status == 304)) {
var data = re.responseText;
ajax_call_maybe_evaluate_json(callbacks[0],
data,
re.getResponseHeader('Content-Type'));
}
else {
if(callbacks[1]) {
callbacks[1](re.status + ' ' + re.statusText);
}
else {
debug_alert('Error for URI '+uri + ' ' + re.status + ' ' + re.statusText);
}
}
}
re.send(null);
delete re;
}"
server-uri))
(defmethod prepare-js-ajax-function ((processor simple-ajax-processor) fun-name js-fun-name
&rest rest &key method &allow-other-keys)
(declare (ignore processor))
(unless (eq method :get)
(error "SIMPLE-AJAX-PROCESSOR does not support methods other than GET"))
(apply #'prepare-js-ajax-function-definitions "ajax_call_uri" fun-name js-fun-name rest))
;; (defun wrap-result-in-xml (result element-id)
;; (no-cache)
;; (format nil
;; "
;; ~A~A"
;; (if element-id
;; (concatenate 'string "" element-id "")
;; "")
;; result)
;; )
;; (defmethod handle-request ((processor simple-ajax-processor))
;; (let ((ajax-xml (string-to-js-boolean (parameter "ajax-xml")))
;; (ajax-elem (parameter "ajax-elem")))
;; (let ((result (call-next-method)))
;; (if ajax-xml
;; (progn
;; (setf (content-type) "text/xml")
;; (wrap-result-in-xml result ajax-elem))
;; result)
;; ))
;; )
(defmethod %generate-includes ((processor simple-ajax-processor))
"No includes for SIMPLE processor"
;;
"")
(defmethod %generate-js-code ((processor simple-ajax-processor))
(apply #'concatenate 'string
(prepare-js-debug-function processor)
(prepare-js-ajax-encode-args)
(prepare-js-parse-callbacks)
(prepare-js-ajax-is-json)
(prepare-js-ajax-call-maybe-evaluate-json)
(prepare-js-simple-ajax-preamble (maybe-rewrite-url-for-session
(server-uri processor)))
(prepare-js-simple-init-request)
(loop
for fun-name being the hash-keys
in (exported-funcs processor)
collect (apply #'prepare-js-ajax-function
processor
fun-name
(js-function-name processor fun-name)
(gethash fun-name (exported-funcs processor))))
))