AboutProjects

HTML Dialect 007

Author: Henrik Mikael Kristensen
Date: #date
Copyright: 2008 - HMK Design
Version: 0.0.7

This is alpha software under development. Features may change drastically during development.

Introduction

The purpose of the HTML dialect is to produce HTML code using a REBOL dialect. There are multiple reasons for this:

  • Dialect code takes up much less space than HTML and is simpler and easier to write.
  • Fits both static and dynamic HTML content generation.
  • It's easier to make dynamic content.
  • Provide standards compliant HTML, no matter the doctype, using the same dialect code.
  • REBOL code all the way. No need to intermix REBOL code with HTML.

The HTML Dialect is currently in version 0.0.5 and is released under the BSD license.

Installation

In order to use the HTML dialect, include the html.r file in your code and you're ready to go! You will know it's loaded when the ctx-html context exists in memory.

Usage

Primarily this is for usage with a webserver, such as Cheyenne, so there is an output buffer (a plain text string) called out-buffer available. When you want to output the content of it, you can do this in an entirely normal fashion with print, or by saving it or whatever you want to do.

You generate HTML with the html-gen or the output-html function. This is similar to the layout function in VID in REBOL/View, if you've tried that.

The html-gen function performs the parsing of the dialect and fills out-buffer with HTML code. Example:

>> html-gen [=== test ["my code"]]
== true
>> out-buffer
== "<test>my code</test>"

Every time you add a word, string, element or other piece of dialect code inside the dialect, it's run through html-gen and appended to the end of out-buffer without spacing.

>> html-gen ["more code"]
== true
>> out-buffer
== "<test>my code</test>more code"

html-gen accepts a variety of datatypes and can therefore be used to generate small bits of HTML code, output a single char or even nothing, if your input is none!. html-gen uses itself extensively inside its own parser for this purpose to minimize code size and allow dialect recursion.

Example:

html-gen "Text"

Will append the following to out-buffer:

Text

This code:

html-gen 'a

Will append the following to out-buffer:

a

This code:

html-gen [tag [shout till noon]]

Will append the following to out-buffer:

<shout till="noon">

The output-html function wraps html-gen. The function first clears the out-buffer, then generates the HTML, then copies the out-buffer, then clears the out-buffer again and finally returns the copy. This function is mostly useful, if you want to see output directly returned to the console, or if you generate entire pages without appending content manually in the out-buffer. Example:

>> output-html [=== test ["my code"]]
== "<test>my code</test>"
>> output-html ["more code"]
== "more code"

Both html-gen and output-html accept none!, string!, tag!, file!, url!, number!, time!, date!, get-word!, word! and block! as input.

If you want to generate multiple pages in sequence with html-gen, use clear out-buffer between generating pages with html-gen, or use the output-html function directly.

For the examples below we will use output-html for simplicity.

Full Page

Example for generating one full page:

output-html [page "My Page Title" ["This is my Webpage"]]

That line produces the following HTML code (indentation used here for clarity, it is not present in the actual output):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>My Page Title</title>
  </head>
  <body>This is my Webpage</body>
</html>

If you want to include a style sheet to the basic page, you can add it as a parameter to the page command:

output-html [page "My Page Title" css style.css ["This is my Webpage"]]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <title>My Page Title</title>
  </head>
  <body>This is my Webpage</body>
</html>

Enclosing Tags and Recursion

The HTML dialect supports recursing tags in as many levels as you want. You can for example use enclosing tags with the the === command, tag and optionally end-tag, full-tag and always end-tag or directly with a word for certain valid HTML tags:

output-html [=== p [=== pre [=== tt [=== a [Hello] ]]]]
== "<p><pre><tt><a>Hello</a></tt></pre></p>"

output-html [
  tag [p] tag [pre] tag [tt] tag [a] "Hello"
  end-tag end-tag end-tag end-tag
]
== "<p><pre><tt><a>Hello</a></tt></pre></p>"

output-html [p [pre [tt [a Hello]]]]
== "<p><pre><tt><a>Hello</a></tt></pre></p>"

The HTML dialect tracks which tags were inserted, when using the tag or full-tag command. This makes tag and full-tag usable for usage across multiple HTML dialect blocks, where a start and end-tag may not be in the same HTML dialect block, while === must always occur in its entirety inside the same HTML dialect block.

End-tags are stored in the end-tags block inside the ctx-html context. This block is treated as a FIFO stack.

Example:

output-html [tag [this]]
== "<this>"
output-html [end-tag]
== "</this>

The difference between tag and full-tag are that tag will print tags as single-tags, if the tag is a valid HTML single-tag. If you are using a valid single-tag, the tag is not tracked and inserting an end-tag, will not cause the tag to be properly ended. Valid single-tags are stored in the single-tags block inside the ctx-html context.

For the following example, consider that >br<, >hr< and >img< are in the single-tags block:

Examples:

output-html [tag [p] tag [hr] end-tag]
== "<p><hr /></p>"

Example of using a valid HTML single tag along with an erroneous end-tag:

output-html [tag [link]]
== "<link />"
output-html [end-tag]
** Script Error: Out of range or past end
** Where: html-gen
** Near: out close-tag either block? last

Tags are tracked across multiple uses of html-gen, so if you don't end a tag correctly in one use of html-gen, subsequent uses of it will also contain errors. Furthermore, the HTML dialect can't track if your complete page contains too few end-tags. The only way is to check if ctx-html/end-tags is empty at the end of page generation.

full-tag will always treat any tag as a tag that has an end-tag, so whenever you are using full-tag, end-tag is mandatory.

Example:

output-html [full-tag [link]]
== "<link>"
output-html [end-tag]
== "</link>"

HTML Output

Some things about the output:

  • There are never spaces between uses of html-gen, so any spaces that need to be there, must be added by you.
  • The output is always a string.
  • The output may not be very readable, as html-gen does not add newlines or indentations to the HTML code.

CSS Styles

Any tag can be followed by one or more optional issue! values which describe one or more CSS classes used for this style. If the issue! is not added, the style is not included for that tag.

Examples:

