1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.2//EN">
<html><head>
<LINK rel="stylesheet" href="/doc/araneida.css">
<title>Araneida Reference : HTML generation</title>
</head><body>
<h1>HTML Generation</h1>
<p> We have functions that turn sexps into HTML. The format of the
sexp is
<pre>
((element-name {:attribute-name attribute-value}*) {contents})
</pre>
where element-name is a symbol, attribute-name is a keyword, and
contents are more elements, or strings. If there are no attributes,
the parens around element-name can be omitted. For example
<pre>
(html
(head (title "Title"))
(body (p "Click here to visit ((a :href "http://www.google.com/") "Google"))))
</pre>
<p>There is a special case for a tag named comment.
<pre>
(html
(comment (span "yes")))
=>
<!--
<span>yes</span> -->
</pre>
<p> You can also do:
<pre>
(html
((comment "This is no longer used") (span "yes")))
=>
<!-- This is no longer used
<span>yes</span> -->
</pre>
</pre>
<p> The functions are HTML (returns a string) and HTML-STREAM (outputs
directly to a stream). The latter is much less consy, so to be
preferred
<p> We also have a pattern-based rewriting system so that you can
"invent your own tags" (sic), using DEFINE-PATTERNS. See example 6 in
<a href="../examples/main.lisp">../examples/main.lisp</a>. This is
used in the DEFINE-PAGE macro, which also gives you correct handling of
conditional GETs for free.
<h1>Custom HTML tags</h1>
<h2>They're <i>kinda</i> like macros</h2>
<p>You can create custom tags that do "special" things.
<pre>
(defhtmltag coffee (attr content)
(declare (ignore attr content))
"c|_|")
</pre>
<p>Let's you do:
<pre>
(html (span "Coffee: " (coffee)))
=>
<span>Coffee c|_|</span>
</pre>
<p>That's a very simplistic example, of course.
<p>A more in-depth example might be:
<pre>
(defhtmltag odd-even-list (attr content)
`((ul ,@attr)
,@(let ((counter 0))
(mapcar (lambda (elt)
(incf counter)
(destructure-html (tag attrs content) elt
`((,tag :class ,(if (oddp counter) "odd" "even") ,@attrs) ,@content)))
content))))
(html
(odd-even-list
(li "odd")
(li "even")
(li "odd")
(li "even")))
=>
<ul>
<li class="odd">odd</li>
<li class="even">even</li>
<li class="odd">odd</li>
<li class="even">even</li>
</ul>
</pre>
<p>When writing more advanced custom tags, you may find DESTRUCTURE-HTML quite useful (see above for sample code).
<h1>Templates</h1>
<p>A template is nothing special, it's just a function with a funny name. It can be useful, though, for
keeping your templates out of the rest of your code, and for grepping purposes.
<pre>
(deftemplate mytemplate (&optional warning)
`(p \"A regular paragraph\" ,@(when warning (blink \"NOW WITH A BADLY FORMATTED WARNING!\"))))
; it's called:
(html
(call-template 'mytemplate))
</pre>
<p>Templates do not use the function namespace, so you couldn't do, for instance: <tt>(mytemplate)</tt>
<p>You can trace and untrace templates, as well:
<pre>
(trace-template mytemplate)
(untrace-template mytemplate)
</pre>
<h1>Integration with Parenscript</h1>
<p>If you load Parenscript before Araneida, you can use it with your normal
HTML generation routines.
<p>For example:
<pre>
(html '((span :css (:color "black" :size "200%")) "Print this"))
</pre>
<p>Would result in:
<pre>
<span style="color:black;size:200%">Print this</span>
</pre>
<p>If you need a block of CSS, you can do:
<pre>
(html '(html
(head (title "A simple title")
(css (h1 :color "red")
(h2 :color "blue")))
(body (h1 "A simple header"))))
</pre>
<p>To get:
<pre>
<html><head><title>A simple title</title>
<style type="text/css">
<!--
h1 {
color:red;
}
h2 {
color:blue;
}
--></style></head>
<body><h1>A simple header</h1>
</body>
</html>
</pre>
<p>If you need to send CSS as a file, just do:
<pre>
(defmethod handle-request-response ((handler my-handler) method request)
(css-file request
(* :border \"1px solid black\")
(div.bl0rg :font-family \"serif\")
((\"a:active\" \"a:hoover\") :color \"black\" :size \"200%\")))
</pre>
<p>It will send it with the proper content type, even.
<p>On the Javascript side of things, if you need inline Javascript, do:
<pre>
(html `((a :onclick ,(js:js-inline (alert "click!"))) "Click me!"))
</pre>
<p>To get:
<pre>
<a onclick="javascript:alert('click!');">Click me!</a>
</pre>
<p>If you need a block of Javascript code, do:
<pre>
(html `(html
(head (title "Another simple title")
(js-script
(defun foo (x)
(alert (+ "Be a lert: " x)))
(defun bar (x)
(alert (+ "Bar - " x)))))
(body
(p "All foos and bars come to an end")
(p ((a :onclick ,(js:js-inline (foo "end"))) "Foo!"))
(p ((a :onclick ,(js:js-inline (bar "end"))) "Bar!")))))
</pre>
<p>And the Javascript will be put in a proper <script> block.
<p>Lastly, if you need to send a javascript file, it's exactly like css-file,
except it's called js-file.
<p>Remember to use Araneida's css-file and js-file and NOT Parenscript's.
<p>On the same note, please note that Parenscript's HTML generation code is called
within Parenscript code and NOT Araneida's. This means that you would say
<pre>
(js-script
(defun add-div (name href link-text)
(document.write
(html ((:div :id name)
"The link is: "
((:a :href href) link-text))))))
</pre>
<p>Just like in the Parenscript docs.
<p>Enjoy!
</body></html>
|