Common Lisp Package: WUWEI

README:

WuWei -- an Ajaxy web toolkit for Common Lisp

WuWei is a toolkit for building Ajax web pages and web sites in Common Lisp. It's designed to be light-weight, a toolkit rather than a platform.

Wu wei is Chinese for "effortless doing".

Features

  • Continuation-based AJAX user interfaces
  • Server-side DOM operations (add/remove elements, visual fades, drag and drop)
  • High-level interfaces to in-place-editing and autocomplete widgets
  • Login and session management
  • OAuth2 client

Examples

May be run at the demo site: http://wuwei.name

Credits

WuWei was written primarily by Mike Travers, originally under the sponsorship of CollabRx, Inc. Some bits of it are derived from BioBike.

Requirements/dependencies:

  • A Common Lisp implementation. WuWei has been run in Allegro, Clozure (aka OpenMCL), and SBCL, and ought to run in other implementations.
  • mtlisp, a utility package.
  • Other libraries (aserve or portable aserve, cl-json, and their dependencies)
  • Uses the Prototype and Scriptaculous JavaScript libraries (included in the source).

Install

Easiest using QuickLisp:

  1. Install QuickLisp from http://www.quicklisp.org/
  2. Tell the install system where to find wuwei and mtlisp:
  3. (push #p"/misc/repos/wuwei/" asdf:central-registry) (push #p"/misc/repos/mtlisp/")

  4. (OpenMCL only) Unfortunately there are some incompatabilities with the distributed version of Portable AllegroServe and OpenMCL, so:
  1. Load everything:
  2. (ql:quickload "wuwei") (ql:quickload "wuwei-examples") ; if wanted

FUNCTION

Public

AUTO-COMPLETE-FIELD (&KEY (ID (STRING (GENSYM id))) NAME VALUE OPTIONS COMPLETIONS-URL COMPLETIONS-GENERATOR EMBEDDED-HTML ON-SELECTED TEXTAREA (UPDATE (STRING+ ID _auto_complete)) INPUT-OPTIONS (SCROLL? 30) SPINNER?)

Generate an HTML autocompletion field. Arguments below (all except completions-url are optional) ID - the HTML ID of the element NAME - the name of the field VALUE - the current value of the field TEXTAREA - T to use a multi-line textarea OPTIONS - additional options to pass to the scriptaculous Ajax.Autocompleter object. INPUT-OPTIONS - options to pass to the input or textarea tag (eg '(("tokens" . ("," #Newline)))) COMPLETIONS-GENERATOR - a procedure that takes a prefix and returns a list of (id . name) pairs EMBEDDED-HTML - T if strings can contain HTML markup COMPLETIONS-URL - a URL that supplies the completions. Either this or COMPLETIONS-GENERATOR must be supplied, but not both ON-SELECTED - a function that is called with the value, value string, and id of the selected option UPDATE - the HTML ID of the autocompletion box SCROLL? - If an integer, add scroll bar if more completions than this (default to 30) SPINNER? - T to show a spinner while fetching completions

REMOTE-FUNCTION (URL &KEY FORM PARAMS (IN-FUNCTION? T) CONFIRM BEFORE AFTER SPINNER SUCCESS FAILURE COMPLETE EVAL-SCRIPTS? STOP-PROPAGATION? UPDATER? PERIODIC?)

Generate a remote function (javascript Ajax call) ex: (remote-function "/new-chunk" :params `(:user ,user :type (:raw ,(format nil "$(~A).value" selector-id)))) returns: new Ajax.Request('/new-chunk', {"asynchronous":true,"parameters":{"user":"mt","type":$(selector23).value}}); return false; :form If t, serialize the surrounding form; if a string serialise the form with that name; else use params :params List of (:key1 value1 ...), ignored if :form is t :confirm Ask user for confirmation first (value is the message) :complete Javascript to execute when action completes :success as :complete, but on success only :failure as :complete, but on failure only :before Javascript to run before the Ajax request :after Javascript to run after the Ajax request :spinner The ID of an elt, a spinner will be inserted after the elt before the Ajax request and removed when completed :in-function? :eval-scripts? :stop-propagation? Stop propagation of events to parents. Forces :in-function? to be nil :updater? Make an Ajax.Updater object rather than an Ajax.Request; value is dom id of item to be updated :periodic? Make an Ajax.PeriodicalUpdater, updater? must be non-nil

SELECT-FIELD (&KEY ID NAME OPTIONS URL PARAMS SELECTED HTML-OPTIONS)

Generate an HTML select field. If URL is given, trigger off of the mouseup event OPTIONS is a list of (value name) pairs.

Undocumented

BUTTON-TO-FUNCTION (TEXT JS &KEY HTML-OPTIONS)

BUTTON-TO-REMOTE (TEXT URL &REST REMOTE-FUNCTION-OPTIONS &KEY HTML-OPTIONS &ALLOW-OTHER-KEYS)

CHECKBOX-TO-FUNCTION (TEXT JS &KEY HTML-OPTIONS)

CHECKBOX-TO-REMOTE (TEXT URL &OPTIONAL CHECKED? &REST REMOTE-FUNCTION-OPTIONS &KEY PARAMS (ID (STRING (GENSYM check))) CLASS HTML-OPTIONS &ALLOW-OTHER-KEYS)

CLEAN-JS-STRING (STRING)

CLEAR-ERROR

CSS-INCLUDE (FILE-OR-URL)

CSS-INCLUDES (&REST FILES)

DELETE-SESSION (&OPTIONAL (KEY *SESSION*) STORE-CLASS)

ELEMENT-NAMED (DOM-ID)

ERROR-BOX

FLASH-MESSAGE (MSG)

HTML-ESCAPE-STRING (STRING)

IMAGE-TAG (IMG &KEY ALT BORDER WIDTH HEIGHT TO-STRING?)

IMAGE-URL (IMG)

IN-PLACE-FIELD (&KEY (ID (STRING (GENSYM id))) NAME OPTIONS (PROMPT Click to edit.) ON-CHANGE VALUE CLASS SUBMIT-ON-BLUR? (EDITABLE? T))

JAVASCRIPT-INCLUDE (FILE-OR-URL)

JAVASCRIPT-INCLUDES (&REST FILES)

LOCATE-PUBLIC-DIRECTORY (&OPTIONAL DIRECTORY)

NEW-SESSION-HOOK (REQ ENT)

PARSE-UPLOAD-FORM (REQ &KEY (PATHNAME-MAKER #'(LAMBDA (NAME) (MAKE-PATHNAME DEFAULTS (PATHNAME /tmp/) NAME (STRING+ (STRING *SESSION*) _ NAME)))))

PUBLIC-URL (NAME)

RADIO-TO-REMOTE (TEXT URL &OPTIONAL CHECKED? &REST REMOTE-FUNCTION-OPTIONS &KEY HTML-OPTIONS &ALLOW-OTHER-KEYS)

RENDER-ERROR (MSG &KEY STACK-TRACE USER-ERROR?)

SYSTEM-NAME

UPLOADER (ID URL &OPTIONAL ISDRUGRANK)

Private

Undocumented

ACCESS-PROTECTED-RESOURCE (URL &REST IGNORE)

ACCESS-PROTECTED-RESOURCE-WITH-ERROR (URL &REST OTHER-ARGS)

AJAX-TIMEOUT (REQ ENT)

ALL-SESSION-VARIABLE-SYMBOLS

ALL-SESSION-VARIABLE-VALUES (SESSION)

ALL-SESSION-VARIABLES

BREAK-LINES (STRING)

CAMEL-CASE (STRING)

CLEAN-UPLOAD-JS-STRING (STRING)

COERCE-DRAKMA-TO-STRING (SS)

COERCE-URL (FILE-OR-URL)

COMPOSE-ERROR-MESSAGE (PATH &KEY ERROR STACK-TRACE EXTRA-JS)

CREATE-BLOCK-FOR-ERROR (&KEY ERROR STACK-TRACE)

DO-RESPONDER-TIMEOUTS

DUMP-STACK (&OPTIONAL (STREAM *STANDARD-OUTPUT*))

ESCAPE-SINGLE-QUOTES (STRING)

EVAL-PAGE (REQ ENT)

EVAL-SERVER (REQ ENT)

FIND-OR-MAKE-SESSION-STORE (CLASS)

GEN-DOM-ID

GENSYM-SESSION-ID

GET-ACCESS-TOKEN (CODE)

GET-AUTH-CODE-URI

GET-FRAMES-LIST

GET-URL (URL &REST KEYS)

GET-URL-WITH-BACKOFF (URL &REST KEYS)

GOTO-URL-FUNCTION (URL)

HMAC-SHA1-STRING (STRING &OPTIONAL (SECRET *SESSION-SECRET*) (RETURN HEX))

HTML-REPORT-ERROR (&KEY ERROR STACK-TRACE)

JSON-OPTIONS (OPTIONS)

JSON-OPTIONS-TRANSFORM (OPTIONS)

JSON-REPORT-ERROR (&KEY ERROR STACK-TRACE)

LABELIFY (STRING)

LOG-MESSAGE (MESSAGE)

LOGOUT (REQ ENT)

PUBLISH-TEMPORARILY (PATH &REST ARGS)

RENDER-SCRIPT-LATER (SCRIPT)

RENDER-UPDATE-SCRIPTS

REPORT-BUG-BUTTON (&OPTIONAL (INFO ))

RESET-SESSION-STORES

SAVE-SESSION-VARIABLES (&OPTIONAL (SESSION *SESSION*))

SESSION-DEBUG-PAGE (REQ ENT)

SET-EQUAL (L1 L2 &KEY (TEST #'EQ))

SET-RESPONDER-TIMEOUT (PATH &OPTIONAL (TIME (+ (NOW) *DEFAULT-RESPONDER-TIMEOUT*)))

SIGNED-VALUE (V &OPTIONAL (SECRET *SESSION-SECRET*))

SLURP-PART (REQ &KEY STREAM (ELEMENT-TYPE '(UNSIGNED-BYTE 8)))

SMART-STRING (K)

STACK-TRACE

STRING-SIGNATURE (STRING &OPTIONAL (SECRET *SESSION-SECRET*))

STRING-UPCASE? (S)

SYSTEM-INFO

UNPUBLISH-PATH (PATH)

VERIFY-SIGNED-VALUE (RV &OPTIONAL (SECRET *SESSION-SECRET*))

WGET-URL (URL &KEY QUERY)

MACRO

Public

WITH-HTTP-RESPONSE-AND-BODY ((REQ ENT &REST KEYS) &BODY BODY)

Combines WITH-HTTP-RESPONSE and WITH-HTTP-BODY

Undocumented

AJAX-CONTINUATION ((&KEY ARGS KEEP (CONTENT-TYPE text/javascript) (SESSION NIL SESSION-SPEC?) NAME LOGIN-HANDLER TIMEOUT) &BODY BODY)

ASYNC ((&KEY (PRE-TEXT waiting...) SPINNER) &BODY BODY)

BR

DEF-SESSION-VARIABLE (NAME &OPTIONAL INITFORM &KEY (STORE-TYPE MEMORY) READER WRITER)

HTML-LIST (VAR)

HTML-PRINC (TEXT)

HTML-STRING (&BODY STUFF)

HTML-TO-STREAM (STREAM &BODY STUFF)

IN-PLACE-SETF-FIELD (OBJECT ACCESSOR &REST ALL-KEYS &KEY ON-CHANGE &ALLOW-OTHER-KEYS)

NBSP

PUBLISH-AJAX-FUNC (PATH-OR-OPTIONS ARGS &REST BODY)

PUBLISH-AJAX-UPDATE (PATH-OR-OPTIONS &BODY BODY)

RADIO-BUTTONS (NAME OPTIONS &KEY SEPARATOR)

RENDER-SCRIPTS (&BODY CLAUSES)

RENDER-UPDATE (&BODY CLAUSES)

WITH-AJAX-ERROR-HANDLER ((NAME &KEY EXTRA-JS) &BODY BODY)

WITH-HTML-ERROR-HANDLING (&BODY BODY)

WITH-HTML-SAFE-ERROR-HANDLING (&BODY BODY)

WITH-JSON-ERROR-HANDLING (&BODY BODY)

WITH-SESSION ((REQ ENT &KEY) &BODY BODY)

WITH-SESSION-RESPONSE ((REQ ENT &KEY CONTENT-TYPE NO-SAVE?) &BODY BODY)

WU-CONTINUATION (OPTIONS &BODY BODY)

WU-CONVERSATION (FIRST &BODY REST)

WU-PUBLISH (URL &BODY BODY)

Private

Undocumented

DEFINE-RENDER-ELEMENT-OPERATION (KEYWORD &OPTIONAL (FUNC (STRING-DOWNCASE (STRING KEYWORD))))

DEFINE-RENDER-UPDATE (TYPE ARGS &BODY BODY)

LOGGING-ERRORS (&BODY BODY)

MAYBE-TO-STRING (TO-STRING? &BODY BODY)

MULTIPART? (REQ)

NL

P

RENDER-DEBUG (MSG)

WITH-RENDER-UPDATE (&BODY BODY)

WITH-SESSION-VARIABLES (&BODY BODY)

WITHOUT-UNWINDING-RESTART ((RESTART &REST ARGS) &BODY BODY)

WU-CONVERSATION-1 (FIRST &BODY REST)

GENERIC-FUNCTION

Public

ELEMENT-RENDER (DOM-OBJECT)

This method should do the actual HTML rendering of the object

Undocumented

DISPLAY-BASE (OBJECT)

DISPLAY-LIST (PAGED-ELEMENT)

ELEMENT-UPDATE (E)

RENDER-PAGING-CONTROLS (OBJECT)

TOTAL-SIZE (PAGED-ELEMENT)

Private

Undocumented

ADD-SESSION-VARIABLE (TYPE VAR)

GET-SESSION-ID (STORE REQ)

READ-SESSION-VARIABLE-VALUE (SSV STREAM)

RECOMPUTE-SECRET (STORE)

RESET-SESSION-STORE (STORE)

SESSION-DELETE-SESSION (STORE SESSION)

SESSION-SAVE-SESSION-VARIABLES (STORE SESSION)

SESSION-VALUES (STORE SESSION)

SESSION-VARIABLE-SYMBOLS (STORE)

SESSION-VARIABLE-VALUE (SSV)

TOTAL-PAGES (OBJECT)

WRITE-SESSION-VARIABLE-VALUE (SSV STREAM)

SLOT-ACCESSOR

Public

Undocumented

CURRENT-PAGE (OBJECT)

SETFCURRENT-PAGE (NEW-VALUE OBJECT)

HTML-ELEMENT-DOM-ID (OBJECT)

Private

Undocumented

HTML-ELEMENT-PARENT (OBJECT)

SESSION-VARIABLE-INITFORM (OBJECT)

SESSION-VARIABLE-SYMBOL (OBJECT)

SESSION-VARIABLES (OBJECT)

VARIABLE

Public

Undocumented

*AJAX-REQUEST*

*ASERVE-REQUEST*

*DEVELOPER-MODE*

*FILE-FIELD-NAME*

*PUBLIC-DIRECTORY*

*SYSTEM-NAME*

*WITHIN-RENDER-UPDATE*

Private

Undocumented

*ACCESS-TOKEN*

*AJAX-COUNTER*

*AJAX-ERROR-BOX?*

*BUFFER-SIZE*

*BUG-REPORT-URL*

*DEFAULT-RESPONDER-TIMEOUT*

*DOM-HT*

*DOM-ID-COUNTER*

*FLASH-MESSAGES*

*LOGGING*

*LOGGING-STREAM*

*OAUTH-AUTH-ENDPOINT*

*OAUTH-TOKEN-ENDPOINT*

*OAUTH2-CALLBACK*

*OAUTH2-CLIENT-ID*

*OAUTH2-CLIENT-SECRET*

*OAUTH2-SCOPES*

*REFRESH-TOKEN*

*RENDER-DEBUGGING*

*RENDER-UPDATE-SCRIPTS*

*RESPONDER-TIMEOUTS*

*SESSION*

*SESSION-SECRET*

*SESSION-STORES*

*STACK-FRAME-LIMIT*

*UPLOADER-HTML*

CLASS

Public

Undocumented

FLASH-BOX

HTML-ELEMENT

PAGING-MIXIN

Private

Undocumented

IN-MEMORY-SESSION-STORE

LIST-PAGING-MIXIN

SERIALIZED-SESSION-STORE

SESSION-STORE

SESSION-VARIABLE