SymbolicWeb
SymbolicWeb is a GUI, widget or server-centric framework for developing web applications. It is written in Common Lisp. SymbolicWeb is free software licensed under the AGPLv3 plus GPL linking exception.
It uses portable browser technologies such as HTML, CSS, JavaScript, AJAX and Comet, and wraps these in widgets. These widgets are instantiated and stored on the server end, then presented and updated in real-time on the client end as their state changes. While being widget based, SymbolicWeb does not hide or restrict access to low-level details such as HTML, CSS and JavaScript.
SymbolicWeb allows for two way real-time communication between server and client. Updates or changes can propagate from the server to the client at any time (Comet), while AJAX is used to send messages or events the other way around.
It does not use or depend on browser plug-ins such as Flash or Java Applets for rendering or transportation of data and messages. Hunchentoot is used to deal with HTTP on the server end, while jQuery is used on the client end to deal with AJAX, Comet and general browser differences.
SymbolicWeb was awarded a stipend by the Google Summer of Code program in 2008 via the LispNYC organization.
Features
- Support for browser back button and browser history. Widget state can be serialized to The Browser URL, then be serialized back the other way as the user presses the back and forward buttons in the browser.
- Ability to bookmark or link to the state of an application or a set of widgets.
- A single widget instance can be visible in multiple browsers, browser windows or tabs at the same time. Sharing a container widget between multiple users is an example of this. The container might function as a chat-pane or tab in a chat application, and as new child nodes or messages are added to this container they become visible for all users viewing this shared container widget.
- Works around the two connection limit of HTTP and web browsers by sending HTTP requests to a separate subdomain of the host created for each browser window or tab.
- Ability to manipulate HTML attributes, CSS properties and add both server and/or client side callbacks for DOM events. The set of attributes, properties and events which can be manipulated is expandable via the add-attribute-type, add-css-type and add-event-type functions.
- Ability to transmit custom JavaScript code from the server to the client at any time.
- Real-time interactive development (see the Example code section below).
Example code
This shows how to create and manipulate a simple widget directly from the Lisp REPL.
SW> (defparameter *our-widget* (mk-span "Hello World")) ;; CREATES the widget, stores it in a global variable
SW> (real-html-of *our-widget*) ;; returns the html which will be sent to the client
"<span id='html-element-168'>Hello World</span>"
SW> (html-of *our-widget*) ;; returns the html "content"
"Hello World"Adding the widget to the web page:
SW> (add-to (root) *our-widget*)(root) refers to the top-level node in the DOM tree of the web page. *our-widget* is added as a child to this node.
The programmer can manipulate the widget via the REPL. The widget is at this point visible on the client and will reflect any changes done to it in real time without the user having to refresh the web page:
SW> (setf (background-color-of *our-widget*) "red") ;; the CSS "background-color" property
SW> (setf (html-of *our-widget*)
(string-upcase (html-of *our-widget*)) ;; converts the string to upper-caseSpecifying an event and a callback:
SW> (setf (on-click-of *our-widget*)
(mk-cb (widget)
(write-line "Hello World span was clicked!")
(setf (background-color-of *our-widget*)
(random-elt '("red" "green" "blue")))))When the user clicks on the span at the client end, the server side callback will print a message to standard output and set the background-colour (CSS property) of the widget to a random colour. It is also possible to specify callbacks that are handled directly on the client side, without a round-trip to the server.
It is possible to send custom JavaScript code to the browser by using the run function:
SW> (run "alert('hi');")..and return values from the client (by specifying :json t here the type returned would be an integer instead of a string):
SW> (run "return 3 * 2;" :async-p nil)
"6"