ParenScript vs script.aculo.us
Currently, my job does not involve a whole lot of programming, and I'm getting a bit rusty and irritated. So, last weekend I decided to noodle around aimlessly with some systems I meant to try out for a while now.
Parenscript advertises itself as being easy to integrate with javascript libraries such as Prototype, but the manual gives no examples on how to do this. Furthermore, the Parenscript manual uses aserve / htmlgen for its examples, while much of the action these days is with hunchentoot. So, without further ado, a pointless example integrating hunchentoot, cl-who, parenscript and script.aculo.us. Load the code after loading hunchentoot, cl-who and parenscript into your running Lisp.
All in all quite painless. The only point where I had to sit and think a bit was the translation of the prototype-style DOM accessors to parenscript notation.
Edit: Oh, and the js-script code above is missing the CDATA bits which were eaten by the web. Check page 6 of the parenscript documentation for the missing pieces.
Edit2: Thanks to Aankhen for pointing out that the CDATA wasn't et after all, just hiding. I'll go wrestle with this blog now to fix the stupid smartquotes.
;;; Just the standard intro
(defpackage :js-hax
(:use :common-lisp :hunchentoot :cl-who :parenscript))
(in-package :js-hax)
(start-server :port 8080)
;;; Set the path to where you unpacked script.aculo.us
;;; create-folder-dispatcher-and-handler publishes subdirectories:
;;; http://.../js/lib/prototype.js
;;; http://.../js/src/scriptaculous.js
(push (create-folder-dispatcher-and-handler
"/js/" #p"/home/someone/source/scriptaculous-js-1.8.0/")
*dispatch-table*)
(defmacro js-script (&rest body)
"Utility macro for including ParenScript into the HTML
notation of cl-who"
`(with-html-output (*standard-output*)
(:script :type "text/javascript"
(format t "~%// <!--[CDATA[~%~A~%//]]-->~%" (ps ,@body)))))
;;; Slider example, taken from the scriptaculous wiki
(defun foo ()
(with-html-output-to-string (*standard-output* nil :prologue t)
(:html
(:head (:title "script.aculo.us Tests")
(:script :language "JavaScript" :type "text/javascript"
:src "/js/lib/prototype.js" "stupid firefox")
(:script :language "JavaScript" :type "text/javascript"
:src "/js/src/scriptaculous.js" "stupid firefox"))
(:body
(:h1 "script.aculo.us vs. ParenScript")
(:p "The humble slider.")
(:p
(:div :id "track1"
:style "width:200px;background-color:#aaa;height:5px;"
(:div
:id "handle1"
:style "width:5px;height:10px;background-color:#f00;cursor:move;"))
(:div :id "debug1" :style "padding-top: 5px;"))
(js-script
;; Create the Slider object
(new (*control.*slider
;; Hook it up to the UI elements ...
"handle1" "track1"
;; ... and assign behavior
(create on-slide (lambda (v)
;; Prototype-style DOM accessors:
;; $('debug1').innerHTML = ...
(setf (slot-value ($ "debug1")
'inner-h-t-m-l)
(+ "slide: " v)))
on-change (lambda (v)
(setf (slot-value ($ "debug1")
'inner-h-t-m-l)
(+ "changed! " v)))))))))))
(push (create-prefix-dispatcher "/foo" 'foo) *dispatch-table*)