[basic]
_if = __if(bool:B);
__if(bool:-1) = @else;
__if(bool:B) = @then;
split(Txt,Pat) = eval("var x = $Txt.split($Pat); x.ofs='cat'; x;");
scan(Txt,Pat) = eval("var x = $Txt.search(new RegExp($Pat)); x;");
[Patterns]
html(Tag,Args,Body) =
cat("<"+Tag+" "+Args+">"+Body+"</"+Tag+">\n");
htmlTag(Tag,Args) = cat("<",Tag," ",Args,">");
css(Tag,Style) = html("style","type=\"text/css\"",cat(Tag," {\n", Style,"\n}\n"));
[htmlLiterals]
htmlDoctype = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
htmlCharSet = "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />\n";
[css]
cssStyle(css("body","background-color:#ffffff;"));
/*cssStyles=reduce(select(cssStyle(X))); */
[GenericPage]
genericHtmlPage=
cat(htmlDoctype,
html("html","xmlns=\"http://www.w3.org/1999/xhtml\"",cat(
html("head","",reduce(select(headerItem(X)))),
html("body","",reduce(select(bodyItem(X)))))));
headerItem(htmlCharSet);
headerItem("
<!--The contents of this file are subject to the Mozilla Public License -->
<!--Version 1.1 (the \"License\"); you may not use this file except in -->
<!--compliance with the License. You may obtain a copy of the License -->
<!--at http:\/\/www.mozilla.org/MPL/-->
<!--Software distributed under the License is distributed on an \"AS-->
<!--IS\" basis, WITHOUT WARRANTY OF ANY KIND, either express or -->
<!--implied. See the License for the specific language governing -->
<!--rights and limitations under the License.-->
<!--The Original Code is Bloom, a rule-based development framework for -->
<!--web applications. The Initial Developer of the Original Code is -->
<!--Babelfish, Hilversum, The Netherlands. -->
<!--All Rights Reserved.-->
");
headerItem(reduce(select(cssStyle)));
bodyItem(html("noscript","","This page requires a JavaScript-enabled browser"));
[PaneLayout]
cssStyle(css("#container","background-color:#ffeedd; width:800; height:540;
position:relative; margin-left: auto;
margin-right:auto;
font: normal 0.7em/1.4em Tahoma, Verdana, Arial, Georgia, sans-serif;"));
bodyItem(html("div","id=\"container\"",reduce(select(cntrItem))));
cssStyle(css("#titlebar","position:relative; margin:0;"));
cntrItem(html("div","id=\"titlebar\"",reduce(select(titleBarItem))));
cssStyle(css("#navbar","position:relative; margin:5; width:190px; height:auto;"));
cntrItem(html("div","style=\"font-size:12;\" id=\"navbar\"",reduce(select(navBarItem))));
cssStyle(css("#minnavbar","position:relative; margin:5; width:190px; height:auto;"));
cntrItem(html("div","id=\"minnavbar\"",reduce(select(minNavBarItem))));
minNavBarItem(htmlTag("hr",""));
cssStyle(css("#contentFrame","overflow:auto;
position:absolute; top:105; right:0; margin:5; width:590px; height:430;"));
cntrItem(html("div","id=\"contentFrame\"",reduce(select(contentItem))));
cssStyle(css("#errFrame","position:relative; top:0px; left:200px; height:200px"));
cntrItem(html("div","id=\"errFrame\" style=\"display:none; background-color:#ffaaaa;\"",""));
[site]
headerItem(html("title","","Bloom: rule based web loom"));
headerItem(htmlTag("link","rel=\"shortcut icon\" href=\"http://blm.sourceforge.net/favicon.ico\""));
titleBarItem(htmlTag("img","src=\"http://blm.sourceforge.net/titlebar.gif\""));
start:genericHtmlPage;
[homePage]
navBarItem(html("a","href=\"JavaScript:parent.act('htmlElementSetInnerHTML(`contentFrame`,homeText)')\"","Bloom<br>"));
homeText = cat(
html("div","style=\"border-color:black; margin:20; float:right;\"",
html("table","style=\"border-style:solid; border-width:1; border-color:#BBBBBB;\"",
cat(html("tr","",
html("td","",htmlTag("img","src=\"http://blm.sourceforge.net/Loom.gif\""))),
html("td","style=\"font-size:10; width:208; text-align:justify;
\"",
"Just as a loom weaves single-colored, one
dimensional threads into the most beautiful, functional cloths,
so does the web-loom Bloom weave HTML, CSS, Bloom rules,
templates and patterns into beautiful, functional web
applications. As the illustration suggests, Bloom leverages the
efficiency, and therefore the expertice and efficacy of the web
application developer.")))),
html("div","style=\"padding:20\"","<span
style=\"font-size:x-large\">Bloom</span> is a light-weight setting
for making web-sites, content management systems and small to medium
web applications.
<p><span style=\"font-size:large\">B</span>loom (short for
web-loom) is text/file-oriented as ooposed to database-centric,
although data can be stored and shared with a database using AJAX.
<p><span style=\"font-size:large\">B</span>loom has no restrictive layout or
modules; <em>everything</em> from HTML's angle brackets to a
site-wide consistent look & feel is defined in Bloom rules. Bloom
is capable to work as a smart client or in a client-server
configuration using AJAX.
<p><span style=\"font-size:large\">B</span>loom has a small (memory) footprint and yet
deploys single-page applications (SPA); it can even generate
single-page application development environments (SPADEs's) which
include an envronment to alter their own data, meta data and
logic.
<p><span style=\"font-size:large\">F</span>inally: Bloom is available for free as open source software
(under the Mozilla 1.1 license)")
);
contentItem(homeText);
[infoPage]
navBarItem(html("a","href=\"JavaScript:parent.act('htmlElementSetInnerHTML(`contentFrame`,infoText)')\"","Info<br>"));
infoText = html("div","style=\"padding:20\"","
<span
style=\"font-size:x-large\">Bloom</span> at a glance:
<dl>
<dt><b>Text and file oriented</b>
<dd>Bloom is text and file oriented (instead of database centric), so
Bloom texts can be edited using <b>any text editor</b> and files can be
located and backed-up in <b>your prefered setting</b> as part of
a larger build enviroment. Of course, Bloom can store data in a SQL
database.
<dt><b>No preconceptions</b>
<dd>Bloom has no preconceptions about <b>layout</b> or application
<b>structure</b> or even about HTML and CSS. No obligatory frames or
banners, no unexpected limitations due to built-in modules. If HTML
starts using square brackets instead of angle brackets, your new site
can run in minutes.
<dt><b>Stand alone <em>and</em> client-server (AJAX)</b>
<dd>Bloom can use a server with SQL database to store and share data,
but it is equally suitable for stand-alone operation, possibly storing
data in <b>local files</b> (desk-top). When Bloom uses a server it is through
asynchronic synchronisation (<b>AJAX</b>).
<dt><b>Rule based</b>
<dd>Bloom is rule-based, which helps to achieve a consistent look and
feel, content re-use and powerful navigation systems. Also, Bloom
rules offer object-oriented and aspects-oriented features.
<dt><b>Small footprint</b>
<dd>With a core of less than 200 lines of JavaScript code and a
library of less than 500 lines of code, Bloom can create tiny
applications.
<dt><b>Open Source</b>
<dd>Bloom is distributed as Open Source Software under the Mozilla
Public License Version 1.1. It is free of charge and you can extend
and re-distribute it in accordance with the license.
<dt><b>Extendable</b>
<dd>Bloom rules are modular, making it easy to extend any Bloom
application with your own modules. The Mozilla 1.1 license
particularly caters for extendible systems.
<dt><b>Single Page Application (SPA)</b>
<dd>Bloom typically creates single page applications (SPA's). A SPA is
a <b>smart client</b> which avoids latency problems and simplyfies software
deployment. If data is stored on a server, it is done through AJAX,
again <b>avoiding latency</b> lags.
<dt><b>Comprehension oriented architecture</b>
<dd>Bloom uses a revolutionary technique called Comprehension Oriented
Architecture, as opposed to top-down architecture, where top-down,
<b>data-driven</b> and <b>resolution-based</b> aspects are combined
(woven) into web applications.
<dt><b>Domain Specific Languages</b>
<dd>Bloom sopports domain-specific languages to allow styles,
templates and patterns and other (meta) data to be expressed in an
appropriate, domain specific language. For instance, Bloom rules use
intuitive <b>pattern-replacement syntax</b>.
<dt><b>SPA Development Environment (SPADE)</b>
<dd>Bloom can generate Single Page Application Development
Environments: web-applications that include an environment to alter
themselves (data, and possibly also logic).
<dt><b>Ease of use</b>
<dd>Using Bloom is software development with tremendous expressive power,
but requiring great attention to detail.
<dt><b>ToDo</b>
<dd>At the moment of writing certain limitations exist:
<ul>
<li>Currently only Firefox is supported
<li>AJAX is halfway finished
<li>DSL's are not yet supported
<li>Debugging facilities are limited
</ul>
</dl>
");
[downloadPage]
navBarItem(html("a","href=\"JavaScript:parent.act('htmlElementSetInnerHTML(`contentFrame`,downloadText)')\"","Download<br>"));
downloadText =
html("div","style=\"padding:20\"",
cat(
html("span","style=\"font-size:x-large\"","Bloom"),
"is available for free under the Mozilla 1.1 license (see, ",
html("a","href=\"http://www.mozilla.org/MPL/\"","www.mozilla.org/MPL"),
htmlTag("p",""),
"When you are reading this text you have already downloaded Bloom:
this site is a Bloom application which contains all there is.",
htmlTag("p",""),
"Other than that, a few downloads are available.",
html("ul","",cat(
html("li","","<a href=\"http://sourceforge.net/project/showfiles.php?group_id=174824\">Bare Bloom</a> is a distro that contains the core and
not much more. It is a good starting point for building a new site
from scratch."),
html("li","","<a href=\"http://sourceforge.net/project/showfiles.php?group_id=174824\">Development Bloom</a> is a distro containing
various Bloom modules under development, all of which may be
unfinished, obsolete, or utterly useless, but some of which are
quite useful."))),
"<P>The source of Bloom are maintained at SourceForge and can be
found <a href=\"http://sourceforge.net/projects/blm\">here</a>"));
[useCase]
/* navBarItem(html("ul","",mapSelect(useCase,useCaseTocEntry,1))); */
navBarItem(html("a","href=\"JavaScript:parent.act('useCaseShowPage(`1`)')\"","Tutorial<br>"));
useCaseTocEntry(useCase(Id,Ttl)) = html("a",cat("href=\"JavaScript:parent.act('useCaseShowPage(`$1`)','",Id,"')\""),cat(html("li","",Ttl)));
/*useCaseNavLink(section(Id,Ttl)) = html("li","",Ttl); */
useCaseShowPage(Id) = cat(
varSet(name:"thisUseCase",value:at(select(useCase(Id)),0)),
htmlElementSetInnerHTML("contentFrame",cat(html("h1","",at(varGet(name:"thisUseCase"),1)))),
mapSelect(section(Id),useCaseAddSection,1));
useCaseAddSection(section(Id,Ttl,Cntnt)) =
htmlElementSetInnerHTML("contentFrame",cat(html("h2","",Ttl),Cntnt),"append");
[useCase1]
useCase(1,"Case 1: A Simple Web Site","In this section we
develop a simple web-site consisting of a few interlinked web pages
with a single consistent style. As we go, we introduce Bloom rules and
notation.");
section(1,"Intro","
<P>In this section we develop a simple web-site consisting of a few
interlinked web pages with a single consistent style. As we go, we
introduce Bloom rules and notation.
<P>Consider a set of use-case descriptions such as the one you are
now reading.
<P>Our site will have a header, with a site title, logo and possibly
additional information. Below the header is a table of contents, to
the left, showing the title of each use-case as a link, and a content
pane, to the right, showing either an index page with a brief
description of each use-case, or the selected use-case.
");
section(1,"Preliminaries","
<P>Bloom uses a single frame to contain all pages in order to achieve a
JavaScript program state across all pages. Accordingly, the \"site\"
starts out with single file, say <tt>UseCases.html</tt>, the contents of which
are
<pre>
<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html xmlns=\"http://www.w3.org/1999/xhtml\">
<head>
<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />
<title><span style=\"color:red\">Use Cases</span></title>
<script type=\"text/javascript\" src=\"bloom.js\"></script>
</head>
<frameset ROWS=\"100%\" COLS=\"100%\">
<frame name=\"contentFrame\" src=\"<span style=\"color:red\">UseCasesContents.html</span>\">
</frameset>
</pre>
<P>Note that the contents of this file are identical for every Bloom
application, with the exception of the title and contents file name,
shopwn in red.
<P>The contents file (here <tt>UseCasesContents.html</tt>) is as
follows, where the ellipses signify the Bloom rules defining the
content of our site (discussed below). Again, this text is identical
for every application with the exception of the Bloom rules (red
ellipses). The name <tt>start</tt>, shown in green, defines which
Bloom object specifies the content to be rendered for our site. This
object is defined in the Bloom rules.
<pre>
<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html xmlns=\"http://www.w3.org/1999/xhtml\">
<head>
<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />
<title>Test</title>
</head>
<body onload=\"document.normalize();
parent.vars.initSpec=document.getElementById('rulesText').firstChild.nodeValue;
parent.act('cat(submitSpec(varGet(name:`initSpec`),0),render(reduce(varGet(name:`<span style=\"color:green\">start</span>`))))')\">
<noscript>This page requires JavaScript</noscript>
<div id=\"rulesText\" style=\"display:none\">
<span style=\"color:red\"><b>...</b></span>
</div>
</body>
</html>
</pre>
");
section(1,"Bloom: objects","
<P>A Bloom specification consists of a set of modules. Every module
has a name, which appears in rectangular brackets, and a sequence of
objects separated and terminated by a semi-colon. The sequence of
modules is terminated with <tt>[end]</tt> (accordingly, no module
should be named \"end\").
<P>A Bloom object is what is called a <em>term</em> in algebra. A term
has an outermost function symbol and a number of arguments, which are
also terms, appearing between parentheses and separated by commas. If
a term has zero arguments, the parentheses are left out. Thus,
<tt>and(true,true)</tt> is a term.
<P>A term can also be a variable; in Bloom any identifier starting
with a capital is a variable (hence, functions should start with a
lower case letter). Also, integers and strings are terms.
<P>A term can be a function call, but it can equally describe an
object (record, struct) where the function symbol is the type and the
arguments are member values (fields, properties). A call which doesn't
match the left-hand side of any rule or to an altogether undefined
function, results in the creation of an object with the indicated type
and fields. When we refer to a term as \"object\", we mean the object
that term describes.
<P>In many settings, fields (members, properties) have a name. In
Bloom the name of a field is indicated followed by a colon. Thus
<tt>p(a:1,b:2)</tt> indicates an object of type <tt>p</tt> with fields
<tt>a</tt> and <tt>b</tt> with the indicated values. Unnamed fields in
a term are given intreger names from left to right starting with
0. Thus <tt>f(a)</tt> and <tt>f(0:a)</tt> are the same.
<P>An important kind of object is a rewrite rule, which is written as
<tt>s=t</tt> (where <tt>s</tt> and <tt>t</tt> are terms). A rule
signifies a pattern replacement: a term that matches the left-hand
side of a rule may be replaced by the corresponding instance of the
right-hand side. For instance, the rule <tt>double(X)=plus(X,X)</tt>
signifies that <tt>double(1)</tt> gives rise to <tt>plus(1,1)</tt>.
<P>In Bloom, content to be displayed is obtained by repeated pattern
replacement, starting with the object refered to with the variable
<tt><span style=\"color:red\">start</span></tt> mentioned earlier. The
result of that repeated replacement is the HTML text (CSS, ...)
representing the content; it isn't a string (that would be
impractical), but a tree (=term) the leaves of which are the strings
that will be pasted (in pre-order, i.e. as they appear in the term
representation) in the new page. The function <tt>cat</tt> is
undefined and is often used to pack a number of objects in a struct
with nameless fields.
");
section(1,"Patterns","
<P>Most objects describe parts of web pages, or patterns thereof that are used
moreoften. For instance, module <tt>Patterns</tt> below, hides details of
HTML and CSS syntax to allow HTML and CSS constructs to be specified
as plain function calls.
<pre>
[Patterns]
html(Tag,Args,Body) = cat(cat(\"&lt;\",Tag,\" \",Args,\"&gt;\"),Body,cat(\"&lt;/\",Tag,\"&gt;\\n\"));
htmlTag(Tag,Args) = cat(\"&lt;\",Tag,\" \",Args,\"&gt;\");
css(Tag,Style) = html(\"style\",\"type=\\\"text/css\\\"\",cat(Tag,\" {\\n\", Style,\"\\n}\\n\"));
</pre>
<P>For instance, in light of this module, the call <tt>html(\"h1\",\"\",\"The
Title\")</tt> leads to the text <tt>cat(cat(\"&lt;\",h1,\"
\",\"\",\"&gt;\"),\"The Title\",cat(\"&lt;/\",\"h1\",\"&gt;\\n\"))</tt>,
which results in the text <tt><h1 >The Title</h1></tt> to be
added to a page.
");
section(1,"Bloom: comprehension","
<P>The module Patterns is a simple example of top-down
pattern-replacement, and it is conceivable how an entire
web-application could be developed in this top-down fashion. However,
for various reasons, such as the fact that HTML requires certain
things to be placed in certain places, the top-down approach would
mean that strongly related aspects occur far apart in the code. This
is undesirable.
<P>Bloom favours an approach where a single module contains all
objects related to an application (a component, an aspect (in the
sense of AOP) or some other coherent functionality). Location-specific
placement is dealt with elsewhere, top-down, without knowledge of what
is being placed. The mechanism to achieve this is
<b>comprehension</b>.
<P>Other than the the HTML code mentioned under preliminaries and
possibly some server-side PHP, a Bloom application (web-site, content
management system) consists of a set of modules, each of which
consists of a set of objects. Note that these objects are called
top-level objects as opposed to descendents (sub-terms) whose parents
do not include a module.
<P>Comprehension allows us to select all objects of interest from this
set. The function <tt>select</tt> takes as its single argument a
pattern (= term possibly containing variables) and returns the list
of all top-level objects that match that pattern.
");
section(1,"Generic Page","
<P>The module GenericPage defines what an HTML page looks like.
<pre>
[GenericPage]
genericHtmlPage=
cat(htmlDoctype,
html(\"html\",\"xmlns=\\\"http://www.w3.org/1999/xhtml\\\"\",cat(
html(\"head\",\"\",reduce(select(headerItem(X)))),
html(\"body\",\"\",reduce(select(bodyItem(X)))))));
headerItem(htmlCharSet);
headerItem(reduce(select(cssStyle)));
bodyItem(html(\"noscript\",\"\",\"This page requires a JavaScript-enabled browser\"));
</pre>
<P>Any <tt>headerItem</tt> should be placed in the head of the page,
whereas any <tt>bodyItem</tt> will be placed in the body. For example,
the declaration of the no-script message must be placed in the body,
and is therefore introduced as a <tt>bodyItem</tt>. The constants
<tt>htmlCharSet</tt> and <tt>htmlDoctype</tt> are defined below, in
module htmlLiterals.
<P>Note that matching allows a subject to have more arguments (=
fields, immediate sub-terms) than the pattern. Thus, the pattern
<tt>cssStyle</tt> matches any object of that type, independent of the
number of fields it has. Similarly, <tt>bodyItem(X)</tt> matches any
object with at least one field (this excludes only <tt>bodyItem</tt>'s
without argumenbts, which are empty and might therefore just as well
be included; the variable is left here merely to make this point).
");
section(1,"HTML Literals","
<P>The two HTML literals used in module genericPage are defined
here. Whether to keep a constant in-line or to define it as a constant
(function with no arguments) is a matter of choice. Here, it is done
like this to avoid overly long or deep rules and to improve
self-documentation.
<pre>
[htmlLiterals]
htmlDoctype = \"&lt;!DOCTYPE html PUBLIC \\\"-//W3C//DTD HTML 4.01 Transitional//EN\\\"&gt;\\n\";
htmlCharSet = \"&lt;meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html;charset=utf-8\\\" /&gt;\\n\";
</pre>
");
section(1,"Pane Layout","
<P>Bloom has no pre-conceptions about the general layout of HTML
pages. In this simple web-site we will define a common layout of a
title bar on top, followed by a narrow left column for overview and
navigation, next to a wide right column for the actual content.
<pre>
[PaneLayout]
cssStyle(css(\"#titlebar\",\"position:absolute; top:0; left:0; height:95px;\"));
bodyItem(html(\"div\",\"id=\\\"titlebar\\\"\",reduce(select(titleBarItem))));
cssStyle(css(\"#navbar\",\"position:absolute; top:100px; left:5; width:200px;\"));
bodyItem(html(\"div\",\"id=\\\"navbar\\\"\",reduce(select(navBarItem))));
cssStyle(css(\"#contentFrame\",\"position:absolute; top:100px; left:200px;\"));
bodyItem(html(\"div\",\"id=\\\"contentFrame\\\"\",reduce(select(contentItem))));
</pre>
Note that each pane collects its own content through comprehension.
");
section(1,"Site","
<P>Having dealt with generics and pane layout, it is time to produce
specific, actual content.
<pre>
[site]
headerItem(html(\"title\",\"\",\"A simple web site\"));
titleBarItem(html(\"h1\",\"\",\"Bloom use-cases\"));
cssStyle(css(\"body\",\"background-color:#eeeeff;\"));
start:genericHtmlPage;
</pre>
<P>An object of the form <tt>name:term</tt> is an application variable
definition (not to be confused with a variable within a term). Its
value can be used or changed by an application (using <tt>varSet</tt>
and <tt>varGet</tt>). Ordinarily there is no need to change the value
of <tt>start</tt>, because Bloom applications are single-page
applications. Hence there is only one HTML page.
");
section(1,"Structure","
<P>A use-case is a piece of text. For many reasons, it makes sense to
break this text down. For this simple web-site we'll take a use case
to have a title and a sequence of sections. Each section has a title
and content. In addition, we mentioned an index page in the
introduction, so each use-case must have an abstract (a HTML text).
<P>In principle each use-case could be represented by a single term,
but in general big terms are less easy to maintain, for humans, so we
choose to separate the different sections.
<P>Although other mechanisms may be easier, for now we will simply add an
ID to each use case and each section in order to keep them together.
<P>Thus, the use-case you are now reading is represented by a term
like <tt>useCase(1,\"Case 1: A Simple Web Site\",\"In this section we
develop a simple web-site consisting of a few interlinked web pages
with a single consistent style. As we go, we introduce Bloom rules and
notation.\")</tt>. The first section might then be represented by
<tt>section(1,\"Preliminaries\",\"Bloom uses a single frame...\")</tt>.
");
section(1,"Table of contents","
<P>The table of contents in the navigation bar will hold a link for
each use-case, which, when clicked, presents the content of that page
in the content frame.
<P>We use a variant of comprehension: <tt>mapSelect</tt> takes a
pattern and an auxiliary function as arguments (and one further
argument 1, which we will not discuss now). It determines all matching
objects (using <tt>select</tt>) and applies the auxiliary function to
each, returning the list (<tt>cat</tt>) of all results.
<P>The table of contents is produced by
<pre>
navBarItem(html(\"ul\",\"\",mapSelect(useCase,useCaseTocEntry,1)));
</pre>
<P>Each entry is produced by <tt>useCaseTocEntry</tt>.
<pre>
useCaseTocEntry(useCase(Id,Ttl)) = html(\"a\",cat(\"href=\\\"JavaScript:parent.act('useCaseShowPage(`$1`)','\",Id,\"')\\\"\"),cat(html(\"li\",\"\",Ttl)));
</pre>
<P>Most of this is straightforward, except perhaps action
<tt>\"href=\\\"JavaScript:parent.act('useCaseShowPage(`$1`)','\",Id,\"')\\\"\"</tt>
defined for each link. The JavaScript function <tt>parent.act</tt> is
Bloom's common entry. We've already seen it in file
<tt>UseCasesContents.html</tt> in Section Preliminaries.
<P>We won't go into all details of this rule, but do note that the ID
of the use-case under consideration is passed into the script to be
executed (thorugh $1).
");
section(1,"Content","
<P>Content is written into the content-pane by <tt>useCaseShowPage</tt>
<pre>
useCaseShowPage(Id) = cat(
varSet(name:\"thisUseCase\",value:at(select(useCase(Id)),0)),
htmlElementSetInnerHTML(\"contentFrame\",cat(html(\"h1\",\"\",at(varGet(name:\"thisUseCase\"),1)))),
mapSelect(section(Id),useCaseAddSection,1));
</pre>
<P>We use a variable to hold the <tt>useCase</tt> object to avoid
repeated select's.
<P>Function <tt>htmlElementSetInnerHTML</tt> writes HTML to a named
HTML element. If a third argument is given, content is appended rather
than replacing the current content. Function <tt>at</tt> fetches a
sub-term from an object following a path dowsn (here, just the index 1
to retrieve the title). Function <tt>useCaseAddSection</tt> is defined
as follows.
<pre>
useCaseAddSection(section(Id,Ttl,Cntnt)) =
htmlElementSetInnerHTML(\"contentFrame\",cat(html(\"h2\",\"\",Ttl),html(\"a\",cat(\"name=\\\"\",Ttl,\"\\\"\"),\"\"),Cntnt),\"append\");
</pre>
");
section(1,"End","
<P>Here ends the first tutorial. We've developed a simple web-site
consisting of a few interlinked web pages with a single consistent
style, and we have introduced various aspects of Bloom.
");
section(1,"Comments","
<P>In the approach we have presented, Bloom rules appear in HTML
text. The <tt>section</tt> objects contain (Bloom) strings which contain HTML
text again. Without counter measures, the HTML tags in Bloom strings
aren't ignored by the HTML parser and lead to erroneous behaviour in
the site.
<P>This is one instances of a very common problem. The usual solution
is to escape certain characters. This is not the best solution and it
should be improved upon elsewhere or in the future, but at the point
of writing it is the approach we have taken.
<P>Our situation is complicated further because the HTML text of our
use-case containes pre-formatted HTML text, which must also be
escaped.
<P>The following escapes are used.
<ul>
<li> The source is plain HTML. In HTML text that is to appear
verbatim in the displayed page, each < is replaced by &lt;, and
that text is surrounded by <pre></pre> (or <tt></tt> in-line).
<li> When such HTML is placed in a Bloom object (as a string), all
double quotes it containes should be escaped with a backslash (\"
replaced by \\\"). However, escaping the sequence \\\" with a single
backslash is wrong, so first, every backslash is escaped (\\ => \\\\) and
then every quote (\" => \\\")
<li> Then every ampersand is replaced by its HTML encoding (& =>
&amp;). Subsequently every left angle bracket is replaced by its
HTML encoding (< is replaced by &lt;)
</ul>
");
[moduleEditor]
comment("This is the module editor. NavBar has a list of clickable
module names(plus new). Clicking loads that module's content into an
editor. Buttons for delete, revert, save.");
navBarItem(html("a","href=\"JavaScript:parent.act(
'cat(htmlElementSetInnerHTML(`minnavbar`,
cat(htmlTag(`hr`,``),htmlTag(`br`,``),mapSelect(module,meNavLink,1))),
htmlElementSetInnerHTML(`contentFrame`,moduleEditorDiv))')\"","Module Editor<br>"));
moduleEditorDiv = html("div","id=\"mEditorDiv\"",
html("form","",cat(
html("textarea","name=\"mEditor\" id=\"mEditor\" rows=\"20\" cols=\"70\"",""),
html("a","href=\"javascript:parent.act('cat(htmlElementSetInnerHTML(`minnavbar`,` `),
submitSpec(htmlElementGetValue(`mEditor`),1),render(reduce(varGet(name:`start`)))
)')\"","submit"),
html("a","href=\"javascript:parent.act('cat(htmlElementSetInnerHTML(`minnavbar`,`<hr>`),htmlElementSetInnerHTML(`contentFrame`,homeText),htmlElementSetDisplayStyle(`mEditorDiv`,`none`))')\"","close"))));
meNavLink(module(name:MN))=html("a",cat("href=\"JavaScript:parent.act('moduleEditorDoItem(`$1`)','",MN,"')\""),cat(MN,"<br>"));
moduleEditorDoItem(MN) = htmlElementSetValue("mEditor",topString(varSet(name:"meCurrentModule",value:at(select(module(name:MN)),0)),"[end]"));
[end]