emacs.d/clones/lisp/www.cliki.net/HTML-template.html

166 lines
12 KiB
HTML
Raw Normal View History

2022-10-07 15:47:14 +02:00
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>CLiki: html-template</title>
<link rel="alternate" type="application/atom+xml" title="ATOM feed of edits to current article"
href="https://www.cliki.net/site/feed/article.atom?title=html-template">
<link rel="stylesheet" href="static/css/style.css">
<link rel="stylesheet" href="static/css/colorize.css">
</head>
<body>
<span class="hidden">CLiki - html-template</span>
<div id="content"><div id="content-area"><div id="article-title">html-template</div><div id="article">HTML-TEMPLATE is an <a href="HTML&#32;template.html" class="category">HTML template</a> library to use templates much like Perl's <a href="https://metacpan.org/pod/HTML::Template">HTML::Template</a>. Despite its name, HTML-TEMPLATE is HTML-agnostic and could be used for templating other documents.<p>It was written by <a href="Edi&#32;Weitz.html" class="internal">Edi Weitz</a> and can be found at <a href="https://edicl.github.io/html-template/">https://edicl.github.io/html-template/</a>.<p><a href="Jörg&#32;Höhle.html" class="internal">Jörg Höhle</a> also liked the idea of a <em> clear and complete
separation between HTML</em> (written by designers) and code. He
came up with a variant of Edi's approach to HTML template. It uses
Edi's parsing code (thanks!), no more, but the programmer view on it
<em>feels very different</em>.<p>Consider Edi's 7x7 chess board example on his documentation page and
how my code would look like:<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> my-template
<span class="comment">;; load and check against specification
</span> <span class="paren2">(<span class="nonparen">tmpl-load <span class="string">"file.html"</span> '<span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">LOOP</span></i></a> rows <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">LOOP</span></i></a> cols colorful-style content</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">counter 0</span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen">tmpl-print
my-template
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_lambda.html" class="symbol"><i><span class="symbol">lambda</span></i></a> <span class="paren4">(<span class="nonparen">rowprinter</span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> repeat 7 <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a>
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_funcall.html" class="symbol">funcall</a> rowprinter
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_lambda.html" class="symbol"><i><span class="symbol">lambda</span></i></a> <span class="paren1">(<span class="nonparen">cellprinter</span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> repeat 7 <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_funcall.html" class="symbol">funcall</a> cellprinter <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_evenpcm_oddp.html" class="symbol">oddp</a> counter</span>)</span> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> <span class="string">"~R"</span> counter</span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_incfcm_decf.html" class="symbol">incf</a> counter</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
</span></div><p><a href="Jörg&#32;Höhle.html" class="internal">Jörg Höhle</a>'s design goals:
<ul><p> <li> Separate HTML design from code as much as possible, the key
idea in the template approach.<p> </li>
<li> <em>Verifiable specification</em> of the interface between
both, never see "$foo" in a user's browser as an indication that
some variable was not substituted.<p> </li>
<li> Designer and programmer <em>work concurrently</em> early
on. The programmer may use a default template automatically derived
from the specification, the web-designer a random-content template
delivering web-server based on this specification.<p> </li>
<li> <em>Efficiently deliver data</em>, which should be no
slower than frameworks based on direct embedding of code in <a href="HTML.html" class="internal">HTML</a> or
vice-versa. That's why I rejected intermediate structures (Edi's <a href="https://edicl.github.io/html-template/#semantics">template
structure</a>) and produce compilable code. A parsed template
becomes Lisp code, which can be either compiled and loaded as such
from the file system, or compiled on the fly at load-time.<p> </li>
<li> <em>Incrementally deliver results</em> as produced (useful
for huge data or HTTP 1.1 chunked encoding) which is incompatible
with non-lazy intermediate structures.<p> </li>
<li> Provide for <em>lexical scoping in templates</em>,
unlike Perl's HTML::Template. That is, a <samp>TMPL_VAR</samp> occurring
inside <samp>TMPL_LOOP</samp> may reference variables defined in an
outer (e.g. global) level. There's no need to repeat definitions at
inner levels.<p> </li>
<li> Deliver data in pieces as large as possible: i.e. no individual
calls to <a href="https://www.cliki.net/site/HyperSpec/Body/fun_writecm_p_rintcm_princ.html" class="hyperspec">PRINC</a> or <a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="hyperspec">FORMAT</a> for each HTML tag, coalesce these
instead.<p> </li>
<li> Early HTML validation of the templates
</li>
<li> some more I forgot...<p></li>
</ul><p>[This next section confuses me a bit. I think a list entry refers to Edi's version, but I can't really tell.]
Some differences between Edi and Jörg's work include:
<ul>
<li> No <tt>TMPL_INCLUDE</tt>
</li>
<li> No facility for caching or automated reloading, which I feel
orthogonal to templates, interferes with
<tt>TMPL_INCLUDE</tt> and is left to the application.
</li>
<li> An attempt to load templates validates them, so the running
web-server application will choose to reject template updates (and
log the error) until they are corrected instead of displaying
garbage to the user.
</li>
<li> <tt>TMPL_VAR</tt> may have content, which is valuable for
the web designer's <a href="GUI.html" class="internal">GUI</a>: s/he sees this content up to a closing
<tt>/TMPL_VAR</tt>.
</li>
<li> Variable substitution on the code side is <em>based on ordering
in the specification</em>, not on names or symbols, so there are no
surprises with packages and symbol-names across files.
</li>
<li> The template substituting code is trivially small and was
ported to Scheme. In fact, there's almost no such code since it's
in part in the programmer calling sequence (witness the above
example) and part in the Lisp code representing the template.
</li>
<li> Edi's got a package ready to go for you. [So is there code somewhere interested people could hack on, or something?]
</li>
</ul><p>My experience:
<ul>
<li> The above specification is not all about the interface between
programmer and designer. URL structure, form names etc. need also
be agreed upon.
</li>
<li> The template approach is <em>very useable</em> for
applications with <strong>small or medium demand for variable
appearance</strong>. Or you'd need too many templates.
</li>
<li> I generated pages using templates featuring <strong>highly
dynamic content</strong> (e.g. variable numbers of both rows and
colums of a table, selectable and variable order) which some people
initially thought not usable with a strict templates approach. It
was, in fact, clean and easy.
</li>
<li> <samp>TMPL_LOOP</samp> and <samp>TMPL_VAR</samp> are really
general and could even emulate <samp>TMPL_IF</samp>.
</li>
<li> I generated my templates from Lisp code via SXML, instead of
having a designer. This aids consistency among templates. For a
all-by-one-person job, the separation is clear overhead, even if
there's potential for code reuse. You'd probably prefer a
<a href="htout.html" class="internal">HTML-from-sexpr</a> approach in such a case and bypass templates.
</li>
<li> <em>HTML validation</em> of the templates is hindered by
<samp>TMPL_IF</samp> with an <samp>ELSE</samp> part, substitutions
inside attributes and obviously only possible when the
substitutions done by <samp>TMPL_VAR</samp> affect the HTML
structure. The most dynamic template is <kbd>TMPL_VAR
make-it-all</kbd>!<p> </li>
<li> As an enhancement, there could be a mechanism for global
substitutions which would remain outside of the specification.
E.g. some pages like to display calendars, the current date or use
a mapping from month names to numbers etc. Such substitutions could
always be present, across all pages of the application.
</li>
</ul></div></div>
<div id="footer" class="buttonbar"><ul><li><a href="html-template.html">Current version</a></li>
<li><a href="https://www.cliki.net/site/history?article=html-template">History</a></li>
<li><a href="https://www.cliki.net/site/backlinks?article=html-template">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=html-template&amp;from-revision=3830186510">Edit</a></li><li><a href="https://www.cliki.net/site/edit-article?create=t">Create</a></li></ul></div>
</div>
<div id="header-buttons" class="buttonbar">
<ul>
<li><a href="https://www.cliki.net/">Home</a></li>
<li><a href="https://www.cliki.net/site/recent-changes">Recent Changes</a></li>
<li><a href="CLiki.html">About</a></li>
<li><a href="Text&#32;Formatting.html">Text Formatting</a></li>
<li><a href="https://www.cliki.net/site/tools">Tools</a></li>
</ul>
<div id="search">
<form action="https://www.cliki.net/site/search">
<label for="search_query" class="hidden">Search CLiki</label>
<input type="text" name="query" id="search_query" value="" />
<input type="submit" value="search" />
</form>
</div>
</div>
<div id="pageheader">
<div id="header">
<span id="logo">CLiki</span>
<span id="slogan">the common lisp wiki</span>
<div id="login"><form method="post" action="https://www.cliki.net/site/login">
<label for="login_name" class="hidden">Account name</label>
<input type="text" name="name" id="login_name" class="login_input" />
<label for= "login_password" class="hidden">Password</label>
<input type="password" name="password" id="login_password" class="login_input" />
<input type="submit" name="login" value="login" id="login_submit" /><br />
<div id="register"><a href="https://www.cliki.net/site/register">register</a></div>
<input type="submit" name="reset-pw" value="reset password" id="reset_pw" />
</form>
</div>
</div>
</div>
</body></html>