output-html [div #headline "Hello"]
== {<div class="headline">Hello</div>}

output-html [div #text #headline "Hello"]
== {<div class="text, headline">Hello</div>}

Note: Styles through HTML IDs is not supported.

HTML Doctypes

The HTML dialect supports most available versions of the HTML specs, though not yet adhering to them 100%. When including the page command on the web page, the !DOCTYPE tag is automatically included at the top of the webpage. Single standing tags in XHTML 1.0 and upwards are always postfixed with a /. The following types are supported:

html-2.0-dtd
html-3.2-dtd
html-4.01-strict
html-4.01-transitional
html-4.01-frameset
xhtml-1.0-strict
xhtml-1.0-transitional
xhtml-1.0-frameset
xhtml-1.0-dtd
xhtml-basic-1.0-dtd
xhtml-basic-1.1-dtd
mathml-1.01-dtd
xhtml-mathml-svg-dtd
svg-1.0-dtd
svg-1.1-full-dtd
svg-1.1-basic-dtd
svg-1.1-tiny-dtd

They are all stored in the doc-types block, which is used in the HTML dialect.

To switch the HTML version, just use it before any code:

output-html [html-4.01-strict tag [br]]
== {<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd"><br>}
output-html [xhtml-1.0-strict tag [br]]
== {<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><br />}

Dynamic Content

The HTML dialect provides powerful methods for inserting dynamic content. Although you can compose or reduce blocks externally for the dialect, there are various ways to determine content from inside the dialect, while it's being parsed.

Using do

The do command evaluates a block of regular REBOL code inside the block. The last value returned from the block is inserted in the place where the do block exists and is fed into html-gen. This can be both normal values or entire dialect blocks, to provide alternative HTML content when needed in certain circumstances.

Example:

div #now [do [now]]
== <div class="now">22-Jun-2008/04:12:06+2.00</div>

You can use it to provide alternate blocks, say, if your table of blog posts is empty. Example:

div #posts [
  do [
    either empty? posts [[
      "No posts in this blog."
    ]][[
      table rows :posts
    ]]
  ]
]

Using set-word!

The set-word datatype is specifically reserved for reusable blocks of code or single words or values in your dialect code, making your code even smaller. You must refer to the original set-word! as a word!, when you want to recall the content.

output-html [hello: [p "Hello World!"] hello hello]
== {<p>Hello World!</p><p>Hello World!</p>}

The word is stored in an internal block of keys and values in the ctx-html context in the user-words block throughout the lifetime of the context. You can't delete defined words, but you can redefine them. The word is not available globally and defining a global word with the same name will not affect the content of the stored word.

You can redefine the same word throughout the use of the block. Example:

hello: [p "Hello World!"] hello
hello: [p "Goodbye"] hello

Produces:

<p>Hello World!</p>
<p>Goodbye</p>

You can also use this to create unique methods for generating HTML using do blocks. Example:

t: [p [do [now wait 1]]]
t t t

Produces:

<p>10-Aug-2008/0:25:56+2:00</p>
<p>10-Aug-2008/0:25:57+2:00</p>
<p>10-Aug-2008/0:25:58+2:00</p>

Caveats

  1. Each block that you feed to a set-word must make fully sense for html-gen, and that you can't split things like tables in multiple segments. You can use an entire table cell's content, but not separate rows or format blocks.
  2. If you (accidentally) define a word that also qualifies as a tag, such as 'b or 'strong, that word will not be usable. Such an example would merely result in the word being ignored and the appropriate tag would be used instead. Tags have higher priority. Example:
p: [p "Hello"] p

Produces:

<p></p>
  1. You can't delete defined words. They stay in the context throughout its lifetime.

Using get-word!

The use of get-word! types in code will automatically get a word from the global context, or whatever context the dialect code block is bound to at HTML generation time. This is a global rule.

a: "my string"
output-html [p [:a]]
== "<p>my string</p>"

If you define a set-word! as mentioned in the section above, this set-word! will not be usable as a get-word!. get-word! only refers to the contexts to which the input block is bound. /note

Page Composition

You can build a webpage from multiple blocks and then combine them together in a single "super block", which may help you create clearer page compositions. When including a get-word!, it is processed internally with html-gen, and if that word contains some HTML dialect code, it will be processed as that. You can do this even in multiple levels as html-gen is fully recursive.

Example:

header: [div #menu "My header"]
content: [div #body "My body"]
footer: [div #footer "Copyright 2008 Acme Corp"]

output-html [page "My Page" [:header :content :footer]]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>My Page</title>
  </head>
  <body>
    <div class="menu">My header</div>
    <div class="body">My body</div>
    <div class="footer">Copyright 2008 Acme Corp</div>
  </body>
</html>

Forms

Creating forms with the HTML dialect is very straight forward: You add form elements and a submit button, and then when you submit the form, the server receives them via POST.

The HTML dialect poses some intentional limitations on forms for simplifying the form system:

  • All HTML dialect forms send via the POST method. This will not change.
  • There are no per-field settings yet, such as maximum field size. This is planned for change later.
  • There is no scheme yet for form validation, neither server- nor client-side. This is planned for change later.

A form is created by stating the form action, name and possible default input values through an object. The form code is enveloped in a block. Each field element describes its associated name as a word! value. This method is fine, if you don't want default data to be put in the form or expect to revisit the form in a validation process through REBOL and/or Cheyenne, but for example a PHP solution, or if you are creating a form to be used on a completely static HTML page.

Example:

form submit.rsp [
  div #label "Name" [field name]
  div #label "Address" [field address]
  div [submit "Submit Form"]
]

Produces:

<form action="submit.rsp" method="POST">
  <div class="label">
    Name
    <input type="field" name="name" value="" />
  </div>
  <div class="label">
    Address
    <input type="field" name="address" value="" />
  </div>
  <div>
    <input type="submit" name="Submit Form" />
  </div>
</form>

The names used for each field in the form are the same as those used in the dialect.

Using the Form Object

If you use a get-word! in the form specifications, you will be able to attach an external object to the form. The object must already exist with the required content. This is a better method than the above one, if you desire to recreate the form with its existing data in the same REBOL runtime environment that the form was originally generated from, or you wish default data to be put in the form.

While the job of the HTML dialect finishes when rendering the HTML code, it means you can essentially tie form data to a fixed object that simply updates its values when you submit form data to the server, granted that you must write this part yourself. The ctx-html internal value is form-object, which is by default none.

The added benefit is that the HTML dialect will let you auto-refill the form with the stored values in the object, when the page needs to be rendered again. The form object is stored internally in the ctx-html context as form-object.

Example, showing a pre-existing form object, that has the same words as used in the form:

form-data: make object! [
  name: "Luke Lakeswimmer"
  address: "Tatooine Rebol Base"
]

And in the form dialect code, we include form-data:

form submit.rsp :form-data [
  div #label "Name" [field name]
  div #label "Address" [field address]
  div [submit "Submit Form"]
]

Produces:

<form action="submit.rsp" method="POST">
  <div class="label">
    Name
    <input type="field" name="name" value="Luke Lakeswimmer" />
  </div>
  <div class="label">
    Address
    <input type="field" name="address" value="Tatooine Rebol Base" />
  </div>
  <div>
    <input type="submit" name="Submit Form" />
  </div>
</form>

You can also create the form-data object inline in the dialect code or as a block of key/value pairs.

Dialect Rule Reference

The following rule-sets describe how the dialect parser works. The entire parser is built from the rule blocks or sets below. Actions in the code (the parentheses), are left out for clarity. We start with the types and work our way from the low-level rules and up toward the main parser.

block-types

This describes all block types except for path!

block-types: [block! | hash! | list!]

value-types

This rule defines the datatypes that describe values directly, such as numbers, strings and urls. Tags are purposely disallowed.

value-types: [
  money! | binary! | number! | date! | time! | tuple!
  | url! | email! | file! | any-string! | char! | pair!
]

cell-types

This rule defines the allowed datatypes for input parameters for most tags. It should be the same types as allowed in html-gen.

cell-types: [
  ['do block-types]
  | [
    value-types | block-types | datatype! | word!
    | get-word! | lit-word! | path! | lit-path!
    | refinement! | logic!
  ]
]

href-types

These rules define URL inputs for use in page-rules.

href-types: [
  ['do block-types] | [word! | url! | string! | path! | refinement!]
]

doc-types

This rule is used as a word-rule.

doc-types: [
  html-2.0-dtd
  | html-3.2-dtd
  | html-4.01-strict
  | html-4.01-transitional
  | html-4.01-frameset
  | xhtml-1.0-strict
  | xhtml-1.0-transitional
  | xhtml-1.0-frameset
  | xhtml-1.0-dtd
  | xhtml-basic-1.0-dtd
  | xhtml-basic-1.1-dtd
  | mathml-1.01-dtd
  | xhtml-mathml-svg-dtd
  | svg-1.0-dtd
  | svg-1.1-full-dtd
  | svg-1.1-basic-dtd
  | svg-1.1-tiny-dtd
]

verbatim-rules

These rules are output directly as they are input (verbatim). They are the first rules in the HTML dialect, as the input is not processed at all.

verbatim-rules: [
  value-types | tag! | lit-word! | path! | lit-path!
  | refinement! | datatype! | logic!
]

eval-rules

These rules are used for the TAG command.

eval-rules: [any ['do block-types | any-type!]]

base-rules

These rules produce various types of common tags and links and are used as base for higher levels of rules.

base-rules: [
  '=== word! opt ['opts block-types] cell-types
  | 'tag into eval-rules
  | 'end-tag
  | 'do block-types
  | block-types
]

link-rules

These are the rules used with the at command to produce links using various input formats.

link-rules: [
  'at [
    'page word!
    | 2 cell-types
      any [
        'vars [block! | object! | get-word!]
        | 'words block!
      ]
  ]
]

image-rules

These are the rules for producing image links.

image-rules: [
  image cell-types
]

table-rules

These are the main rules for building an HTML table. It uses several sub-rules which are described below.

table-rules: [
  'table
    opt 'debug
    opt [some issue!]
    any [
      [
        'format
          any [format-rule block-types]
          any [
            'rows [
              get-word! | into table-format-rules
              | table-format-rules
            ]
          ]
      ] | [
        'rows [
          get-word! | into table-row-rules
          | table-row-rules | into table-block-rules
        ]
      ]
    ]
  ]
]

format-rule

This rule is used to determine the type of row used for a particular format block.

format-rule: [
  opt [
    'first | 'even-last | 'odd-last
    | 'last | 'odd | 'even | 'any
  ]
]

table-row-rules

These rules define how a single row in a table can be shaped.

table-row-rules: [
  some [
    'row any [
      ['cell | 'header]
      any [
        'colspan integer! | 'align word!
        | 'width integer! opt 'percent | 'class word!
      ]
      [none! | cell-types]
    ]
  ]
]

table-cell-rule

This table rule is used to generate a table cell, where there are multiple columns per row in the input data, or the input data consists of objects.

table-cell-rule: cell-types

table-row-rule

This table rule is used to generate a table cell, where there is only one column per row in the input data and the input data does not consist of objects.

table-row-rule: cell-types

table-format-rules

These rules are used after the format command and are identical in structure to table-block-rules, however when using blocks of blocks or plain blocks as input, the formatting is ignored.

table-format-rules: [
  any [object! | into [any table-cell-rule] | table-row-rule]
]

table-block-rules

These rules are used after the rows command without using format first. This means objects are just output cell by cell. The data row is parsed the same way as the formatting row.

table-block-rules: [
  any [object! | into [any table-cell-rule] | table-row-rule]
]

tag-rule

These rules are used in cases where a normal HTML tag is wanted. It can be used recursively.

tag-rule: [
  [
    'html | 'head | 'title | 'body | 'p | 'strong
    | 'em | 'b | 'i | 'u | 'tt | 'big | 'small
    | 'strike | 'del | 'pre | 'ul | 'il | 'li
    | 'sup | 'sub | 'samp | 'code | 'blockquote | 'q
    | 'kbd | 'var | 'cite | 'tr | 'th | 'td
    | 'table | 'a | 'div | 'span | 'dl | 'dt | 'dd
    | 'h1 | 'h2 | 'h3 | 'h4 | 'h5 | 'h6
  ]
  opt [some issue!]
  opt ['id cell-types]
  [tag-rule | get-word! | cell-types | ()]
]

tag-rules

It looks redundant here, but in the source code, this rule collects all tags properly from recursive runs of tag-rule and generates the required HTML code.

tag-rules: tag-rule

loop-rules

These rules produce loops, and allow traversing data blocks either wholly or partially.

loop-rules: [
  'loop integer! block-types opt ['alternate block-types]
  | 'traverse [block-types | get-word!]
    opt ['using [word! | 'lit-word | get-word! | block-types]]
    block-types
    opt ['alternate block-types]
]

text-format-rules

These rules allow special formatting parsers for text. The rules are meant to be extensible later, and are not really useful now.

text-format-rules: ['format word! cell-types]

form-rules

These rules produce form tags and are considered a higher level of rules. They also manage the form content, either from words or a specific form object.

form-rules: [
  'form cell-types opt [get-word! | ['vars | object!]] cell-types
  | 'textarea word!
  | ['field | 'button | 'hidden | 'password] word!
  | 'checkbox word!
  | 'radio word!
  | 'select word! opt ['values | 'key-values] cell-types
  | ['submit | 'reset] string!
]

page-rules

These rules produce the outer skeleton of the webpage by providing the HEAD and BODY section.

page-rules: [
  'page cell-types any [
    'redirect href-types integer!
    | 'favicon href-types
    | 'charset [string! | word!]
    | 'css href-types
    | 'description string!
    | 'robots some [
      'noindex | 'index | 'nofollow | 'follow
      | 'noarchive | 'nosnippet | 'noodp | 'noydir
    ]
    | 'rss href-types string!
    | 'atom href-types string!
    | 'script href-types
    | 'meta ['name | 'http-equiv] 2 cell-types
  ] block-types
]

