[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> &lt;!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"> &lt;html xmlns=\"http://www.w3.org/1999/xhtml\"> &lt;head> &lt;meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" /> &lt;title><span style=\"color:red\">Use Cases</span>&lt;/title> &lt;script type=\"text/javascript\" src=\"bloom.js\">&lt;/script> &lt;/head> &lt;frameset ROWS=\"100%\" COLS=\"100%\"> &lt;frame name=\"contentFrame\" src=\"<span style=\"color:red\">UseCasesContents.html</span>\"> &lt;/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> &lt;!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"> &lt;html xmlns=\"http://www.w3.org/1999/xhtml\"> &lt;head> &lt;meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" /> &lt;title>Test&lt;/title> &lt;/head> &lt;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>`))))')\"> &lt;noscript>This page requires JavaScript&lt;/noscript> &lt;div id=\"rulesText\" style=\"display:none\"> <span style=\"color:red\"><b>...</b></span> &lt;/div> &lt;/body> &lt;/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(\"&amp;lt;\",Tag,\" \",Args,\"&amp;gt;\"),Body,cat(\"&amp;lt;/\",Tag,\"&amp;gt;\\n\")); htmlTag(Tag,Args) = cat(\"&amp;lt;\",Tag,\" \",Args,\"&amp;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(\"&amp;lt;\",h1,\" \",\"\",\"&amp;gt;\"),\"The Title\",cat(\"&amp;lt;/\",\"h1\",\"&amp;gt;\\n\"))</tt>, which results in the text <tt>&lt;h1 &gt;The Title&lt;/h1&gt;</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 = \"&amp;lt;!DOCTYPE html PUBLIC \\\"-//W3C//DTD HTML 4.01 Transitional//EN\\\"&amp;gt;\\n\"; htmlCharSet = \"&amp;lt;meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html;charset=utf-8\\\" /&amp;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 &lt; is replaced by &amp;lt;, and that text is surrounded by &lt;pre>&lt;/pre> (or &lt;tt>&lt;/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; => &amp;amp;). Subsequently every left angle bracket is replaced by its HTML encoding (&lt; is replaced by &amp;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]