|
HTMLB extends plain HTML4 with 11 tag families. They work in any browser that supports HTMLB and on any normal HTTP host. Full client-side, no server code required.
| Tag |
Purpose |
Go to |
| <variable> | store and recall text variables | details |
| <urlparam> | read ?key=value from the URL | details |
| <calc> | math and text operations | details |
| <if> | show or hide content by condition | details |
| <switch> / <case> | multi-way choice | details |
| <template> / <call> / <param> | reusable blocks with parameters | details |
| <moddoc> | modify another element by id | details |
| <include> | include file, plain or HTML+HTMLB, scoped | details |
| <rmws> | remove whitespace around the tag | details |
| <style for> | style rules for elements, classes and ids | details |
| <user> | browser user agent and current date/time | details |
| attribute expansion | use tags inside quoted attributes | details |
|
How to read this page: each tag shows syntax, then a table of attributes, then a short example you can copy. All tags are case-insensitive but variable names and urlparam keys are case-sensitive.
|
Attribute Expansion - Tags Inside Attributes
Any attribute (quoted or unquoted) can contain these self-closing tags. The browser replaces the tag with its text value before using the attribute.
| Allowed inside attributes |
| <variable> <urlparam> <calc> <call> <param> <user> |
Rules: attribute values are entity-decoded and trimmed first, then expanded. Tag names are case-insensitive. Works in quoted and unquoted attributes, on any tag including <variable> itself (for example to, name, default, a/b/c all expand nested tags first).
- Quoted: text mixed with multiple tags. Example: href="page.html?n=<urlparam name='n'/>-<calc a='1' b='2' op='+'/>".
- Unquoted: exactly one whole tag, no concatenation. Example: <call template=test html=<urlparam name=test>> works, but a=<urlparam name='x'/>-hi stays literal.
- Never <include>: not allowed inside attributes (it would leak files into URLs). Any other non-listed tag is copied verbatim, and a stray < stays literal.
- Short form (quoted only): if the quoted value ends inside a whitelisted tag before its >, a virtual close is assumed and the tag still runs. Example: href="<urlparam name='next'" means href="<urlparam name='next'/>". Only at end of value, only whitelisted tags, under 2048 chars.
- Missing variable: a pure <variable get> of a not-yet-set variable (and a bare tag with neither get nor set) stays literal for a later pass, so forward references work. Anything with set runs immediately (get wins if both present).
- Up to 64 tags per attribute, nesting depth 64. More than 64 are left as plain text. Substituted values, <calc> strings and attribute text results are cut at 64K.
- <call> in attributes is plain text: template markup is resolved, then tags are stripped, whitespace runs collapse to one space and trim, script/style/textarea content is dropped, leftover value tags (<urlparam> etc.) are evaluated inline, and your own <b> stays literal without rescanning (max 256 tags stripped).
- Works on any tag. Example: <a>, <img>, <variable> itself.
|
Examples
<a href="<urlparam name='next' default='index.html'/>">Next</a>
<img src="avatar.png" alt="<variable get='username'/>">
<variable set="who" to="<urlparam name='name' default='Guest'/>">
<p>Hello, <variable get="who"/>!</p>
<calc a="<param name='x'/>" b="10" op="+">
<!-- mixed text + two tags (quoted) -->
<a href="page.html?n=<urlparam name='n' default='1'/>-<calc a='1' b='2' op='+'/>">next</a>
<!-- unquoted: exactly one tag -->
<call template=test html=<urlparam name=test>>
<!-- short form: virtual close at end of quoted value -->
<a href="<urlparam name='next' default='index.html'">Next</a>
<!-- call becomes plain text (tags stripped, spaces collapsed) -->
<template name="hi" params="who">Hello <b><param name="who"/></b></template>
<a title="<call template='hi' who='Bob'/>">link</a> <!-- title is: Hello Bob -->
<!-- never include, non-whitelisted stays verbatim -->
<a href="<b>hi</b>">link</a> <!-- value keeps <b>hi</b> literally -->
Notes: non-whitelisted tags are copied verbatim, not stripped. A stray < that is not a tag stays literal. Tag names are case-insensitive, but variable names stay case-sensitive. Nested attributes expand first, so to="<urlparam ...>" stores the resolved text.
|
1. <variable> - Variables
Store text once and reuse it. Variables live only for the current page load and are case-sensitive.
Set: <variable set="name" to="value">
Set global: <variable set="name" to="value" global>
Get: <variable get="name">
| Attribute | Required | What it does |
| set | for setting | name of the variable to create or overwrite |
| to | for setting | value to store. Can contain expanded tags like <urlparam> |
| get | for getting | name to read. Prints nothing if not found. get has priority if both get and set are present. |
| global | no | if present, variable escapes <include> scope and persists globally. Without it, child <include> reads parent but writes are local (function-like). |
Example
<variable set="title" to="Hello World">
<h1><variable get="title"/></h1>
<p>Title is: <variable get="title"/></p>
<!-- with urlparam -->
<variable set="who" to="<urlparam name='user' default='Stranger'/>">
<p>Hello, <variable get="who"/>!</p>
Notes: setting prints nothing. Getting a missing name prints nothing. Names are case-sensitive: who and Who are different. Scope: <include type="text/html"> creates a new variable scope, child can get parent vars, but set without global is discarded on return. Use global to modify parent/global.
|
2. <urlparam> - Read the URL Query String
Reads ?key=value&other=123 from the page URL, or from the enclosing <include src="page.html?key=value"> query string. Handles percent-encoding and plus signs. Inside <include> without ?key it falls back to parent <include> and then main page URL.
<urlparam name="key" default="fallback" valid="a?b?c" separator="?">
| Attribute | Required | What it does |
| name | yes | query key to look up (decoded before comparison, so %20 matches space) |
| default | no | value if key is missing, or if valid rejects it. If omitted, empty. |
| valid | no | allow-list. Split by separator. If value not in list and not empty, use default. |
| separator | no | string that separates valid entries. Default is ?. Trimmed spaces, exact case match. |
Examples
<!-- page.html?name=Alice -> Alice -->
<p>Hi <urlparam name="name" default="Guest"/></p>
<!-- allow only these pages -->
<urlparam name="page" default="home" valid="home?about?contact" separator="?">
<!-- custom separator -->
<urlparam name="color" default="blue" valid="red,green,blue" separator=",">
<!-- inside an attribute -->
<a href="<urlparam name='next' default='index.html'/>">Next page</a>
<!-- with include: page.html includes header -->
<include src="header.html?name=Bob" type="text/html">
<!-- inside header.html: Hi <urlparam name="name" default="Guest"/> → Hi Bob -->
<!-- header without ?name falls back to page.html?name -->
Decoding: + becomes space, %20 becomes space, %3D becomes =. Empty value (?key=&) is returned as empty and is not rejected by valid. Inside <include> the query is taken from src="?key=value" first.
|
3. <calc> - Math and String Operations
One tag for both numbers and text. Use op to choose the operation. Prints 0 on bad input, divide-by-zero, or invalid operator.
<calc a="10" b="3" op="+" > <!-- math -->
<calc a="hello" op="upper"> <!-- text -->
<calc a="hello world" b="6" c="5" op="substr">
<calc a="a-b-c" b="-" c="_" op="replace">
| Attribute | What it does |
| op | required. One of: + - * / % ^ (math) or len upper lower substr replace match search rand (text, case-insensitive, no aliases) |
| a | first value. Required for all ops. For len/upper/lower it is the string. For substr, replace, match and search it is the source text. |
| b | second value. Required for math ops. For substr it is start index (characters, 0-based, negative counts from end). For replace, match and search it is the search pattern (plain words match literally, see regex note below). |
| c | for substr: length in characters (omit to go to end). For replace: replacement text, used literally (omit to delete matches). For search: 1-based number of the match to return (omit for the first match). |
| op | Example | Result |
| + | <calc a="10" b="3" op="+"> | 13 |
| - | <calc a="10" b="3" op="-"> | 7 |
| * | <calc a="10" b="3" op="*"> | 30 |
| / | <calc a="10" b="4" op="/"> | 2.5 (always decimal) |
| % | <calc a="10" b="3" op="%"> | 1 (fmod for decimals) |
| ^ | <calc a="2" b="8" op="^"> | 256 (pow) |
| len | <calc a="hello" op="len"> | 5 (UTF-8 characters, not bytes) |
| upper | <calc a="hello" op="upper"> | HELLO |
| lower | <calc a="HELLO" op="lower"> | hello |
| substr | <calc a="hello world" b="6" c="5" op="substr"> | world |
| replace | <calc a="a-b-c" b="-" c="_" op="replace"> | a_b_c (all occurrences) |
| match | <calc a="hello123" b="\d+" op="match"> | 1 if the pattern matches, else 0 |
| search | <calc a="a1b22c333" b="\d+" c="2" op="search"> | 22 (2nd match, empty if none) |
| rand | <calc a="1" b="100" op="rand"> | random integer 1-100 (inclusive) |
More replace examples
<calc a="hello 123 world 456" b="\d+" c="#" op="replace"> <!-- hello # world # -->
<calc a="a1b22c" b="[0-9]+" op="replace"> <!-- abc (no c = delete) -->
<calc a="a.b.c" b="\." c="-" op="replace"> <!-- a-b-c (escape the dot) -->
<calc a="foo boo" b="o+" c="0" op="replace"> <!-- f0 b0 -->
How it works: a is the source, b the search pattern, c the literal replacement. Case-sensitive, byte-oriented, all occurrences replaced. Plain words match literally; these are regex and must be escaped with backslash to match literally: . ^ $ * + ? [ ] plus \d \w \s classes and [a-z] ranges. Empty or invalid b returns a unchanged.
Entities: attribute values are decoded twice (page load, then attribute), so to replace with the 4 characters < write c="&amp;lt;" in source. A replacement of only spaces is trimmed to empty (use a visible character instead).
|
Match and search (op="match" / op="search")
<calc a="hello123" b="\d+" op="match"> <!-- 1 -->
<calc a="hello" b="\d+" op="match"> <!-- 0 (no match) -->
<calc a="a1b22c333" b="\d+" op="search"> <!-- 1 (first match) -->
<calc a="a1b22c333" b="\d+" c="2" op="search"> <!-- 22 (2nd match) -->
<calc a="a1b22c333" b="\d+" c="9" op="search"> <!-- empty (only 3 matches) -->
Same patterns as replace (case-sensitive, byte-oriented substring search, same regex syntax). match prints 1 when the pattern is found, else 0. search prints the matched text itself, or empty when nothing is found. c picks which match to return, 1-based (omit for the first). Bad c (non-numeric, below 1, past the last match), missing a, or empty/invalid b prints empty (match prints 0 instead).
|
Random numbers (op="rand")
<calc a="1" b="6" op="rand"> <!-- dice -->
<calc a="100" b="1" op="rand"> <!-- same as 1 to 100 (auto swapped) -->
<calc b="10" op="rand"> <!-- 0 to 10 (missing a = 0) -->
<calc op="rand"> <!-- 0 to 100 (both missing) -->
a is the lowest value, b the highest (both inclusive). Missing a means 0, missing b means 100. Empty or non-numeric bounds print 0. Range is inclusive, 64-bit values. Any page using rand is marked uncacheable.
|
More substr examples
<calc a="hello world" b="0" c="5" op="substr"> <!-- hello -->
<calc a="hello world" b="-5" op="substr"> <!-- world (negative start)-->
<calc a="hello world" b="6" op="substr"> <!-- world (to end) -->
<calc a="abc" b="10" op="substr"> <!-- empty (past end) -->
Numbers: integers use 64-bit, decimals use double and print with %g. Math with two integers stays integer except / and ^ which are always decimal.
|
4. <if> - Conditionals
Show or hide the content inside based on a value. All listed conditions must be true (AND). Use not to flip the result.
<if value="..." eq="..." gt="..." lt="..." gteq="..." lteq="..." empty not img htmlb>
... content shown if true ...
</if>
| Attribute | What it checks |
| value | required (unless img or htmlb is used). The value to test. Usually from a variable: value="<variable get='x'/>". If missing, hides content. |
| eq or equal | true if value equals this text exactly |
| gt | true if value > this (numbers; falls back to decimal) |
| lt | true if value < this |
| gteq | true if value >= this |
| lteq | true if value <= this |
| empty | present = true if value is empty. Combine with not to test "not empty". |
| not | present = flip result of all conditions |
| img | present = true if the browser can show images (graphical mode with images on). Ignores all other checks except not. Combine with not for the text-only fallback. |
| htmlb | present = always true in HTMLB browsers. Use not htmlb for fallback content shown in ordinary browsers. img and htmlb together must both be true (AND). |
Examples
<!-- default = not empty -->
<if value="<variable get='name'/>">
Hello <variable get="name"/>!
</if>
<!-- exact match -->
<if value="<urlparam name='page'/>" eq="admin">
Secret panel
</if>
<!-- number -->
<if value="<variable get='score'/>" gteq="100">
You win!
</if>
<!-- empty / not empty -->
<if value="<variable get='email'/>" empty>
Please enter email
</if>
<if value="<variable get='email'/>" not empty>
Email OK
</if>
<!-- AND: both must match -->
<if value="<variable get='role'/>" eq="editor" not empty>
...
</if>
<!-- text-only fallback -->
<if not img>
.--.
/ o o \
| ^ |
\_-_/
</if>
<if img>
<img src="logo.png" alt="Logo">
</if>
<!-- fallback for browsers without HTMLB -->
<if not htmlb>
<p>This page needs an HTMLB browser for the full version.</p>
</if>
<if htmlb>
<p>Full HTMLB content here.</p>
</if>
If no operator is given, the test is "not empty". Multiple operators are AND. Bad numbers make numeric checks false.
|
5. <switch> / <case> - Multi-Way Choice
Cleaner than many <if> tags. First matching <case> is shown.
<switch value="...">
<case if="a?b?c" separator="?"> ... </case>
<case default> ... </case>
</switch>
| Tag | Attributes |
| <switch> | value - text to test (often value="<urlparam name='x'/>" or a variable) |
| <case> | if="a?b?c" - list of values that match, split by separator (default ?, trimmed, exact case). default alone = catch-all if nothing matched before. If neither, hides content. |
Examples
<switch value="<urlparam name='lang' default='en'/>">
<case if="en">Hello!</case>
<case if="fr">Bonjour!</case>
<case if="es?pt" separator="?">Hola!</case>
<case default>Hello (unknown)</case>
</switch>
<!-- with variables -->
<variable set="role" to="<urlparam name='role' default='guest'/>">
<switch value="<variable get='role'/>">
<case if="admin">Admin panel</case>
<case if="editor?author" separator="?">Editor tools</case>
<case default>Guest view</case>
</switch>
Max 16 nested switches. A default shows only if no earlier case matched. The <switch> itself stays visible, so stray text inside it outside any <case> will show.
|
6. <template> / <call> / <param> - Reusable Blocks
Define a block once, call it many times with different values. No JavaScript.
Define: <template name="card" params="title, body"> ... </template>
Call: <call template="card" title="Hi" body="Hello world">
Inside: <param name="title">
| Tag | Attributes |
| <template> | name required - template name. params="a, b, c" optional - comma-separated param names (spaces trimmed, empty ignored). Block content is hidden until called. |
| <call> | template required - name to call. Any other attribute is a param value: title="Hi" sets <param name="title"> to Hi. Self-closing. |
| <param> | name required - prints the matching <call> attribute, or a <variable> with same name as fallback. Also works inside a tag attribute: <a href="<param name='url'/>">. Self-closing. A bare <param> in body position splices its value raw into the page (parsed as HTML, see below); inside attributes it stays text. Add plaintext (no value) to print the value as text even in body position: passed tags (e.g. <urlparam>) are evaluated once to fetch the value, then the result is printed literally and never re-evaluated or parsed. |
Examples
<template name="card" params="title, body">
<table border="1" cellpadding="8">
<tr><td><b><param name="title"/></b><br><param name="body"/></td></tr>
</table>
</template>
<call template="card" title="Hello" body="Welcome to HTMLB">
<call template="card" title="About" body="No JS needed">
<!-- param inside an attribute -->
<template name="btn" params="url, label">
<a href="<param name='url'/>"><param name="label"/></a>
</template>
<call template="btn" url="index.html" label="Home">
<!-- nesting: template can call another -->
<template name="inner" params="x">Value: <param name="x"/></template>
<template name="outer" params="x">Outer <call template="inner" x="<param name='x'/>"></template>
<call template="outer" x="hi">
Notes: templates are collected before page render and removed from output. Unknown template prints nothing. Up to 500 nested calls. Values over 64K are cut. A call value containing a tag (e.g. x=<calc op=rand>) is evaluated once per call: every <param> for it sees the same result. <param> outside a call prints the variable with same name.
|
Text by default, HTML by position
Substituted values are text by default and are never parsed as markup: direct <urlparam>, <variable get>, <calc> and <param> output print literally, and values passed through <calc> attributes stay text too. Nested HTMLB tags inside values (<urlparam>, <calc>, set <variable>) are still evaluated to their text result before splicing.
To deliberately render a value as markup, put a bare <param> in body position inside the template: its value is spliced raw into the page source and parsed as HTML. Position decides, not content. To force text even in body position, add plaintext: <param name="html" plaintext/> evaluates nested tags in the passed value once (so <urlparam> resolves), then prints that result byte-for-byte — a one-tag equivalent of the escape template below. Inside <textarea> (whose content is copied raw) the value is spliced raw so the field shows it literally.
<!-- safe default: ?test=<b>hi</b> shows literally -->
<form method="get">
<urlparam name=test>
<textarea name="test" value=""><urlparam name=test></textarea>
<input type="submit"/>
</form>
<!-- opt-in: same value renders as markup -->
<template name="test" params="html">
<param name="html"/>
<form method="get">
<textarea name="test" value=""><param name="html"/></textarea>
<input type="submit"/>
</form>
</template>
<call template=test html=<urlparam name=test>>
Security: only pass trusted or generated content to body-position params. A query value containing </textarea> would break out of the field. Escape untrusted input first with replace:
<template name="escape_html" params="html"><calc a=<param name="html"> b="<" c="&amp;lt;" op="replace" /></template>
<call template="escape_html" html=<urlparam name="test"> />
<!-- ?test=<b>hi</b> prints as text: <b>hi</b> -->
|
7. <moddoc> - Modify Another Element by ID
Insert or replace content inside or around any element that has an id. The <moddoc> block itself is removed.
<moddoc for="targetId" insert inside at="start"> ... </moddoc>
<moddoc for="targetId" replace> ... </moddoc>
| Attribute | What it does |
| for | required. id of target element. |
| replace / insert | choose mode. replace deletes old inner content and puts new in its place. insert keeps old content. Default is insert. If both present, replace wins. |
| inside / outside | only for insert. inside = within the target tags. outside = before/after the whole element. Default inside. |
| at | only for insert. at="start" = before inner content (or before element if outside). at="end" or omitted = after. |
Examples
<div id="main">Original content</div>
<!-- add at end inside -->
<moddoc for="main" insert inside at="end">
<p>Added at bottom</p>
</moddoc>
<!-- add at start inside -->
<moddoc for="main" insert inside at="start">
<p>Added at top</p>
</moddoc>
<!-- insert outside -->
<moddoc for="main" insert outside at="start">
<p>Before the div</p>
</moddoc>
<!-- replace everything inside -->
<moddoc for="main" replace>
<p>Completely new content</p>
</moddoc>
If id not found, nothing happens. Multiple <moddoc> blocks run in document order. Self-closing targets (like <img id="x">) have empty inner content.
|
8. <include> - Include Files
Insert another file. With type="text/html" the file is parsed as HTMLB (scoped); without type it is inserted as plain text (escaped, no HTML/HTMLB).
<include src="header.html" type="text/html" />
<include src="header.html?name=Bob" type="text/html" />
<include src="notes.txt" /> <!-- plain, no type -->
<include src="https://example.com/data.html" /> <!-- plain, HTML escaped -->
| Attribute | What it does |
| src | required. Path or URL to file. Relative to current page URL (via join_urls). Supports file://, http://, https://, or plain path. May contain ?key=value query, used for <urlparam> inside the included file. Percent-decoded for local files. |
| type | if type="text/html" → file is parsed as HTMLB (templates, variables, conditionals). Otherwise → plain text: all < & > escaped, no HTMLB. Even text.html without type is plain. |
Examples
<!-- plain vs HTMLB -->
<include src="text.txt" /> <!-- verbatim, no HTMLB -->
<include src="text.html" /> <!-- verbatim, no HTMLB even though .html -->
<include src="header.html" type="text/html" /> <!-- HTMLB expanded -->
<!-- urlparam via src query (isolated with fallback) -->
<include src="greeting.html?name=James" type="text/html" />
<!-- inside greeting.html: <urlparam name="name" default="Guest"/> → James -->
<!-- greeting without ?name falls back to parent/main ?name -->
<!-- variable scope (function-like) -->
<variable set="x" to="outer">
<include src="inner.html" type="text/html" /> <!-- inner: <variable set="x" to="inner"> -->
<variable get="x"/> <!-- still outer (child writes don't leak) -->
<variable set="y" to="1" global> <!-- with global → persists -->
<!-- old layout pattern (still works) -->
<include src="base.html" type="text/html" />
<moddoc for="content" replace>
<p>Page-specific content</p>
</moddoc>
Scope: each type="text/html" include gets its own variable/urlparam scope. Child can get parent vars, but set without global is discarded on return. urlparam reads src="?query" first, then parent, then main page. Plain includes are fully escaped and support https:// (e.g. google.com) as source. Recursion up to 8 levels, 16 MB limit.
|
9. <rmws> - Remove Whitespace
Joins the text before and after the tag with no gap: it drops the pending space and skips the whitespace that follows it. Self-closing, no attributes. Useful inside <template> loops to glue separators without the line-break gaps left by source formatting.
<rmws>
Examples
<!-- without rmws the newline before the comma shows as a space: "0, 1" -->
<template name="loop" params="i,limit">
<param name="i"/>
<if value="<param name='i'/>" lt="<param name='limit'/>">
<rmws>,
<call template="loop" i="<calc a='<param name='i'/>' b='1' op='+'/>" limit="<param name='limit'/>">
</if>
</template>
<call template="loop" i="0" limit="3"> <!-- 0, 1, 2 -->
Notes: the effect ends as soon as real text is printed or at a line break. No effect inside <pre>-style blocks or inside hidden content (<if> false branch).
|
10. <style for> - Style Rules
Define presentation rules once without CSS, they apply to the elements that follow. Unlike the block <style> tag, the self-closing form with for is processed and stored in memory.
<style for="h1" color="green" />
<style for="img" bgcolor="red" />
<style for=".note" align="center" />
<style for="#main" bgcolor="#FFFFE0" />
<style for="h1, h2, .note" color="green" />
| Selector (for) | Matches |
| h1 | tag name, any tag, case-insensitive (h1, img, footer, ...) |
| .note | one whitespace-separated class token, case-sensitive |
| #main | exact element id |
| h1, h2, .note | comma-separated list: the rule matches if any selector matches. Spaces around commas are ignored, empty entries skipped. Tags, classes and ids can be mixed. |
| Property | What it does |
| color | text color: name (green) or hex (#008000). Applies to text elements and image alt text. |
| bgcolor | background color. Native bgcolor attributes work only on body table tr td th (HTML standard), the rule adds it elsewhere: text and full-line background on blocks (div p footer ...). |
| size | font size 1-7 on text elements, absolute (4) or relative (+1 -1). On hr it is rule thickness, on input field width in characters. Not used on textarea select option button (they use cols/rows). |
| face | font face name. |
| align | left right center justify (plus top middle bottom on images in graphics mode). |
| width | only where the element supports it: img table hr td th (percentages where supported). Ignored elsewhere, e.g. on h1. |
Examples
<style for="h1" color="green" />
<h1>This heading is green</h1>
<h1 color="red">Explicit wins: this one stays red</h1>
<style for="img" width="100" />
<img src="a.png" alt="100 wide">
<style for=".note" align="center" bgcolor="yellow" />
<p class="note">Centered on yellow</p>
<style for="#main" bgcolor="#FFFFE0" />
<div id="main">Warm background</div>
<!-- unknown elements (footer header nav section ...) get a
style scope when a rule matches, closed by </footer> -->
<style for="footer" align="center" />
<footer>Centered footer</footer>
<!-- one rule for several targets: any match applies -->
<style for="h1, h2, .note" color="green" />
<h1>Green</h1>
<h2>Green too</h2>
<p class="note">Green as well</p>
Rules: the tag must be self-closing (/>), a block <style for=...> without it hides content like plain <style>. A rule affects only elements after it. for accepts a comma-separated list (h1, h2, .a, #b); one rule then covers every listed target and counts as a single rule for last-wins resolution. When several rules match one element, the last one wins per property; an explicit attribute on the element itself always beats any rule. Rules live for the page load only. Values can contain expanded tags, e.g. color="<variable get='c'/>". Colors need a color-capable session, same as native attributes.
|
11. <user> - User Agent and Date/Time
Print plain-text information about the visitor's browser: the user agent string, or the current date and time in any format. Self-closing, no content. Also works inside quoted attributes.
<user what="agent" />
<user what="datetime" format="%Y-%m-%d %H:%M:%S" />
| Attribute | Required | What it does |
| what | yes | required, case-insensitive. agent prints the browser user agent: the configured fake user agent when one is set, otherwise Links (version; system). datetime prints the current local time formatted with format. Missing or any other value prints nothing. |
| format | no | only for what="datetime". A strftime format string, e.g. %Y-%m-%d for the date, %H:%M for the time. Missing or empty means %Y-%m-%d %H:%M:%S. Cut at 128 characters. |
Examples
<p>You are using: <user what="agent"/></p>
<p>Today is <user what="datetime" format="%Y-%m-%d"/></p>
<p>The time is <user what="datetime" format="%H:%M"/></p>
<p>Stamp: <user what="datetime"/></p> <!-- default format -->
<!-- case does not matter -->
<p><user what="DateTime" format="%d.%m.%Y"/></p>
<!-- inside an attribute -->
<a href="log.html?agent=<user what='agent'/>">Log my visit</a>
<!-- with if: show a message in the morning -->
<if value="<user what='datetime' format='%H'/>" lt="12">
<p>Good morning!</p>
</if>
Notes: output is plain text, never parsed as markup. Useful format codes: %Y year, %m month, %d day, %H hour, %M minute, %S second, %A weekday name. The clock is the visitor's local time and changes on every page load.
|
Complete Example - Putting It Together
A greeting page that uses variables, url params, calc, and templates - no JavaScript.
<template name="greeting" params="name, count">
<p>Hello, <param name="name"/>!</p>
<p>Name length: <calc a="<param name='name'/>" op="len"></p>
<p>Visits: <param name="count"/></p>
</template>
<variable set="who" to="<urlparam name='user' default='Guest'/>">
<variable set="n" to="<calc a='<variable get="n"/>' b='1' op='+'>">
<call template="greeting" name="<variable get='who'/>" count="<variable get='n'/>">
<switch value="<variable get='who'/>">
<case if="Admin"><p>Admin panel here</p></case>
<case default><p>Guest view</p></case>
</switch>
<if value="<variable get='who'/>" not empty>
<p>Welcome back!</p>
</if>
|
Limits and Notes
| Limit | Value |
| File fetch for include | 16 MB max, 15s timeout, 8 levels for include (4 for legacy extends) |
| Attribute expansion tags | 64 per attribute, nesting depth 64 |
| Calc string output | 64 K max (cut if longer) |
| Template nesting | 500 calls deep, 64 K output per call |
| Switch nesting | 16 deep |
| Variable/include scope | 16 deep, function-like (global flag escapes) |
| Style rules | 256 max per page, values cut at 1024 chars |
| User datetime format | 128 chars max, default %Y-%m-%d %H:%M:%S when missing or empty |
| All tags stop on bad input | they print 0 or nothing, never break the page |
Top | Back to Home | View Source Code
|