error-rules

These rules (actually only one rule for now) are used for handling and printing errors generated by the parser during HTML creation. They will be extended later to become more useful.

error-rules: 'errors

word-rules

The word rules are used for lists of words that are either dynamic to the parser, i.e. lists of words that are built during parsing or are built into the HTML dialect, such as the word list for doc-types.

word-rules: [doc-types | get-word! | word!]

all-rules

These rules are the collection of all the above mentioned rules. These rules are used directly by the parser, and you can see here in which order they are evaluated.

all-rules: [
  any [
    verbatim-rules | base-rules | link-rules | image-rules
    | table-rules | tag-rules | loop-rules | text-format-rules
    | form-rules | page-rules | error-rules | word-rules
  ]
]

Dialect Command Reference

page

Produces the outer skeleton for a webpage with correct HTML tags and DOCTYPE.

Parsed as:

'page cell-types <subcommands> block-types

Example:

page "My Page" []

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>My Page</title>
  </head>
  <body></body>
</html>

page supports a range of subcommands. The page command supports using the subcommands as many times as you want, before creating the main page in a block.

redirect

This allows setting a 302 redirect for a page along with the number of seconds to wait before redirecting.

Parsed as:

'redirect href-types integer!

Example:

page "Wrong page" redirect http://foo.com 5
  ["Redirecting to foo.com in 5 seconds"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <meta http-equiv="refresh" content="5; url=http://foo.com" />
    <title>Wrong page</title>
  </head>
  <body>Redirecting to foo.com in 5 seconds</body>
</html>

refresh

This is an alias for redirect and does exactly the same thing.

Parsed as:

'refresh href-types integer!

favicon

This sets the favicon for the webpage. It does not generate a favicon, but only links to an .ico file stored on the server.

Parsed as:

'favicon href-types

Example:

page "My page" favicon icon.ico ["My web page"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <link rel="shortcut icon" href="icon.ico" />
    <title>My page</title>
  </head>
  <body>My web page</body>
</html>

charset

This allows you to set the charset for the webpage. A full list of charsets is given here. Note that REBOL 2 does not support Unicode, so text will be encoded as plain ASCII. Therefore you should be careful when selecting UFT-8 encoding. There is no standard selected charset. Unicode will be supported with REBOL 3.

Parsed as:

'charset [string! | word!]

Example:

page "My Page" charset utf-8 ["My Unicode Webpage."]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <meta http-equiv="content-type"
      content="text/html; charset=utf-8" />
    <title>My Page</title>
  </head>
  <body>My Unicode Webpage.</body>
</html>

description

This sets the description of the webpage for use by search engines.

Parsed as:

'description string!

Example:

page "My Page" description "A great page" ["My page"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <meta name="description" content="A great page" />
    <title>My Page</title>
  </head>
  <body>My page</body>
</html>

robots

This manages settings for a webpage with respect to how webcrawlers and search engines like Google and Yahoo see them. There are several settings available, each one set as a block of words.

Beware that not all webcrawlers adhere to your robots settings and malware is certain to ignore them.

This subcommand does not generate a robots.txt file.

Parsed as:

'robots into [
  some [
    'noindex | 'index | 'nofollow | 'follow
    | 'noarchive | 'nosnippet | 'noodp | 'noydir
  ]
]
noindexTells the search engine not to index this page.
indexTells the search engine to specifically index this page. This is default.
nofollowTells the search engine not to follow links on this page for indexing.
followTells the search engine to specifically follow links on this page for indexing. This is default.
noarchiveTells Google not to store a cached copy of this page.
nosnippetTells Google not to display a text snippet under the listing.
noodpTells Google, MSN and Yahoo not to use search information gathered from the Open Directory Project.
noydirTells Yahoo not to use search information from the Yahoo Directory.

Example:

page "My Page" robots [index nofollow] ["My page"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <meta name="robots" content="index, nofollow" />
    <title>My Page</title>
  </head>
  <body>My page</body>
</html>

css

This includes a CSS stylesheet file in the webpage. It neither produces CSS styles within the webpage nor produces a CSS file. The CSS file must already exist. You can include as many CSS stylesheet files as you want.

Parsed as:

'css href-types

Example:

page "My Page" css style.css css menu.css ["My Webpage"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <link rel="stylesheet" href="style.css" type="text/css" />
    <link rel="stylesheet" href="menu.css" type="text/css" />
    <title>My Page</title>
  </head>
  <body>My Webpage</body>
</html>

rss

This includes a link to an RSS feed for the webpage along with a title for the feed. It allows webbrowsers to automatically detect the RSS feed for your webpage. It does not produce the RSS feed itself, although the HTML dialect can be used to create RSS feeds. For this command, the RSS feed must already exist.

Parsed as:

'rss href-types string!

Example:

page "My Blog" rss blog-rss.xml "My Blog RSS Feed" ["My Blog"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <link rel="alternate" href="blog-rss.xml"
      type="application/rss+xml" title="My Blog RSS Feed" />
    <title>My Page</title>
  </head>
  <body>My Webpage</body>
</html>

atom

This includes a link to an ATOM feed for the webpage along with a title for the feed. It allows webbrowsers to automatically detect the ATOM feed for your webpage. It does not produce the ATOM feed itself, although the HTML dialect can be used to create ATOM feeds. For this command, the ATOM feed must already exist.

Parsed as:

'atom href-types string!

Example:

page "My Blog" atom blog-atom.xml "My Blog Atom Feed" ["My Blog"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <link rel="alternate" href="blog-atom.xml"
      type="application/atom+xml" title="My Blog Atom Feed" />
    <title>My Page</title>
  </head>
  <body>My Webpage</body>
</html>

script

This includes javascript files in the webpage. It neither creates javascript code inside the webpage nor produces a separate javascript file. The javascript file must already exist.

Parsed as:

'script href-types

Example:

page "My Page" script menu.js ["My Webpage"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <script src="menu.js" type="text/javascript">
    <title>My Page</title>
  </head>
  <body>My Webpage</body>
</html>

meta

Produces a generic META tag with name and content.

Parsed as:

'meta ['name | 'http-equiv] 2 cell-types

Example:

page "My Page" meta name keywords "wikipedia,encyclopedia" ["My Webpage"]

Produces:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <meta name="keywords" content="wikipedia,encyclopedia" />
    <title>My Page</title>
  </head>
  <body>My Webpage</body>
</html>

===

This produces an enclosing tag set, such as <tt></tt> around the content defined in the following cell-types. You can with opts define an options block for the tag. This is extensively used internally, and you should in most cases not need to use it directly for HTML. It is, however, useful for XML tag generation, such as for RSS feeds, where all tags must have enclosing tags.

Parsed as:

'=== word! opt ['opts block!] cell-types

Example:

=== tt opts [class clever] "My Text"

Produces:

<tt class="clever">My Text</tt>

I wrote earlier that styles are always written as an issue!. This is not the case here, as the opts block contains generic input that is fed to REBOL's built in build-tag function, which produces an # in the finished class string:

build-tag [a class #myclass]
== <a class="#myclass">

Which is no good, so in this one case, we are working without issue! But since this is a low level way of producing tags with options, you may never need to use it in your own dialect code.

tag

Creates a tag using REBOL's compose/deep and build-tag function. The HTML dialect tracks the use of tags that are not listed in the interal single-tags block and will store this tag in a stack for later retrieval by the end-tag command.

Parsed as:

'tag block!

Example:

tag [th]

Produces:

<th>

Example:

tag [th width 100]

Produces:

<th width="100">

full-tag

Creates a tag using REBOL's compose/deep and build-tag function. In contrast with the tag command, the HTML dialect does not perform tracking of single tags and all tags produced here has an end tag. This is used internally to produce the === command and is necessary for producing RSS and ATOM feeds that have tags with end tags, that are normally single-tags in regular HTML.

Parsed as:

'tag block!

Otherwise the behavior is exactly the same as for tag.

end-tag

Complements tag, by providing. If this is used on a tag that is listed as a single tag or if the command is used too many times, compared to the number of tags, the parser will return an error.

Parsed as:

'end-tag

Example:

tag [th] end-tag

Produces:

<th></th>

at

This produces a link either directly or from a small dialect and is capable of building GET strings from objects, words or values of various formats. It is also capable of telling whether the link exists on the current page and renders the link as plain text instead.

It's recommended to use this method to produce any link in the dialect.

Parsed as:

'at [
  'page word!
  | 2 cell-types
    any [
      'vars [block! | object! | get-word!]
      | 'words block!
    ]
]

There are two methods for providing links.

Direct Links

One is to provide the link directly as a URL along with a link name string.

Example:

at http://www.google.com "Go visit Google"

Produces:

<a href="html://www.google.com">Go visit google</a>

Links with get Information

The third method is to generate links with get information. It is possible to build this entirely in REBOL code, so there is no need to manually build such links. All the required encoding happens automatically. There are three ways to do this, depending on the input format you wish to use:

Use a block of words

Given that each word is already set in the context which the dialect block exists in, the words will be placed in the URL along with their values. The word block is preceded by the words word.

Example for words user-id and message-id set to 5 and 3 respectively:

at mylink.html "My Link" words [user-id message-id]

Produces:

<a href="mylink.html?user-id=5&message-id=3">My Link</a>
Use an object

The object should be preceded by the vars word.

at
  mylink.html "My Link"
  vars make object! [user-id: 5 message-id: 3]

Produces:

<a href="mylink.html?user-id=5&message-id=3">My Link</a>
Use a word/value block

The simplest method to deliver the content of the URL directly. The word/value block is preceded by vars.

Example:

at
  mylink.html "My Link"
  vars [user-id 5 message-id 3]

Produces:

<a href="mylink.html?user-id=5&message-id=3">My Link</a>

You can even mix different formats or use the same format in multiple successions. All words and values will be appended to the url. If the same word occurs twice, it will be added both times, so it's up to your webserver how this is handled in the get request.

Example:

at
  mylink.html "My Link"
  words [user-id]
  vars [message-id 3]

Produces:

<a href="mylink.html?user-id=5&message-id=3">My Link</a>

do

This runs the code inside the given block. The return value is then parsed again with html-gen and is useful for generating certain kinds of dynamic content.

Example:

do [
  either empty? data [
    "No data available, sorry."
  ][
    table rows :data
  ]
]

This produces either a text or a table, depending on whether the comedians table is empty.

loop

This loops a block of code. The return value of the looped code is parsed with html-gen, which in turn is appended to the output buffer. You can supply an optional alternate dialect block that is used on even cases, while the first is then used on odd cases.

Parsed as:

'loop integer! block-types opt ['alternate block-types]

Example:

loop 3 ["Test"]

Produces:

TestTestTest

Example:

loop 3 [div #title "Test"]

Produces:

<div class="title">Test</div>
<div class="title">Test</div>
<div class="title">Test</div>

Example where we are setting an alternative design block for even loops and the original block is now only used on odd numbered loops:

loop 3 [div #title "Odd"] alternate [div #title "Even"]

Produces:

<div class="title">Odd</div>
<div class="title">Even</div>
<div class="title">Odd</div>

traverse

Traverses an input block and for each element, inserts it in a design block that is parsed with html-gen. This way you can loop a piece of code with slightly different content in it.

Parsed as:

'traverse
  [block-types | get-word!]
  opt ['using [block-types | lit-word! | word! | get-word!]]
  block-types
  opt ['alternate block-types]

The input can be one of three formats:

  1. A block of blocks containing an identical number of elements for all blocks
  2. A block of elements that are not blocks or objects
  3. A block of objects

If the input is anything else, traverse is not guaranteed to work properly.

The input can be managed with a word or a set of words in the using block, which is similar to how REBOL's foreach function works. These words are used as get-words in the design block. You can also use the idx word to indicate the index position of the input block as it moves through the loop.

Blocks of non-block/non-object elements

Example for a single word along with the use of 'idx:

traverse
  [alpha beta gamma] using [number]
  [div #title [:idx ":" :number]]

Produces:

<div class="title">1:alpha</div>
<div class="title">2:beta</div>
<div class="title">3:gamma</div>

The more words you have in the using block, the longer it skips, so if you have two words in the block, the traverse loop will skip two elements in the input block, just like foreach.

Example:

traverse
  [alpha beta gamma delta] using [a b]
  [:idx ": " :b " " :a " "]

Produces:

1: beta alpha 3: delta gamma

Blocks of Blocks

When the input block consists of many evenly sized blocks, the word block will be set to each value in the current block.

Example:

traverse
  [[1 2 3][4 5 6]] using [title text date]
  [div #title :title div #text :text div #date :date]

Produces:

<div class="title">1</div>
<div class="text">2</div>
<div class="date">3</div>
<div class="title">4</div>
<div class="text">5</div>
<div class="date">6</div>

If the size of the blocks vary anyway, one of two conditions will occur:

  1. The word block is shorter than the input block. All words are set, while the extra values from the input block are not used.
  2. The word block is longer than the input block. All values are assigned to their word and the words that are not set, are set to none. In the output, this translate to an empty string.

Blocks of Objects

When the input block consists of objects, each word in the word block is simply bound to the current object.

Example:

traverse
  [
    make object! [
      title: "the title"
      text: "my text"
      date: 22-nov-2004
    ]
    make object! [
      title: "the second title"
      text: "my second text"
      date: 24-nov-2004
    ]
  ]
  [div #title :title div #text :text div #date :date]

Produces:

<div class="title">the title</div>
<div class="text">my text</div>
<div class="date">22-nov-2004</div>
<div class="title">the second title</div>
<div class="text">my second text</div>
<div class="date">24-nov-2004</div>

If you are using an unknown word here for the object, REBOL will fail and produce an error for an unknown word, so make sure the words you use exist in all objects in the input block.

Do Blocks inside Traverse

For all cases, you can add extra flexibility in that a do block can be bound to the entry, and so instead of using get-word! directly, you can perform actions on the data as it's being rendered into HTML.

Example:

traverse
  [[20 40][14 76]] using [a b]
  ["Number 1: " :a "Number 2: " :b "Sum: " do [a + b]]

The do block is ordinary REBOL code that is bound to the current object, which is why the words are not necessarily represented in that block as get-word!s.

Produces:

Number 1: 20 Number 2: 40 Sum: 60
Number 1: 14 Number 2: 76 Sum: 90

For all cases, you can also use a get-word! as data. Here's an example where the word numbers is set to [[20 40][14 76]]:

traverse
  :numbers using [a b]
  ["Number 1: " :a "Number 2: " :b "Sum: " do [a + b]]

Produces:

Number 1: 20 Number 2: 40 Sum: 60
Number 1: 14 Number 2: 76 Sum: 90

traverse supports using an alternate block for even numbered rows.

Example:

traverse
  [[20 40][14 76][3 27]] using [a b]
  [
    div #odd [
      "Number 1: " :a "Number 2: " :b
    ]
  ]
  alternate [
    div #even [
      "Number 1: " :a1 "Number 2: " :b
    ]
  ]

Produces:

<div class="odd">Number 1: 20 Number 2: 40</div>
<div class="even">Number 1: 14 Number 2: 76</div>
<div class="odd">Number 1: 3 Number 2: 27</div>

Nested Traverse

traverse supports using multiple loops inside eachother. Remember that for each word block, the word block is bound only to the context that resides just inside that design block and not other deeper layered design blocks. The easiest way to handle that is never to use the same word twice in both the inner and the outer loop.

This is buggy and so the example will not work.

Example:

traverse
  [
    "Photoset 1" images/thumbs
      [img1.jpg 23512 20-May-2008 img2.jpg 15922 21-May-2008]
    "Photoset 2" images/thumbs
      [img3.jpg 16508 22-May-2008 img4.jpg 52214 23-May-2008]
    "Photoset 3" images/thumbs
      [img5.jpg 28292 24-May-2008 img6.jpg 12080 25-May-2008]
  ]
  using [photoset path images]
  [
    div #title [:photoset]
    traverse :images using [image size date] [
      div #photo [
        div #image [
          image do [to-file reduce [dirize to-file :path :image]]
        ]
        div #size [:size " bytes"]
        div #date :date
      ]
    ]
  ]

Produces:

No usable result.

table

This is a complex command to produce HTML tables using various types of input blocks. The following block types are supported:

  • 1-dimensional block with any elements as content. This is rendered as a 1-column table.
  • 2-dimensional blocks (blocks of blocks) with any elements as content. This is rendered in a normal 2D table grid.
  • 1-dimensional block with objects as content. This is rendered as a 2D table using each object as a row and each word in that object as the cell content.

Whenever content for a cell is none! the table cell will be empty.

Example:

table #table-style rows [1 2 3]

Produces:

<table class="table-style" cellspacing="0" cellpadding="0">
  <tr>
    <td>1</td>
  </tr>
  <tr>
    <td>2</td>
  </tr>
  <tr>
    <td>3</td>
  </tr>
</table>

When creating a 2D table, the output is of course a 2D HTML table. Example:

table #table-style rows [[1 "foo" 3][4 5 "boo"]]

Produces:

<table class="table-style" cellspacing="0" cellpadding="0">
  <tr>
    <td>1</td>
    <td>foo</td>
    <td>3</td>
  </tr>
  <tr>
    <td>4</td>
    <td>5</td>
    <td>boo</td>
  </tr>
</table>

You are of course also not restricted to specific output sizes. For blocks that have 4 elements, 4 cells are rendered in the table. If you then only have 2 in the next row, only 2 cells are rendered.

You can describe rows across multiple sets of blocks, in case you are unable to describe them in one block or you want to split the table in multiple parts. This comes in handy, if you decide to change the table formatting midway through rendering. Similarly the first block could be a header description, while the rest is data.

Example:

table #table-style rows [1 2 3] rows [4 5 6]

Produces:

<table class="table-style" cellspacing="0" cellpadding="0">
  <tr>
    <td>1</td>
  </tr>
  <tr>
    <td>2</td>
  </tr>
  <tr>
    <td>3</td>
  </tr>
  <tr>
    <td>4</td>
  </tr>
</table>

Table Dialect

The table has its own internal dialect for table row, cell and header description. You can describe most (but not all) attributes available in a regular hand-written HTML table.

Example:

table
  rows [
    row
      cell 1
      cell width 300 2
      cell class price 3
    row
      cell colspan 3 "boo!"
  ]

Produces:

<table cellspacing="0" cellpadding="0">
  <tr>
    <td>1</td>
    <td width="300">2</td>
    <td class="price">3</td>
  </tr>
  <tr>
    <td colspan="3">boo!</td>
  </tr>
</table>

You can also write the entire table structure as words and values without framing each row in blocks. This makes it easier to create the entire table from code. Only the table, rows, row and cell words are used.

Example:

table
  rows
    row cell 1 cell width 300 2 cell class price 3
    row cell colspan 3 "boo!"

Produces:

<table cellspacing="0" cellpadding="0">
  <tr>
    <td>1</td>
    <td width="300">2</td>
    <td class="price">3</td>
  </tr>
  <tr>
    <td colspan="3">boo!</td>
  </tr>
</table>

This table dialect is both usable directly and also with the format word to specify the style of each data row in upcoming rows of data. This currently only works with block of objects, so in order to produce the examples below, I get personal help from 3 famous comedians:

comedians: reduce [
  make object! [
    first-name: "Jerry"
    last-name: "Lewis"
    fun-rating: "Funny"
  ]
  make object! [
    first-name: "George"
    last-name: "Carlin"
    fun-rating: "Funnier"
  ]
  make object! [
    first-name: "Jim"
    last-name: "Carrey"
    fun-rating: "Funny"
  ]
]

Now we can use the previously learned parts of the table dialect to produce formatted output. When producing formatted output, each object in the block is traversed and when that happens, you can get each value from the object by specifying it as a get-word!:

Example:

table
  format [row cell :first-name cell :last-name]
  rows :comedians

Produces:

<table cellspacing="0" cellpadding="0">
  <tr>
    <td>Jerry</td>
    <td>Lewis</td>
  </tr>
  <tr>
    <td>George</td>
    <td>Carlin</td>
  </tr>
  <tr>
    <td>Jim</td>
    <td>Carrey</td>
  </tr>
</table>

This output is in fact identical to:

table rows :comedians

So in order to make it more interesting, we add some formatting to the format block:

table
  format [
    row cell [div name :first-name] cell align right :last-name
  ]
  rows :comedians

Produces:

<table cellspacing="0" cellpadding="0">
  <tr>
    <td><div class="name">Jerry</div></td>
    <td align="right">Lewis</td>
  </tr>
  <tr>
    <td><div class="name">George</div></td>
    <td align="right">Carlin</td>
  </tr>
  <tr>
    <td><div class="name">Jim</div></td>
    <td align="right">Carrey</td>
  </tr>
</table>

Then we can design a header for the comedians block. This is done simply by adding a rows block at the start, and use the header word to specify the >th< tag:

table
  rows [row header "First name" header "Last name"]
  format [
    row cell [div name :first-name] cell align right :last-name
  ]
  rows :comedians

Produces:

<table cellspacing="0" cellpadding="0">
  <tr>
    <th>First name</th>
    <th>Last name</th>
  </tr>
  <tr>
    <td><div class="name">Jerry</div></td>
    <td align="right">Lewis</td>
  </tr>
  <tr>
    <td><div class="name">George</div></td>
    <td align="right">Carlin</td>
  </tr>
  <tr>
    <td><div class="name">Jim</div></td>
    <td align="right">Carrey</td>
  </tr>
</table>

We are not restricted to just one row in the table, per object:

table
  format [
    row cell :first-name cell :last-name
    row cell colspan 2 align right :fun-rating
  ]
  rows :comedians

Produces:

<table cellspacing="0" cellpadding="0">
  <tr>
    <td>Jerry</td>
    <td>Lewis</td>
  </tr>
  <tr>
    <td colspan="2" align="right">Funny</td>
  </tr>
  <tr>
    <td>George</td>
    <td>Carlin</td>
  </tr>
  <tr>
    <td colspan="2" align="right">Funnier</td>
  </tr>
  <tr>
    <td>Jim</td>
    <td>Carrey</td>
  </tr>
  <tr>
    <td colspan="2" align="right">Funny</td>
  </tr>
</table>

Row Format Options

The table format command supports different format blocks depending on which row is rendered. This is useful if decorating the table with CSS styles require different appearances depending on which row number is rendered. The words are:

firstThis the first row rendered.
oddThis is any odd row rendered.
evenThis is any even row rendered. If this is left out, the any format block is used.
odd-lastThis is rendered in case the last row is odd numbered.
even-lastThis is rendered in case the last row is even numbered.
lastThis is rendered for both even and odd last rows.
anyThis is any row that is rendered, and is only used if none of the other formatting blocks fit. By default this is the used block.

If any of these words are left out, the used block corresponds to an any format block.

Example:

table
  format
    odd [
      row cell :first-name cell :last-name
      row cell colspan 2 align right :fun-rating
    ] even [
      row cell :first-name cell :last-name
      row cell colspan 2 :fun-rating
    ]
  rows :comedians

Produces:

<table cellspacing="0" cellpadding="0">
  <tr>
    <td>Jerry</td>
    <td>Lewis</td>
  </tr>
  <tr>
    <td colspan="2" align="right">Funny</td>
  </tr>
  <tr>
    <td>George</td>
    <td>Carlin</td>
  </tr>
  <tr>
    <td colspan="2">Funnier</td>
  </tr>
  <tr>
    <td>Jim</td>
    <td>Carrey</td>
  </tr>
  <tr>
    <td colspan="2" align="right">Funny</td>
  </tr>
</table>

Debugging

Tables can be debugged by adding the debug word right after the table. This adds borders around each cell for that table by increasing the cell spacing and cell padding values.

Example:

table debug rows [[1 2 3]]

Produces:

<table cellspacing="1" cellpadding="1">
  <tr>
    <td>1</td>
    <td>2</td>
    <td>3</td>
  </tr>
</table>

Limitations

Currently table does not support tbody.

doc-types

This outputs the appropriate !DOCTYPE tag, for the given word.

Parsed as:

doc-types

Example:

html-2.0-dtd

Produces:

<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">

block!

Parses the block with html-gen.

string!

Adds the given string to the output buffer. The string is not molded.

number!

Molds the number! and adds it to the output buffer.

tuple!

Molds the tuple! and adds it to the output buffer.

money!

Molds the money! and adds it to the output buffer.

tag!

Adds the given tag to the output buffer.

word!

Adds the given word to the output buffer.

set-word!

Stores a block of code in the user-words block in the ctx-html context for later retrieval by a word.

Parsed as:

set-word! [block-types | value-types | word!]

See the using set-words! chapter earlier in this documentation for usage.

get-word!

Evaluates the word according to the context the dialect block is bound to and adds the result to the output. You can use this to specify separate HTML dialect blocks for inclusion in one big HTML block for page composition in multiple steps.

path!

Molds the path and adds it to the output buffer.

lit-path!

Molds the lit-path! as a lit-path! and adds it to the output buffer.

refinement!

Molds the refinement! and adds it to the output buffer.

binary!

Molds the binary! and adds it to the output buffer.

date!

Molds the date! and adds it to the output buffer.

time!

Molds the time! and adds it to the output buffer.

url!

Molds the url! and adds it to the output buffer.

email!

Molds the email! and adds it to the output buffer.

form

This produces the outer tags for a form, handles the input fields via an object. All inputs that exist for this form must be placed in the last block parameter for the form.

Parsed as:

'form
  cell-types
  opt [get-word! | 'vars block! | object!]
  cell-types

Example:

form :form-data [
  field name
]

hidden

This makes a hidden variable for the form.

Parsed as:

'hidden word!

field

This makes a form field. The associated word is the name of the field.

Parsed as:

'field word!

Example:

field first-name

Produces:

<input type="text" name="first-name" value="" />

password

This makes a form password field, where you can't see what you enter. The associated word is the name of the field.

Parsed as:

'password word!

Example:

password passcode

Produces:

<input type="password" name="passcode" value="" />

textarea

This makes a form text area. The associated word is the name of the text area.

Parsed as:

'textarea word!

Example:

textarea comment

Produces:

<textarea name="comment"></textarea>

select

This makes a select popup for a form. It uses a block as input for generating all its options. The current index for the block is used as the selected position.

Parsed as:

'select
  word!
  ['values | 'key-values]
  cell-types

There are two input formats available:

valuesMeans a block of values, such as [1 2 3 4]. This means the value will be sent back to the server, while the value is displayed in the select button.
key-valuesMeans a block of word/value pairs, such as [a 1 b 2 c 3]. This means the word is the one to get sent back to the server.

Example, for the case of plain values:

select countries values [
  "Switzerland"
  "Norway"
  "United States"
]

Produces:

<select name="countries">
  <option>Switzerland</option>
  <option>Norway</option>
  <option>United States</option>
</select>

Example, for the case of key/value pairs:

select countries key-values [
  ch "Switzerland"
  no "Norway"
  us "United States"
]

Produces:

<select name="countries">
  <option value="ch">Switzerland</option>
  <option value="no">Norway</option>
  <option value="us">United States</option>
</select>

checkbox

Creates a checkbox for the form. The input value for it is anything that conforms to to-logic.

Parsed as:

'checkbox word!

Example:

checkbox receive-email

Produces:

<input type="checkbox" name="receive-email" />

radio

Creates a radio button for the form. As radio buttons can occur in series and are mutually exclusive, an additional group word is needed for each radio button. The selected value is the one that is returned to the server.

Parsed as:

'radio word! cell-types

Example:

radio mode "fast"
radio mode "slow"

Produces:

<input type="radio" name="mode" value="fast" />
<input type="radio" name="mode" value="slow" />

button

Creates a form button.

Parsed as:

'button word! string!

Example:

button click "Click here"

Produces:

<input type="button" name="click" value="Click here" />

reset

Creates a form reset button.

Parsed as:

'reset string!

Example:

reset "Reset Form"

Produces:

<input type="reset" value="Reset Form" />

submit

Creates a form submit button.

Parsed as:

'submit string!

Example:

submit "Submit Form"

Produces:

<input type="submit" value="Submit Form" />

Practical Example

I'm going to build a small source code browser using the HTML dialect. What it will do, is take all *.r files in a directory and display it in an HTML table on a webpage. The example uses RSP in Cheyenne, but you can use it for any place you need to generate a web page.

First we create a source code file, code.rsp, which is where all our code for displaying the source directory will reside.

Second we define what source code to read. I will first settle for reading the directory I need and get information on each file and store that information in a source-code block:

source-code: []

For the sake of simplicity, let's say the source files we want to examine are stored in the current directory, and remove all files that are not ending with the .r extension:

files: read %.
remove-each file files [%.r <> suffix? file]

The information returned from each file is an object, containing useful information like file size and modification date. Since the HTML dialect handles blocks of objects just fine for tables, we can just loop through the directory using the info? function:

foreach file files [
  append source-code make info? file [file-name: file]
]

Next we create the page itself:

output-html [page "Code Browser" []]

Next we add the table inside the page block. The table specs are used to format the block to what we want to see for each row, or more accurately, for each object that is traversed in the input block, as the formatting is not limited to a single table row.

We describe three parts: The header, the format of the layout and then the files that need to be displayed. As the table renderer progresses, it can change the format as it moves along, every time it encounters a format or rows word. So the first row is going to be the header. The format changes the format of the following rows and the second rows provides the rest of the data.

table #file-list
  rows [row header "File Name" header "Time" header "File size"]
  format [row cell :file-name cell :date cell :size]
  rows :files

We can then add some more features, such as reading the header of each source file and scour it for information that can be displayed in the cell. This requires an extra column called "Notes":

rows [
  row
    header "File Name"
    header "Time"
    header "File size"
    header "Notes"
]

For the format column, we add the notes column by reading the file given for the file name in the current object. This is wrapped in a little block for the cell. Some files may not have a proper file header, so we want to ignore those, by wrapping the load code in an attempt and providing an alternative text string to print for those cases:

format [
  row
    cell [strong :file-name]
    cell :date
    cell align right [:size " bytes"]
    cell [
      do [
        any [
          attempt [get in first load/header :file-name 'title]
          "No notes"
        ]
      ]
    ]
]

And that's it.

If we want to add a few bits more, such as right aligned size column and bold file name, we can add that in the format block. These changes are visible in the completed source code for the code.rsp page:

do %html.r
source-code: []
files: read %.
remove-each file files [find/match file %.]
foreach file files [
  append source-code make info? file [file-name: file]
]
print output-html [
  page "Code Browser" [
    table #file-list
      rows [
        row
          header "File Name"
          header "Time"
          header "File size"
          header "Note"
      ]
      format [
        row
          cell [strong :file-name]
          cell :date
          cell align right [:size " bytes"]
          cell [
            do [
              any [
                attempt [get in first load/header :file-name 'title]
                "No notes"
              ]
            ]
          ]
      ]
      rows :source-code
  ]
]

To further change the appearance of the table, it's recommended to use CSS. As you might be able to see, the CSS class for the table is file-list.

Future

As this is a very early development version of the dialect a lot of features are missing:

  • CSS Dialect to simplify creation of CSS content.
  • Further automatization and simplification of form creation and management.
  • Stylize function similarly to VID, for customized tags with one word.