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.

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

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.

11 Responses to “ParenScript vs script.aculo.us”

  1. Aankhen says:

    Can’t say I’m a big fan of Prototype or script.aculo.us myself, but
    interesting entry nonetheless as a practical demonstration of
    integrating ParenScript. I have a few comments.

    It would be nice if you could set up your blog software to not convert
    quotes within code into smart quotes. The conversion makes a
    copy/paste job impossible without a heck of a lot of tweaking.

    What is the “stupid firefox” text in both `script’ elements supposed
    to be? Judging by its position, I’d guess it’s placed as a child; why
    is it in there? Text children of `script’ elements are never
    displayed, only executed.

    You don’t need both `language’ and `type’ attributes on your `script’
    elements. `type=”text/javascript”‘ is all that is required.

    Why does your `js-script’ macro start the script block with “// ” on a
    line of its own? There’s nothing wrong with it, it’s just
    unnecessary.

    The CDATA isn’t “swallowed up by the web”. It’s present in the page
    (see the source), but since it apparently wasn’t escaped it for
    presentation in HTML, it was instead intepreted as a part thereof.

    BTW, I noticed that your page uses a DOCTYPE of XHTML 1.0 Strict. You
    might want to change that to something more lax, such as HTML 4.01
    Loose, since your blog isn’t quite in line with what XHTML 1.0 Strict
    requires
    .

  2. rudi says:

    Hi, thanks for the comments!

    cl-who renders tags without content as a single , not as a pair of begin/end tags. I found out through experimentation that firefox barfed in that case and would render an empty page. I considered reading up on / tweaking the DOCTYPE declaration since it might be within its rights to do so, but went for the quick hack instead.

    the “type=” came from the scriptaculous demos, the “language=” from the parenscript documentation. You may now conclude that I’m not a very advanced web coding monkey.

    The js-script macro was adapted from the parenscript docs (see relevant comment above about my web-fu).

    Glad to be of service.

  3. Aankhen says:

    “cl-who renders tags without content as a single , not as a pair of begin/end tags. I found out through experimentation that firefox barfed in that case and would render an empty page.”

    Ah yes, you have a point there. Strange to say, though, I had the opposite experience when I once tried an empty `script’ element: IE barfed while Firefox handled it alright.

    “I considered reading up on / tweaking the DOCTYPE declaration since it might be within its rights to do so, but went for the quick hack instead.”

    It’s not the DOCTYPE in this case. Browsers treat all HTML as tag soup (unless it’s sent as `application/xhtml+xml’); when you say , their safest bet is to assume that you actually meant (i.e. just the opening tag).

    “the “type=” came from the scriptaculous demos, the “language=” from the parenscript documentation. You may now conclude that I’m not a very advanced web coding monkey.”

    Heh, fair enough.

    “The js-script macro was adapted from the parenscript docs (see relevant comment above about my web-fu).”

    I would yell at you for cargo-culting if I weren’t guilty myself of doing the same thing on a regular basis. :-P

    Thanks for fixing the quotes and the escaping, it’s much more usable now!

  4. Victor says:

    Hmm… quite interesting. I think, I shall try to use Parenscript and Yahoo UI toolkit together to see if the match as neatly as script.aculo.us in the example.

    Thanks for a nice tip!

  5. Arghh, sorry for the documentation! I’ve just moved to California last week and with all the running around trying to find an apartment and getting everything figured out I haven’t had time to touch Parenscript at all. One of the things I promised a few months ago was to rewrite the tutorial file to use Hunchentoot and cl-who, and post it as a wiki page, ostensibly so people can easily contribute great examples like the above, but really because I am too lazy to maintain that much documentation. I’ll put that on the list of things to do before 2007 is out.

  6. rudi says:

    No no, the documentation is very nice, and well-structured! If you wikify it, please consider keeping the official docs as well. In fact, I volunteer to convert the manual to hunchentoot / cl-who.

  7. Edi Weitz says:

    Regarding the single tags, see here:

    http://weitz.de/cl-who/#*html-empty-tags*

  8. Raoul Duke says:

    many thanks for this blog entry; i’m new to all things lisp (well, new in that is has been like 20 years since i last used it for my day job) and posts like this are a great help in getting my bearings. i want to learn enough to be able to cobble together weekend AJAXy hacks.

  9. Ron Lusk says:

    Thanks for your original posting. I borrowed the code and managed to set up a timed slideshow with it, with new list items being inserted into the head of a list and the oldest photo fading from the end of the list. This was a great help, thank you.

  10. rudi says:

    My pleasure, Ron! Glad I could help.

  11. Hello, I came across this article while searching for help with JavaScript. I have recently switched browsers from Chrome to Microsoft IE 6. Now I seem to have a issue with loading JavaScript. Everytime I browse website that needs Javascript, my browser doesn’t load and I get a “runtime error javascript.JSException: Unknown name”. I can’t seem to find out how to fix it. Any aid is greatly appreciated! Thanks

Leave a Reply