Web application pages
*********************

claw applications are usually made of pages.

A PAGE is a CLOS class that contains the rendering logic and is called by the LISPLET when the URL matches the page resource mapping.

Writing your first claw page
============================

You already know how to register a PAGE into a LISPLET, if not, visit the previous chapter; what you miss, is how to put content into a page.

claw comes with the full set of html tags plus some custom components that we'll see in the next sections.

All html tag are rendered with functions whose names are the tag name plus the character >. Tag attributes are pairs of symbols for attribute names and strings for their values.

For example the function that render a DIV tag with class attribute ``foo'' is:

     (div> :class "foo")

Given this short intro we are now ready to write our first claw page:

     (defclass index-page (page) ())
     (defmethod page-content ((index-page index-page))
       (html>
        (head>
         (title> "First sample page"))
        (body>
         (h1> "Hello world"))))
     (lisplet-register-page-location *test-lisplet* 'index-page "index.html"
                                     :welcome-page-p t)

So, overriding the method PAGE-CONTENT for your new defined page gives you the possibility to insert its content. As you can see the method definition is very similar to an HTML file, thought more concise.

The special tag attribute: :ID and :STATIC-ID
---------------------------------------------

claw pages try to keep ``ID'' tag attributes unique among the page. This is particularly useful when you have to render tags that expose their id inside a loop. To see what happens when this situation occurs see the following example:

     (defmethod page-content ((sample-page sample-page))
       (html>
        (head>
         (title> "First sample page"))
        (body>
         (loop for letter in (list "A" "B" "C" "D")
            collect (div> :id "item" letter)))))

will produce the following HTML code

          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
                    "http://www.w3.org/TR/html4/strict.dtd">
          <html>
            <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <title>First sample page</title>
            </head>
            <body>
              <div id="item">A</div>
              <div id="item_1">B</div>
              <div id="item_2">C</div>
              <div id="item_3">D</div>
              <script type="text/javascript">
          //<!--
          document.addEventListener('DOMContentLoaded', function(e) {}, false);
          //-->
              </script>
            </body>
          </html>

When you want to prevent the default behaviour on id generation you have to provide the tag with the attribute :STATIC-ID, that will render into HTML as the attribute :ID, but without the id unique logic generation.

An important method that is present in all tags and component is the GENERATE-ID that you may use to obtain a unique id and put into components or tags with :STATIC-ID.

Look at the following to see how it can work:

     (defmethod page-content ((sample-page sample-page))
       (html>
        (head>
         (title> "First sample page"))
        (body>
         (loop for letter in (list "A" "B" "C" "D")
            for id = (generate-id "item") then (generate-id "item")
            collect (div> (span> :static-id id letter)
     		     (span> :onclick
     			    (format nil "alert(document.getElementById('~a').innerHTML);"
     				    id)
     			    "click me"))))))

that will produce the following HTML code:

          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
                    "http://www.w3.org/TR/html4/strict.dtd">
          <html>
            <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <title>First sample page</title>
            </head>
            <body>
              <div>
                <span id="item">A</span>
                <span onclick="alert(document.getElementById('item').innerHTML);">
                  click me</span>
              </div>
              <div>
                <span id="item_1">B</span>
                <span onclick="alert(document.getElementById('item_1').innerHTML);">
                  click me</span>
              </div>
              <div>
                <span id="item_2">C</span>
                <span onclick="alert(document.getElementById('item_2').innerHTML);">
                  click me</span>
              </div>
              <div>
                <span id="item_3">D</span>
                <span onclick="alert(document.getElementById('item_3').innerHTML);">
                  click me</span>
              </div>
              <script type="text/javascript">
          //<!--
          document.addEventListener('DOMContentLoaded', function(e) {}, false);
          //-->
              </script>
            </body>
          </html>

So, the outside tag generated id, is used in the onclick method of the span tags to reference the previous tag.