DUEL Syntax

The DUEL grammar is an intentionally small, familiar syntax. Each term is intended to be intuitive to remember and is short without abbreviations. DUEL views are defined as HTML/CSS/JavaScript with a small set of special markup tags to control flow and JavaScript code blocks to bind the view template to model data.

The goal is to deliberately keep the syntax minimal. It should be easy to remember and nothing should need to be looked up during usage.

Code Blocks

DUEL code blocks contain 100% pure JavaScript, so there isn't a new language to learn. Since DUEL uses a familiar syntax for code blocks, syntax highlighting in editors is widely supported out of the box. There are three types of code blocks available:

Statement Blocks

<%/*statements*/%>

When code within a statement block is executed, if any value is returned it will be emitted as part of the output.

Expression Blocks

<%=/*expression*/%>

When code within an expression block is executed, the result of will be emitted as part of the output, interpretted as plain text. Expression blocks are effectively equivalent to:

<%return(/*expression*/);%>

HTML Expression Block

Note: these blocks are rarely needed; only when data itself contains markup. Care must be taken to avoid script injection with markup blocks.

<%# /*expression*/ %>

When code within a markup expression block is executed, the result will be emitted as part of the output, interpreted as HTML.

Data Values

index: used within all loops to indicate the item index of the current data being bound

count: used within all loops to indicate total number of items being bound

key: used within property loops to indicate the property name of the current data being bound

Command Markup

DUEL reduces potential for "tag soup" by controlling loops and conditionals declaratively through a small set of memorable markup commands. The complete set of DUEL command markup is:

View declaration

Syntax:

<viewname="…">
…
</view>

Sits at the top of a view to define its metadata. The name attribute contains a string literal which defines the name of view type. This optionally may have a close tag at the end of the view.; open views will be auto-closed by the compiler.

A rarely used feature of this tag is for defining multiple views in the same file. By closing the </view> tag and opening another, a second named view may be defined.

This tag is the only child of the file, and may only sit at the root. Views may not be nested, although they may call into one another (See the <call /> command).

Example:

<viewname="example.Foo"><p>Hello world.</p>

Looping and iteration

Array iteration

Syntax:

<foreach="…">
…
</for>

Wrapped around content to be repeated once per item. The each attribute contains an Array expression defining the list of items to iterate over. The data value will contain the current item, and the index and count values will be updated with the current item index and total item count, respectively.

If the each attribute does not contain an Array expression, the loop will treat it as if it were the first item in an Array.

Example:

<ul><foreach="data.items"><li>Item <%=data%> is <%=index%> of <%=count%>.</li></for></ul>

Property iteration

Syntax:

<forin="…">
…
</for>

Wrapped around content to be repeated once per property. The in attribute contains an Object expression, and the loop will iterate over the properties of that object. In this case, data will contain the property value and an additional key value will contain the (String) property name. The index and count values will be updated with the current property index and total count of properties, respectively.

Example:

<ul><forin="data.foo"><li>Property named <%=key%> has the value <%=data%> and is <%=index%> of <%=count%>.</li></for></ul>

Counting iteration

Syntax:

<forcount="…"data="…">
…
</for>

Wrapped around content to be repeated count number of times. The count attribute contains a Number expression, and the loop will iterate that number of times. If the data attribute is not specified, data will contain the outer scope's data value otherwise it will contain the result of the data attribute expression. The index and count values will contain the current index and the result of the count attribute expression, respectively.

Example:

<ul><forcount="4"data="data.foo"><li>The same <%=data%> for <%=index%> of <%=count%> items.</li></for></ul>

Conditional logic

Conditional blocks

Syntax:

<iftest="…">
…
<elseif="…">
…
<else>
…
</if>

Wrapped around conditional content. The test attribute contains a boolean expression indicating if contents should be included in result. Any truthy value will cause the contents of that section to be emitted.

<else> tags sit inside an <if></if> block as dividers without closing tags (similarly to <hr> and <br> in HTML). The if attribute contains a boolean expression indicating if contents should be included in result. Alternatively, <else test="…"> may be used for symmetry with <if test="…">.

Example:

Embed other views

Syntax:

<callview="…"data="…"key="…"index="…"count="…"defer/>

Calls another template specifying the data to bind. The view attribute is the name of the view to bind, the data attribute defines the data to bind. Optionally key, index and count attributes may be passed through if the view is being called within a loop (e.g. item index of count items).

The defer attribute is an optional mechanism to express that the call should be deferred and executed client-side.

Example:

<callview="example.Bar"data="data.details"/>

Partial views

Syntax:

<partname="…">
…
</part>

Sits inside a view as a placeholder for replacement content, or within a <call></call> block to define the replacement content. The name attribute is a string expression specifying the name of the part to replace.

Example:

Command Arguments

A shorthand syntax is available for the attributes of markup commands. The attributes in each of the markup elements are implicitly code blocks. This means you can add or leave off the code block syntax based on preference: