The web framework
*****************

CLAW-HTML is one of the most advanced web application framework available, completely object oriented (see CLOS (http://en.wikipedia.org/wiki/Common_Lisp_Object_System)), it is based on the concept of pages and components.

Pages are containers for components that provide the request-response business logic. They prevent html elements from duplicating their id, that is very important in component based applications, they are able to handle form requests, and to render components themselves of course.

Components are highly reusable building blocks that make easy and fast the creation of a web application. By using and creating new components, you, the developer, can create robust and consistent web application with the minimal effort. Each component may inject into a page its own set of stylesheet and javascript files, and may come with its own class or instance javascript.

CLAW-HTML getting started
=========================

With CLAW-HTML we'll begin to structure our samples in a more conformed way using the asdf definition system.

If you don't have any idea of what asdf is, please read about it at the asdf Manual (http://constantly.at/lisp/asdf/).

Create a directory named clhtml-sample1 and begin writing the clhtml-sample1.asd file and create a symbolic link in the asdf system directory.

     ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
     ;;; $Header: clhtml-sample1.asd $

     (asdf:defsystem :clhtml-sample1
       :name "clhtml-sample1"
       :description "clhtml-sample1: CLAW-HTML sample application"
       :depends-on (:claw-as :claw-hunchentoot-connector :claw-html)
       :components ((:module src
                             :components ((:file "packages")
                                          (:file "main" :depends-on ("packages"))
                                          (:file "components" :depends-on ("packages"))
                                          (:file "index" :depends-on ("main"))))))

Now create the clhtml-sample1/src directory and the following empty files

  * clhtml-sample1/src/packages.lisp

  * clhtml-sample1/src/main.lisp

  * clhtml-sample1/src/components.lisp

  * clhtml-sample1/src/index.lisp

Finally create the clhtml-sample1/src/docroot directory that will hold the static resources of the demo lisplet.

Define now the package, writing into clhtml-sample1/src/packages.lisp the code below.

     ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
     ;;; $Header: src/package.lisp $

     (in-package :cl-user)

     (defpackage :clhtml-sample1
       (:use :cl :claw-as :claw-hunchentoot-connector :claw-html)
       (:documentation "clhtml-sample1: CLAW-HTML sample application")
       (:export #:clhtml-sample1-start
                #:clhtml-sample1-stop))

The package exports the symbol functions CLHTML-SAMPLE1-START and CLHTML-SAMPLE1-STOP, used to start and stop the application server. This two functions will be defined into the main.lisp file.

Now it's time to write the code do launch the application server and register the lisplet. Fill the main.lisp file with the following code

     ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
     ;;; $Header: src/main.lisp $

     (in-package :clhtml-sample1)

     (defvar *main-file* (load-time-value
                          (or #.*compile-file-pathname* *load-pathname*)))

     (defvar *fs-realm* "frameworksample")

     (defvar *fs-lisplet* (make-instance 'lisplet :realm *fs-realm*
                                         :base-path "/frameworksample"))

     (defvar *ht-connector* (make-instance 'hunchentoot-connector
                                           :address "localhost"
                                           :port 4242
                                           :sslport nil))

     (defvar *sm* (make-instance 'default-session-manager))

     (defvar *ht-log-manager* (make-instance 'hunchentoot-logger))

     (defvar *the-server* (make-instance 'claw-server
                                         :connector *ht-connector*
                                         :log-manager *ht-log-manager*
                                         :session-manager *sm*
                                         :base-path "/claw"))

     (claw-server-register-lisplet *the-server* *fs-lisplet*)

     (defclass demo-configuration (configuration)
       ((users :reader users
               :initform '(("admin" "pwdadmin" ("admin-role" "user-role"))
                           ("user1" "pwduser" ("user-role"))))))

     (defmethod configuration-login ((configuration demo-configuration))
       (multiple-value-bind (user password)
             (if (eq (lisplet-authentication-type *claw-current-lisplet*) :basic)
                 (claw-authorization)
                 (values (claw-parameter "username")
                         (claw-parameter "password")))
           (let ((maybe-principal (assoc user)))
             (when (and maybe-principal (string= password (second maybe-principal)))
               (make-instance 'principal
                              :name user
                              :roles (third maybe-principal))))))

     (claw-server-register-configuration
       *the-server* *fs-realm* (make-instance 'demo-configuration))

     ;;registering lisplet static resources
     (let ((path (make-pathname :directory
                                (append (pathname-directory *main-file*) '("docroot")))))
       (lisplet-register-resource-location *fs-lisplet*
                                           path
                                           "docroot/"))

     (defun clhtml-sample1-start ()
       (claw-server-start *the-server*))

     (defun clhtml-sample1-stop ()
       (claw-server-stop *the-server*))

Your first claw-html page
=========================

It's time to create your first page using claw-html this is done by creating a PAGE subclass, override its page-content method and finally registering it using the make-page-renderer function.

In this very basic example we will not use any of the component feature of the framework, just basic tag functions.

     ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
     ;;; $Header: src/index.lisp $

     (in-package :clhtml-sample1)

     (defclass index-page (page)
       ())

     (defmethod page-content ((o index-page))
       (html>
        (head>
         (title> "Home test page")
         (link> :rel "stylesheet" :href "docroot/screen.css" :type "text/css"))
        (body>
         :id "theBody"
         :class "sampleBody"
         (div> :class "topHeader" "top header")
         (div> :class "mainContent"
               (h1> "Hello world")))))

     (lisplet-register-function-location *fs-lisplet*
                                         (make-page-renderer 'index-page
                                                             #'claw-post-parameters
                                                             #'claw-get-parameters)
                                         "index.html"
                                         :welcome-page-p t)

Now create a very simple screen.css since the index page needs one.

     /* $Header: src/docroot/screen.css */

     .sampleBody {
       width: 800px;
       margin: 10px auto 0 auto;
       background: #8B8DB9;
     }

     .sampleBody .topHeader {
       min-height: 100px;
       background: #D1D2E6;
       padding: 10px;
       border: 1px solid gray;
       -moz-border-radius: 10px; /* only for firefox */
     }

     .sampleBody .mainContent {
       min-height: 500px;
       background: white;
       padding: 10px;
       margin-top: 15px;
       border: 1px solid gray;
       -moz-border-radius: 10px; /* only for firefox */
     }

If you have done all properly in your Slime REPL, after the following commands:

     CL-USER> (asdf:oos 'asdf:load-op :clhtml-sample1)
     ....
     CL-USER> (clhtml-sample1:clhtml-sample1-start)
     NIL
     CL-USER>

You should be able to see the following page:

Creating your first component
-----------------------------

Writing a page the way described before has been straightforward, but it doesn't show any of the framework potentialities. Effectively this is nothing more than what other framework offers.

So let's do what is usually done by component-based frameworks: create the first component. This will be the site template component, surely you don't want to write every page to be different from each other, so you'll create the site template.

This component will provide a tag function similar to any other standard like html>, body>, div> and so on.

The first thing you'll have to do is to create a class that subclasses WCOMPONENT (the name stands for web component) and with metaclass METACOMPONENT. Giving such metaclass to your component definition makes the framework to automatically create a tag function for this component whose name will be the component name plus a > at the end.

A tag function is a function that may be placed inside a page, or another component, to render the referring component.

     (defclass site-template (wcomponent)
       ((title :initarg :title
               :reader site-template-title))
       (:metaclass metacomponent))

Since you haven't provided any DEFAULT-INITARGS, if you forgot to provide the title attribute to your tag function, the page won't render, and an error message will be logged.

Obviously the class does very little by itself without a proper template, so you'll define one for it now.

     (defmethod wcomponent-template ((obj site-template))
       (let ((title-value (site-template-title obj)))
          (html>
           (head>
            (title> title-value))
           (body> :static-id (htcomponent-client-id obj)
                  (wcomponent-informal-parameters obj)
                  (htcomponent-body obj)))))

Here there are three points to highlight. Firstly the HTCOMPONENT-BODY, here we are informing that the component will render its child at this position. Then the WCOMPONENT-INFORMAL-PARAMETERS is a method that informs the component to render tag parameters not directly specified into the class specification, making it possible to specify any tag parameter to the tag function.

CALW-HTML can control the id of each component so that when a component is put into a page, its id is not duplicated. You can avoid this checking using the STATIC-ID attribute, so when writing a component you can use the id given to your component through HTCOMPONENT-CLIENT-ID method an render it into the component template (or other component methods of course). This is a great point of strength for claw-html compared to other frameworks, , such as using the component in a loop without needing to worry about id duplication, a situation that might occur for example when creating table cells.

The last thing to note is the absence of the link to the css file. This was made because each component can inject into the page its own css or js files or definitions.

To add a css or a js file at class definition level you have to implement HTCOMPONENT-SCRIPT-FILES and HTCOMPONENT-STYLESHEET-FILES while to add javascript or css directives into the page you have to use HTCOMPONENT-GLOBAL-INITSCRIPTS, HTCOMPONENT-INITSCRIPTS and HTCOMPONENT-INITSTYLES

In our case it's simply sufficient to override the HTCOMPONENT-STYLESHEET-FILES method as described

     (defmethod htcomponent-stylesheet-files ((obj site-template))
       (list "docroot/screen.css"))

So now that the site template component is ready for our simple example you can now use it with your previous page; do change the page-content method definition in the src/index.lisp file:

     (defmethod page-content ((o index-page))
       (site-template>
         :id "theBody"
         :class "sampleBody"
         :title "Home test page"
         (div> :class "topHeader" "top header")
         (div> :class "mainContent"
               (h1> "Hello world"))))

That will produce the same result of the 'long form' PAGE-CONTENT implementation!

So, you may have now no repetitions of the html tag elements between application pages, a shorter PAGE-CONTENT implementation, and no problems about forgetting to import common stylesheet files (and .js files if you need one).

For curiosity here is the html source output:

Component scripts injection
---------------------------

You have just seen how components can inject css files into your page, as already said for javascript files, this is accomplished by overriding the component method HTCOMPONENT-SCRIPT-FILES, nothing more.

Some words must be spent to describe what happens if you want to inject css directives and javascript commands into the page inside <style> and <scripts> tags.

When you want to inject css directives into a <style> tag you have to override HTCOMPONENT-INITSTYLES method. This method returns a list of strings (containing css directives). The framework removes duplicated strings and subsequently renders inside the <head> tag the <style> tag. The removal of duplicates gives you the possibility of using your component inside loops without being worried about duplicating injection

When you want to inject javascript commands (and functions too) the story is a slightly different. Firstly commands are injected into a <script> tag that is positioned as the last <body> tag.

Then there are two different methods: HTCOMPONENT-GLOBAL-INITSCRIPTS and HTCOMPONENT-INITSCRIPTS.

HTCOMPONENT-GLOBAL-INITSCRIPTS is used to render scripts that are not tied to a particular instance, but come with the component, it's usually used to render javascript functions and global variables.

HTCOMPONENT-INITSCRIPTS renders scripts that are executed on <body> onload event, so no function definitions should be put inside.

For example, suppose that you want to create a component that displays current client time and refreshes it every second; you'll create a global js variable that will sore the component DOM node. You won't initialize it into the global section because you must be sure that the DOM tree is ready, so you'll inject it the with initialization method HTCOMPONENT-INITSCRIPTS.

An example will be better explain the concept, so modify the components.lisp file adding the following code:

     (defclass show-time (wcomponent)
       ((css-class :initarg :class
                   :reader show-time-css-class))
       (:default-initargs :class "showTime")
       (:metaclass metacomponent))

     (defmethod htcomponent-initstyles ((obj show-time))
       (format nil ".~a {color: black;font-weight: bold;}" (show-time-css-class obj)))

     (defmethod wcomponent-template ((obj show-time))
       (span> :static-id (htcomponent-client-id obj)
              :class (show-time-css-class obj)
              (wcomponent-informal-parameters obj)))

     (defmethod htcomponent-global-initscripts ((obj show-time))
       "var showTime = function (node) {
     node.innerHTML = new Date();
     setTimeout(function () {showTime(node);}, 1000);
     };")

     (defmethod htcomponent-initscripts ((obj show-time))
       (format nil "showTime(document.getElementById('~a'));" (htcomponent-client-id obj)))

Then change the WCOMPONENT-TEMPLATE of the INDEX-PAGE int the index.lisp file:

     (defmethod page-content ((o index-page))
       (site-template> :id "theBody"
                       :title "Home test page sample 2"
                       :class "sampleBody"
                       (div> :class "topHeader" "top header")
                       (div> :class "mainContent"
                             (h1> "Hello world"))
                       (div> :style "color: black;"
                             "Today: "
                             (show-time> :class "showTime"))))

As you can see, once inserted into your component no more javascript is needed, the injection system will do everything for you!

Here it is how the page will look like:

claw-html will let you to safely insert the name component multiple times because it will correctly handle injections and id generations.

For example try to put two times the SHOW-TIME> tag function inside the page content like the following:

     (defmethod page-content ((o index-page))
       (site-template> :id "theBody"
                       :title "Home test page sample 2"
                       :class "sampleBody"
                       (div> :class "topHeader" "top header")
                       (div> :class "mainContent"
                             (h1> "Hello world"))
                       (div> :style "color: black;"
                             "Today: "
                             (show-time> :class "showTime"))
                       (div> :style "color: black;"
                             "Today: "
                             (show-time> :class "showTime"))))

As you can see from the following source code css and javascript SHOW-TIME injections are correctly handled and not duplicated as it is for the id generation that do not create conflicts.

Working with forms
==================

Though you can use FORM>, INPUT>, SELECT>, etc. tag functions, claw-html shows its full power when you use its own library of form components.

First you must know that claw-html is a component based framework, not an action based one (like Java Apache Struts for example).

claw-html form components directly interact with their containing page, so that, when a form action is fired, input components may 'automatically' read and write the form visit object slots (that is set to the page itself as default).

Forms, submit buttons, and action links, may fire ACTION-OBJECT (whose default is the current page)  methods on submission, just before the page content rendering.

Your first form
---------------

All right, now it's time to build your first ``hello world'' form. To do so, you have to change your index.lisp file with the following code:

     ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
     ;;; $Header: src/index.lisp $

     (in-package :clhtml-sample2)

     (defgeneric index-page-say-hello (page))

     (defclass index-page (page)
       ((username :initform nil
                  :accessor index-page-username)
        (welcome-message :initform nil
                         :accessor index-page-welcome-message)))

     (defmethod index-page-say-hello ((page index-page))
       (setf (index-page-welcome-message page)
             (format nil "Hello ~a!" (index-page-username page))))

     (defmethod page-content ((o index-page))
       (site-template> :id "theBody"
                       :title "Home test page sample 2"
                       :class "sampleBody"
                       (div> :class "topHeader" "top header")
                       (div> :class "mainContent"
                             (cform> :action 'index-page-say-hello
                                     "Write your name "
                                     (cinput> :id "username"
                                              :accessor 'index-page-username)
                                     (csubmit> :value "Say hello"))
                             (h1> (index-page-welcome-message o)))
                       (div> :style "color: black;"
                             "Today: "
                             (show-time> :class "showTime"))))

     (lisplet-register-function-location *fs-lisplet*
                                         (make-page-renderer 'index-page
                                                             #'claw-post-parameters
                                                             #'claw-get-parameters)
                                         "index.html"
                                         :welcome-page-p t)

As you can see there is no need to handle http request parameters, neither action dispatching!

Now suppose that you want your form to be able to say both ``Hello'' and ``Goodbye''. This time you only have to define the ``goodbye'' method for your page and connect the ``goodbye'' button to it changing the PAGE-CONTENT method definition, like the following:

     (defgeneric index-page-say-goodbye (page))

     (defmethod index-page-say-goodbye ((page index-page))
       (setf (index-page-welcome-message page)
             (format nil "Goodbye ~a!" (index-page-username page))))

     (defmethod page-content ((o index-page))
       (site-template> :id "theBody"
                       :title "Home test page sample 2"
                       :class "sampleBody"
                       (div> :class "topHeader" "top header")
                       (div> :class "mainContent"
                             (cform> :action 'index-page-say-hello
                                     "Write your name "
                                     (cinput> :id "username"
                                              :accessor 'index-page-username)
                                     (csubmit> :value "Say hello")
                                     (csubmit> :action 'index-page-say-goodbye
                                               :value "Say goodbye"))
                             (h1> (index-page-welcome-message o)))
                       (div> :style "color: black;"
                             "Today: "
                             (show-time> :class "showTime"))))

Since you have provided the :ACTION attribute to the second submit button, your form is now able do use two different methods for action dispatching. Yes you don't have to implement any custom code for dispatching actions!

Now you may have noticed that if you submit the form leaving the input box blank, the message ``Hello NIL'' will be displayed.

There is an easy way to avoid this behaviour, ...validation!

For validation you have to provide the CINPUT component with the :VALIDATOR key. This points to a validator function.

A validator function if a function that accepts the value that is passed by the form component; if the validation fails, a validation error message is added to the variable *validation-errors*. The component EXCEPTION-MONITOR is given to show these validation errors.

Input server side validation and data translation
.................................................

Components may validate their input when they are provided with the :VALIDATOR attribute. This attribute designates a function that accept the value passed during form submission.

When a component validation fails, the visitobject is not updated because the form doesn't complete it's rewind cycle phase.

Currently the following validation functions are provided:

  * VALIDATE-REQUIRED (value &key (component (page-current-component *claw-current-page*)) message component-label) Checks if the required input field VALUE is present.  If not, a localizable message "Field ~a may not be empty." is sent with key "VALIDATE-REQUIRED". The argument for the message will be the :LABEL attribute of the COMPONENT.

  * VALIDATE-SIZE (value &key (component (page-current-component *claw-current-page*)) min-size max-size message-low message-hi component-label) Checks if the input field VALUE legth is less then or greater then rispectively of the form keywords :MIN-SIZE and :MAX-SIZE. If less then :MIN-SIZE, a localizable message "Size of ~a may not be less then ~a chars." is sent with key "VALIDATE-SIZE-MIN". The argument for the message will be the :label attribute of the COMPONENT and the :MIN-ZIZE value. If greater then :MAX-SIZE, a localizable message "Size of ~a may not be more then ~a chars" is sent with key "VALIDATE-SIZE-MAX". The argument for the message will be the :label attribute of the COMPONENT and the :MAX-ZIZE value.

  * VALIDATE-RANGE (value &key (component (page-current-component *claw-current-page*)) min max message-low message-hi component-label) Checks if the numeric input field VALUE is less then or greater then rispectively of the form keywords :MIN and :MAX. If less then :MIN, a localizable message "Field ~a is not less then or equal to ~d." is sent with key "VALIDATE-RANGE-MIN". The argument for the message will be the :label attribute of the COMPONENT and the :MIN value. If greater then :MIN, a localizable message "Field ~a is not greater then or equal to ~d." is sent with key "VALIDATE-RANGE-MAX". The argument for the message will be the :label attribute of the COMPONENT and the :MAX value.

  * VALIDATE-NUMBER (value &key (component (page-current-component *claw-current-page*)) min max message-nan message-low message-hi component-label) Checks if the input field VALUE is a valid number and then passes the validation to VALIDATION-RANGE. If not a number, a localizable message "Field ~a is not a valid number." is sent with key "VALIDATE-NUMBER". The argument for the message will be the :label attribute of the COMPONENT.

  * VALIDATE-INTEGER (value &key (component (page-current-component *claw-current-page*)) min max message-nan message-low message-hi component-label) Checks if the input field VALUE is a valid number and then passes the validation to VALIDATION-RANGE. If not a number, a localizable message "Field ~a is not a valid integer." is sent with key "VALIDATE-INTEGER". The argument for the message will be the :label attribute of the COMPONENT.

  * VALIDATE-DATE-RANGE (value &key (component (page-current-component *claw-current-page*)) min max (use-date-p t) use-time-p message-low message-hi component-label) Checks if the input field VALUE is a date between min and max. If :USE-DATE-P is not nil and :USE-TIME-P is nil, validation is made without considering the time part of local-time. If :USE-DATE-P nil and :USE-TIME-P is not nil, validation is made without considering the date part of local-time. If :USE-DATE-P and :USE-TIME-P are both not nil or nil, validation is made considering the date and time part of local-time. If value is less then the date passed to :MIN, a localizable message "Field ~a is less then ~a." is sent with key "VALIDATE-DATE-RANGE-MIN". The argument for the message will be the :label attribute of the COMPONENT and the value passed to :MIN parsed with the :LOCAL-TIME-FORMAT keyword. If value is greater then the date passed to :MAX, a localizable message "Field ~a is greater then ~a." is sent with key "VALIDATE-DATE-RANGE-MAX". The argument for the message will be the :label attribute of the COMPONENT and the value passed to :MAX parsed with the :LOCAL-TIME-FORMAT keyword.