TPL Syntax Documentation. (pre release) - MrStonedOne/dmtemplate GitHub Wiki

DmTemplate .tpl Syntax Documentation

Notice: Pre-release document

The following is a pre-release document, the below spec is starting to finalize and was briefly tested against code and seems to work properly, but said code has not been fully tested, and may require further modifications to finalize. The syntax is subject to change or expansion.

The Misou branch has the code for this.

Introduction

.tpl templates files contain literal html interspersed with dynamically computed tokens.
Tokens are contained within double curly brackets {{ }}
Some tokens take arguments. These are seperated by whitespace, with quotes being used to enclose multiple words into one argument.
Some tokens take html blocks as an argument, they will read and parse the html between the token and a closing token {{/}}

Variable access

The most basic token type simply accesses dynamic data. (all other tokens start with some signifying special character.)

All template parsing starts with an associated list of data that is passed the parser by the caller, each key becomes top level variables that contain their value. eg list("mode" = "Kill", "target" = "Clowns") would set the variable mode to the string Kill and the variable target to the string Clowns.

Variable names must not start with a number or any character that byond could confuse with a number part (., -, +), as well as any of the special characters used to signify other tokens or sanitizing behavior ($, *, &, !, #, /, %). and should not contain whitespace or any of the following characters: (\, ], ,, ", }).

{{var_name}} - Inserts the contents/value of var_name at the location. Sanitizing behavior controlled at runtime based on how the parser was invoked (defaults to sanitizing as html)

{{$var_name}} - Inserts the contents of var_name at the location. sanitized as html.

{{&var_name}} - Inserts the contents of var_name at the location. sanitized as a url.

{{*var_name}} - Inserts the contents of var_name at the location. Is not sanitized (unsafe, only use if you know the value comes from a trusted or pre-sanitized source, or when you know the output is not going to be parsed by a browser)

List access

{{var_name["key"][5][other_var_name]}} - You can work with lists using roughly the same syntax as in byond.

Updating variables.

It is possible to update the values of an interface after the window has been opened by passing a new associated list of variables to the interface. Only variable accesses marked as updatable or dynamic will be updated on the client's view.

{{%var_name}} - Inserts the contents of var_name at the location, can be updated after the window opens.
**Notice: This wraps the contents in a <span> tag. If you need to use updatable variables in places where html isn't parsed (such as html attributes like <a href="?action=dothing;id={{%&var_name}}">do thing</a>), wrap the entire html tag in update blocks (see below) (eg: {{%}}<a href="?action=dothing;id={{&var_name}}">do thing</a>{{/%}})

{{%}}{{/%}} - On updates, the entire block is re-parsed. *Note: This wraps the contents in a <span> tag, only use where such tags would be valid html.

Constants

The following constants are supported for places that expect variables:

TRUE = 1
FALSE = 0
null = null

They have the same meaning as in byond.

Strings

Any place that expects a variable can take a string inside quotes.

Strings can contain embedded variable accesses using [].

Within strings the \ character can be used to escape syntax. The \n sequence is also supported.

Escaping syntax

{{"{{"}} - If you need to use double curly opening brackets within the template html without it being treated as a token start, you can place them inside a token that outputs a string.

{{!#if blah}} - For convenience, Starting a valid token with ! will cause it to be treated as an html string containing the token sans the !. ie: {{#if blah}}.

Conditionals

{{#if var_name}} {{/if}} - Parses the contents only if the value is defined, not-null, and not false. (equivalent to doing if (var_name) dostuff in byond.) (can be updatable)

{{#if! var_name}} {{/if}} - Does the reverse of the above (can be updatable)

Eg: {{#if %name}}{{name}}{{/if}}{{#if! %name}}Person{{/if}}</h2>

You can also use a limited amount of comparison operators, but you can not nest or chain them:
{{#if right operator left}}

{{#if var_name == "string constant"}} {{/if}}
{{#if var_name == 0.12}} {{/if}}
{{#if var_name >= 0.12}} {{/if}}
{{#if var_name < 0.12}} {{/if}}
{{#if var_name["key"][1] != ""}} {{/if}}
{{#if var_name & other_var}} {{/if}}

Standard operators (!=, ==, >, <, >=, <=, &, |, %, ^, in, ~=, ~!) They have the same meaning as in byond.

Non-standard operators:

list contains string - Like in but with the arguments reversed.

*Note: White space between operators, keywords, and variables/constants matter. {{#ifvar_name<0.12}} will fail to parse

{{#ifempty var_name}} {{/ifempty}} - Parses the contents if the value is an empty or invalid list. (can be updatable)

{{#ifempty! var_name}} {{/ifempty}} - Does the reverse of the above (can be updatable)

{{#if ...}}...{{#else ...}}the thing{{/if]} - Does the thing if the previous check failed, can include another check. (can be updatable)

{{#switch varname}} {{#case "value"}} {{/case}} {{case "value"}} {{/case}} {{default}}{{/default}} {{/switch}} - Switch statements. All values must be constant strings or numbers, as a hashtable is generated. (can be updatable) (does not fall through).

*Note: the {{/}} token does not parse the contents after the / character, meaning nothing keeps an {{/ifempty}} from closing an {{#if}} if the coder made a mistake. Unclosed or Unmatched conditionals however do trigger an error.

Comments

{{#if}}Comments here{{/if}} - The conditional tokens do not require any args to be passed to them, allowing you to use blank ifs as a way of inserting comments in your template that are not output to the end user.

Looping through lists (for each)

{{#foreach var_name index}} {{/foreach}} - A foreach block (Implicit form), The contents are re-parsed for each item in the list, the list must contain associated lists of variables that become top level variables for the scope of the block (overriding any variables with the same name). The index arg is optional, if given it is the name of a variable that will hold the index of the current item in the list (overriding any variables of the same name).

{{#foreach var_name index value}} {{/foreach}} - A foreach block (Explicit form), The contents are re-parsed for each item in the list. The index and value arguments are the names of variables you would like to hold the current index and the value (value = var_name[index]) inside the block.

{{#foreach var_name index key value}} {{/foreach}} - A foreach block (Explicit form), The contents are re-parsed for each item in the list. The index, key, and value arguments are the names of variables you would like to hold the current index, the key at that index (key = var_name[index]) and the value associated with that key (value = var_name[key]) inside the block.

*Note: {{#foreach}} blocks inherent from {{#ifempty!}} blocks, and are only computed if given a valid non-empty list.

*Note: All foreach blocks can be made updatable, changes of an item in the list, as well as inserts and deletions off the tail only trigger updates of the affected indexes, inserts and deletions in the middle or head of the list causes all indexes after the earliest affected index to be reparsed.

Examples:

Explicit form

{{#ifempty! message}}
	<P>You have new messages!</P>
	{{#foreach messages index message}}
		{{#if index % 2}}
			<span class="message-odd">
		{{else}}
			<span class="message-even">
		{{/if}}
		<P><b>Message</b> #{{index}}</P>
		<P><b>From:</b> {{message["author"]}}</P>
		<P><b>Contents:</b> {{message["text"]}}</P>
		<br>
		</span>
	{{/foreach}}
{{else}}
	<P>You have no new messages.</P>
{{/ifempty}}

Implicit form

{{#ifempty! message}}
	<P>You have new messages!</P>
	{{#foreach messages index}}
		{{#if index % 2}}
			<span class="message-odd">
		{{else}}
			<span class="message-even">
		{{/if}}
		<P><b>Message</b> #{{index}}</P>
		<P><b>From:</b> {{author}}</P>
		<P><b>Contents:</b> {{text}}</P>
		</span>
		<br>
	{{/foreach}}
{{else}}}
	<P>You have no new messages.</P>
{{/ifempty}}

Quirks

Because of how switch statements process numbers, the following two case statements are equal and would generate a duplicate case statement error

{{#case 5}}{{/case}}
{{#case "{{CASE_NUMBER \"5\"}}"}}{{/case}}

The following however are not considered equal:

{{#case 5}}{{/case}}
{{#case "5"}}{{/case}}
⚠️ **GitHub.com Fallback** ⚠️