DocsCLIPlaygroundRoadmapAbout

Introduction

ftHTML is an HTML preprocessor built with basic webpages in mind to simplify markup and modularize elements. ftHTML supports 'forward typing syntax', importing other ftHTML files, variables, functions, macros and basic templates.

ftHTML is to HTML like what SASS is to CSS.

Even though ftHTML is a preprocessor, it also completely supports a static-driven development cycle. You can develop offline and take advantage of a CLI to convert all ftHTML files to static HTML resources.

ftHTML is intended for all skill levels and all project scopes. It's easy to setup understand and transition from regular HTML, yet it's powerful enough for seasoned developers who love modularizing their workspace and using variables, directives and templates.

Forward Typing Syntax

Self-proclaimed 'forward-typing syntax' is our effort in doing our best to eliminate the need to press the backspace or spend valuable time typing special characters for tags to maintain a forward momentum. Without the use of something like emmet, typing the same identifier twice feels ambiguous, especially when doing it countless times. ftHTML aims to remove the need to do this:

<div>...</div>

by simply doing this: 

div "..."

It's also the intent that the flow of typing is focused on things that matter, not unnecessary special characters.

Variables

ftHTML variables are a way of streamlining your most commonly used snippets. Variables can be defined, even globally, and then used in your markup to easily re-use information, elements, layouts, attributes and more.

To define variables simply wrap their declarations and assignments in a vars pragma:

#vars

  animatedButtonClass 'btn btn-primary btn-lg animated'

  navLinks
    '<nav>
        <li><a href="home">Home</a></li>
        <li><a href="portfolio">Portfolio</a></li>
        <li><a href="about">About</a></li>
        <li><a href="contact">Contact</a></li>
     </nav>'

#end

You can then reference them in your markup, prefixing the variable name with an @ symbol:

body
{
  header @navLinks

  main
  {
    button (#backBtn .@animatedButtonClass) "Click Me!"
    button (#forwardBtn .@animatedButtonClass) "Click Me Too!"
  }

  footer @navLinks
}
<body>

  <header>
    <nav>
      <li><a href="home">Home</a></li>
      <li><a href="portfolio">Portfolio</a></li>
      <li><a href="about">About</a></li>
      <li><a href="contact">Contact</a></li>
    </nav>
  </header>

  <main>
    <button id="backBtn" class="btn btn-primary btn-lg animated">Click Me!</button>
    <button id="forwardBtn" class="btn btn-primary btn-lg animated">Click Me Too!</button>
  </main>

  <footer>
    <nav>
      <li><a href="home">Home</a></li>
      <li><a href="portfolio">Portfolio</a></li>
      <li><a href="about">About</a></li>
      <li><a href="contact">Contact</a></li>
    </nav>
  </footer>

</body>

Variables' values can be strings with raw HTML or can be ftHTML Blocks or Macros or functions!

Importing

You can easily import other .fthtml files into your markup by using the import keyword. Importing expects the file to have ftHTML syntax and to be local in some fashion, meaning no HTTP urls.

Importing can modularize your directory, encourages reusability and simplifies your markup to be human-readable friendly. This also assists in keeping your markup in one convenient location should the chance arise you need to alter it, you would only have to make those changes in one place, one time.

For example, should all your files share the same header, we can define it in a specific file like the following examples:

CLI

ftHTML comes complete with a feature-heavy command line interface (CLI). The CLI is why this is recommended to be installed globally to take advantage of its features

The CLI allows you to easily convert .fthtml files to static resources with just a single command. You can convert entire directories or individual files. You can omit entire directories, as well to ensure efficient and prompt conversions.

A simple example of converting any .fthtml files in the root directory:

C:\ProjectName> fthtml convert ./

Node.js

It's highly recommended to install this globally to take advantage of the CLI features

> npm i -g fthtml

Usage

const ftHTML = require('fthtml');
ftHTML.renderFile('index')
      .then(html => console.log(html))
      .catch(console.log);

Getting Started

After you have installed ftHTML to your workspace globally, it’s time to think about file structure.

Although everyone has personal preferences when building file structures, we encourage those to maintain their preferences as it has no bearing on how ftHTML works. However, we have found that the best way to navigate and build out a folder structure is to keep it segregated from the HTML, and the other static files entirely. We found this works best because it doesn’t matter if you have a static driven project or a more dynamic project with something like expressjs; it all flows just as fluid.

We recommend having ftHTML concepts in your dev folder with a dedicated ftHTML folder. We would recommend that folder to contain an imports dir as well, just to hold templates and frequently imported files.

Take the following Hello World project example with a root dir called ‘HelloWorld’:

HelloWorld
\__.dev\
    \__.ftHTML\
        \__imports\
            —header.ftHTML
            —footer.ftHTML
        —index.ftHTML
    \__css\
        -main.css
\__www
  \__css\
      —main.min.css

The benefit here is when you convert all your .ftHTML files, provided you are using a static driven development cycle, it’s easier syntax when it comes to importing and templating calls. The benefit of dynamic development using something like expressjs is that the files are stored on the server already, segregated from the static dir.

With a quick CLI command for static driven development we can convert those files and push them to the www dir:

C:\Documents\HelloWorld> fthtml convert ./.dev/.fthtml  --dest ./www -k

This process can even be expedited by using a fthtmlconfig file in your root directory, to store the command line arguments. Then all you would have to type is:
> fthtml convert

Hello World.

This tutorial will guide you through creating your first website with ftHTML! We’ll focus on the fundamental syntax and core components that make up ftHTML. You’ll learn how to create elements, children, variables and more. We’ll have a polished 'Hello World' website up and running within 10 minutes!

Before beginning make sure you have installed ftHTML globally on your machine. If you don’t know how to do, you can review our brief installation guide.

Download, or clone, the ftHTML HelloWorld repository to your local machine. The CSS is already included because it’s not really important for the scope of this tutorial, but it just pretty’s things up!

Notice how the file structure is organized. We find this good practice for how ftHTML works, so let’s just keep it that way for now; you can always change it to suit your needs or preferences later!

The 'import' dir is a place to store frequently used code snippets or just snippets used across different pages. You can even bind property values to the import calls to quickly make, and call, dynamic templates.

The files in the import folder will not actually become a part of our website, as files, rather their content will be pulled into other files.


Let’s begin creating your website!

Step 1. Variables

In index.ftHTML, after the doctype declaration, let’s declare a variable! Variables are only allowed to be referenced in the file they are declared.

Let's create a variable called 'author' and set your name as the value. Variables can be declared in the vars pragma or an fthtmlconfig property called 'globalvars'.

doctype "html"

#vars
  author "username"
#end

Nothing else can go in a vars pragma except variable name's followed by their value. You can declare as many as you like here!

Step 2. The Document Body

Great! Let's start building the structure of the page. Let's create our first element under our variables. Every HTML page needs an HTML tag. All ftHTML elements just need the name of the HTML tag. However, when you want to add children you need to add curly braces, { }, after the tag name. You can think of the right curly brace } as HTML's closing tag syntax: </html>. Let's add the HTML tag now.

doctype "html"

#vars
  author "username"
#end

html
{

}

Step 3. Templates

Every HTML page has a head tag as well, where you can alter the title and other document attributes. This would be a great time to take advantage of templates. Navigate to .dev/.fthtml/imports and create a file called head.fthtml.

head
{
  title "Hello World"
}

There's a small change we need to make to this template in order for it to bind a property. The syntax for string interpolation of variables and template properties is the following:

"${ <@variable/property> }"

Since every page's title could potentially be different this would be a great time to make the title the consumer of a binding property, we'll just call that property 'title':

head
{
  title "${ title }"
}

As of now, string interpolation is the only way to display a property bound value.

Now, we need to call this template back in index.ftHTML. Calling a template is just like a regular HTML tag, using the 'import' keyword:

import

The compiler at this point doesn't know where the template is located so let's import it using the 'import' keyword. Importing the file use's relative paths and always excludes the file extension:

import "./.dev/.fthtml/imports/head"

This will actually import the file as-is right now, but we need to bind to the title property we set previously. Property binding from the calling side is just like declaring variables. It expects a name and a value, in this case we called it 'title', so we just type the name of the property on the left-hand side, and its value on the right-hand side. In order for a regular import to behave as a template import, you just need to add curly braces, { } followed by the key-value pairs of property and its value:

import "./.dev/.fthtml/imports/head" {
  title "Hello World"
}

As long as we use the import keyword properly this will pull the syntax we made in head.ftHTML into index.ftHTML and alter the title accordingly! Your index.ftHTML should now look like the following:

doctype "html"

#vars
  author "username"
#end

html
{
  import "./.dev/.fthtml/imports/head" {
    title "Hello World"
  }
}

Step 4. Attributes

Let's go back to the head template so we can link our CSS sheet! Attributes for elements in ftHTML require them to be surrounded by a parenthesis set,( ) . Attributes are key-value pairs, just like regular HTML. Add the tag now to link the CSS:

head
{
  title "${ title }"
  link(rel=stylesheet type="text/css" media=screen href="css/main.css")
}

Attribute values only require quotation marks if they have special characters, like in the href attribute.

Our CSS file is now linked to every page that calls this template and uses the title property!

Step 5. Document Body

Lets create our body element in index.ftHTML. You should have an idea of how to do this by now!

body {

}

Every page needs a header, so let's create one.

Since headers are usually the same thing across many pages this would be a good time to create a regular import. Navigate to the imports directory and add a file named 'header.ftHTML' and add the corresponding tag to that file:

header
{
}

Let's add a navigation menu to the header. You should know how to do this by now but here is what your complete index.fthtml should resemble:

header
{
  nav
  {
    ul
    {
      li "Home"
      li "About"
      li "Contact
    }
  }
}

Step 6. Imports

Now that we've created the header let's import it into our index.ftHTML file:

doctype "html"

#vars
  author "username"
#end

html
{
  import "./.dev/.fthtml/imports/head" {
    title "Hello World"
  }

  body
  {
    import "./.dev/.fthtml/imports/header"
  }
}

To recap, as demonstrated above, there are no property binding values in header.fthtml, so in this case there is no need to add the curly braces to the import call!

Step 7. Main Conent

Add a main HTML tag to the body of the index.ftHTML file.

main
{
}

Let's add a simple heading to the main content that says "Hello World.", but let's give it an id.

ftHTML has syntax sugar for classes and ids and the syntax sugar for an id is something you may have seen in CSS, a hash followed by the id name:

#<id_name>

Let's give it an id of 'main-title', but don't forget about the parenthesis since ids are an attribute!

doctype "html"

#vars
  author "username"
#end

html
{
  import "./.dev/.fthtml/imports/head" {
    title "Hello World"
  }

  body
  {
    import "./.dev/.fthtml/imports/header"

    main
    {
      h1 (#main-title) "Hello World."
    }
  }
}

Let's add a horizontal line after the heading, but let's animate it using a class. The syntax sugar for classes is using something you may have seen in CSS, a period followed by the class name:

.<class_name>

Give it a class called 'animated'.

doctype "html"

#vars
  author "username"
#end

html
{
  import "./.dev/.fthtml/imports/head" {
    title "Hello World"
  }

  body
  {
    import "./.dev/.fthtml/imports/header"

    main
    {
      h1 (#main-title) "Hello World"
      hr (.animated)
    }
  }
}

Let's add an h4 heading under the hr but use the author variable we declared earlier as its value! If you remember how to use string interpolation from the templates section above, you can apply the same lesson here; the difference is that when you call a variable you have to prefix it with an @ symbol.

Let's write 'Made by <author> with ftHTML!'

doctype "html"

#vars
  author "username"
#end

html
{
  import "./.dev/.fthtml/imports/head" {
    title "Hello World"
  }

  body
  {
    import "./.dev/.fthtml/imports/header"

    main
    {
      h1 (#main-title) "Hello World"
      hr (.animated)
      h4 "Made by ${ @author } with ftHTML!"
    }
  }
}

Just like a header, we'll need a footer to complete the main content. Navigate back to the imports directory and create a file for a footer. The footer is largely the same as the header and there are no new lessons learned, so copy and paste the following into that file:

footer
{
  div
  {
    h5 "Links"
    nav
    {
      ul {
        li "Home"
        li "About"
        li "Contact"
      }
    }
  }

  p "copyright 2019 www.example.com"
}

Step 8. Convert your file

So far we've learned about declaring and calling variables, creating tags, attributes, ids, classes, templates and string interpolation. Most of the core components of ftHTML have been discussed and the only thing left is to learn about the CLI to convert your webpage.

Your complete project should look like the following:

To convert your file, navigate to your projects root directory and type the following:

C:\Documents\ftHTML_HelloWorld> fthtml convert ./

Congratulations! You've completed your first ftHTML website! You should see an index.html file in your root directory to open in your browser!

Syntax


Elements

Elements are defined by a valid token, optionally followed by a string for its value or a collection of other elements as its value

Syntax

<tag>
<tag> "<value>"
<tag> @variable
<tag> @json_dot_notation
<tag> <__MACRO_NAME__>
<tag> <function>
<tag> { ,[<...values>] }
<tag> ( ,[<...attrs>] )
<tag> ( ,[<...attrs>] ) { ,[<...values>] }

Requirements

The only requirement for an element to be valid is that it must meet the criteria of a valid tag name. Attributes or values are optional contributions

If a collection of elements (children) is provided, the collection must be enclosed in curly braces: { } Curly braces identify that the preceding tag is the parent of all the elements within the braces. Elements can be nested indefinitely. Elements can NOT have another element as its value without identifying it as a parent with the curly braces. For example, div p "Hello World" will parse into:

<div></div>
<p>Hello World</p>

If attributes are provided for the element, the attributes must be enclosed in a parenthesis set: ( ). The attributes group should follow the tag immediately

Examples

//<tag>
div

//example of <tag> "<value>"
div "made with ftHTML"

//example of <tag> <function>
div random(0 10)

//example of <tag> { ,[...values] }
div
{
  h1 "Hello World"
  hr
  p "made with ftHTML"
}

//example of <tag> { ,[...attrs] }
div (data-target=someId data-attr-foo=bar title="tooltip title")
button (name=myButton autofocus value=myButtonValue)

//example of <tag> ( ,[...attrs] ) { ,[...values] }
div (data-target=someId title="tooltip title" disabled) 'made with ftHTML'
div (data-target=someId title="tooltip title" disabled)
{
  p "made with ftHTML"
  button (name=myButton autofocus value=myButtonValue) "Ok"
}
// example of <tag>
<div></div>

// example of <tag> "<value>"
<div>made with ftHTML</div>

//example of <tag> <function>
<div>4</div>

// example of <tag> { ,[...values] }
<div>
  <h1>Hello World</h1>
  <hr/>
  <p>Made with ftHTML</p>
</div>

// example of <tag> { ,[...attrs] }
<div data-target="someId" data-attr-foo="bar" title="tooltip title"></div>
<button name="myButton" autofocus value="myButtonValue"></button>

// example of <tag> ( ,[...attrs] ) { ,[...values] }
<div data-target="someId" title="tooltip title disabled">made with ftHTML</div>
<div data-target="someId" title="tooltip title disabled">
  <button name="myButton" autofocus value="myButtonValue">Ok</button>
</div>

Concatenating Elements

Requirements

Elements can only be concatenated when siblings are children of the same element, meaning enclosed in a curly braces set: { }, as shown below.

To concatenated strings with sibling elements, take this common example where you may want to include 2 links side by side with text in between:

div (#disclaimer) {
  "By clicking here you have read and agree to the "
  a (href=tos.html) "Terms of Service"
   " and "
   a (href=pp.html) "Privacy Policies"
}
<div id="disclaimer">
  By clicking here you have read and agree to the <a href="tos.html">Terms of Service</a> and <a href="pp.html">Privacy Policies</a>.
</div>

Simply break out of the string and add the element of choice and continue where you left off

Last updated: 15 Apr 2023

Tag Names


Tag names follow the pattern of html tag names ref with some slight modifications, while maintaining case-insensitive format

It can be visualized as such: [\w-]+ meaning, any letter, digit, underscore or hyphen, one or more times. Equivalent to: [a-zA-Z0-9_\-]+

Usage Notes

  • Element names are not converted to lowercase, all element names are parsed as-is
  • Tag names can not be any keyword
Last updated: 15 Apr 2023

Keywords


Reserved Keywords

comment  doctype  end  import  vars
tinytemplates
if  elif  else
ifdef
debug
this
css  js       

Functions

addslashes  choose     html_encode  html_decode  keys   len   join
random      range      replace      sort         str_split
str_repeat  str_reverse  str_format  substring  tcase  trim  values
fallback

Macros

__DATE__               __JS_DATE__
__DATETIME__           __JS_DATETIME__
__LOCAL_DATE__         __JS_LOCAL_DATE__
__LOCAL_DATETIME__     __JS_LOCAL_DATETIME__
__NOW__                __JS_NOW__
__ISO_DATE__           __JS_ISO_DATE__
__UUID__
__JS_AGENT__
__JS_URI__
__JS_URI_HASH__
__JS_URI_HOSTNAME__
__JS_URI_HOST__
__JS_URI_PORT__
__JS_URI_PATH__
__JS_URI_PROTOCOL__
__JS_URI_SEARCH__   

Operators

eq, ne, ie, gt, lt, ge, le,
contains, icontains,
starts, ends, istarts, iends,
match, imatch

Control Flow

each

Usage Notes

  • Reserved keywords can not be used for variable definitions/names
  • Reserved keywords can not be used for element/tag names
  • Reserved keywords can not be used for tiny templates
  • Reserved keywords can not be used for global elements/global variables/global tiny templates
  • Reserved keywords are case sensitive
Last updated: 15 Apr 2023

Pragmas (Directives)


Pragmas are a way for you to communicate with the pre-processor in a way which extends the language. ftHTML utilizes the intent of pragmas to extend the language, as well as traditional control flow. Meaning, some pragmas may look different syntactically than you are used to, but still maintain the intent of pragmas.

Pragmas begin using the # symbol and end with a new line, EOF, or the correlating #end identifier, depending on the pragma

Usage Notes

  • Pragmas are not global and are scoped to their respective file/markup. Meaning they do not cascade into imports & templates
  • ftHTML pragmas are prescriptive and outlined below

#vars

Vars pragma is a specific region for declaring and instantiating variables. A vars pragma can be called anywhere except in a binding property ftHTML value or variable ftHTML value, otherwise known as an ftHTML Block

This pragma will exclusively be used to handle the respective files variables, meaning no other logic or markup will be accepted and this is the only region where it's allowed

Syntax

#vars
  [<...variables>]
#end

Requirements

A valid vars pragma must be closed by using the #end identifier

Examples

#vars
  myVar "Hello World"
#end

h1 @myVar
<h1>Hello World</h1>

#tinytemplates

Tiny templates pragma is a specific region for declaring and instantiating tiny templates

A tiny templates pragma can be called anywhere except in a binding property ftHTML value or variable ftHTML values, otherwise known as an ftHTML Block

This pragma will exclusively be used to handle the respective files tiny templates, meaning no other logic or markup will be accepted and this is the only region where it's allowed

Syntax

#tinytemplates
  [<...templates>]
#end

Requirements

A valid tiny templates pragma must be closed by using the #end identifier

Examples

#tinytemplates
    shell code(.code-inline data-lang=shell)
    pwsh code(.code-inline data-lang=powershell) "PS D:\User\Documents\Programming> ${val}"
#end

shell "> cat $PROFILE
pwsh "Get-Help Get-EventLog"
<code class="code-inline" data-lang="shell">> cat $PROFILE</code>
<code class="code-inline" data-lang="powershell">PS D:\User\Documents\Programming> Get-Help Get-EventLog</code>

#if-elif-else

The if-elif-else pragma serves a purpose to dynamically generate content via a user-defined decision tree based on a given expression. If the if statement produces a truthy value, the children and ftHTML markup directly under it will be generated and exported, otherwise it will continue validating against any other adjacent statements.

This can be extended to an unlimited number of if/else statements in a given #if tree, and there is currently no limitations on how many nested if statements you can provide, pending performance review and community feedback

Note: the #elif and #else statements are optional sytnax for a well-formed #if statement. At minimum, only the if statement and the #end keyword is required

For a complete overview of supported operators, see here

Syntax

#if aValue <operator> bValue
  { ...fthtml }
#elif aValue <operator> bValue
  { ...fthtml }
#else
  { ...fthtml }
#end

Requirements

A valid #if pragma must be closed by using the #end identifier, regardless if additional control-flow or additional #elif/#else statements are provided

The left hand side (aValue) and right hand side (bValue) elements of the if expression only supports the following data types:

  • String
  • Macro
  • Function
  • Variable
  • Word

A 'word' can be any valid single [\w-]+ word or number. If a space, special characters or multiple words are required, use a string or other applicable types

Examples

//assume __LOCAL_DATE__ generates: 25 Dec 2021
#if __LOCAL_DATE__ starts "1 Jan"
    h1 "Happy New Year!"
#elif __LOCAL_DATE__ starts "4 Jul"
    h1 "Happy 4th of July!"
#elif __LOCAL_DATE__ starts "31 Oct"
    h1 "Happy Halloween"
#else
    h1 "Hello World"
#end
<h1>Hello World</h1>

#ifdef

#ifdef affords you insight on if a variable or tiny template is defined. Then, it works similar to the #if-else pragma, where the content is generated only if the variable or tiny template exists

This is useful because variables and tiny templates can be defined globally as well as locally in the current file. Additionally, with the support to extend fthtmlconfig files from other directories, it's useful to have insight if something exists or not so it's not to crash the program, throw errors or otherwise if that extended config file changes

Simply call the varibale or tiny template without any symbol prefixes or identifiers

Syntax

#ifdef <variable name>
  { ...fthtml }
#end

#ifdef <tinytemplate identifier>
  { ...fthtml }
#end

Requirements

A valid #ifdef pragma must be closed by using the #end identifier

Examples

//assume author is not defined globally either
#if a eq b
    #vars
      author "David Freer"
    #end
#end

#ifdef author
    div "Created by ${ @author }"
#end
<!-- nothing is generated because a does not equal b therefore author never gets instantiated -->
Last updated: 15 Apr 2023

Variables


Variables are a good way to quickly re-use frequently coded markup. You can call a variable once it's defined anywhere in the document and its value will be parsed as-is. The advantage of variables is that you can re-use the same content in many places but only have to declare/update it in one convenient location

Syntax

Declaring

#vars
  <variable_name> "<value>"
  <variable_name> <function>
  <variable_name> <__MACRO_NAME__>
  <variable_name> { ...ftHTML }
#end

Referencing

@<variable_name>

Requirements

  • Must be declared within the vars pragma
  • Variable names must follow the same naming requirements as a tag name
  • Variables can not use another variable as its name

Usage Notes

  • Variables can be re-instantiated at any time
  • Variables values become raw text elements, meaning parsed as-is

Examples

#vars

  btn-common 'btn btn-lg btn-primary btn-animated'

  myFavoriteSVG {
    div (.circle) {
      svg(viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg)
      {
        circle(cx=50 cy=50 r=50)
      }
    }
  }

  myUUID __UUID__

  social-links
      '<ul class="social">
        <li>Github</li>
        <li>Codepen</li>
      </ul>'

#end

header
{
  nav @social-links
}

div (#myId .@btn-common)
{
  @myFavoriteSVG
  "Hello World #${ @myUUID }"
}

footer @social-links
<header>
  <nav>
    <ul class="social">
      <li>Github</li>
      <li>Codepen</li>
    </ul>
  </nav>
</header>

<div id="myId" class="btn btn-lg btn-primary btn-animated">
  <div class="circle">
      <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg>
        <circle cx="50" cy="50" r="50"/>
      </svg>
  </div>
  Hello World #2fe868acacf9ab78eedee350bd58ee55
</div>

<footer>
  <ul class="social">
    <li>Github</li>
    <li>Codepen</li>
  </ul>
</footer>

Important

Because HTML5 allows for loose markup, it's impossible to plan for the countless ways a document can be formatted. Additionally, because ftHTML is a whitespace independent language, and in efforts to limit undesired results, it's always best to assume that when a variable follows an empty element then the variable is to be the preceding elements body (value). Take for example the footer @social-links value from the example above. Which could also be written as:

footer
@social-links

As it stands now, there is no way for the parser to know if you want:

<footer></footer>
<ul class="social">
  <li>Github</li>
  <li>Codepen</li>
</ul>

Or if you want the following:

<footer>
  <ul class="social">
    <li>Github</li>
    <li>Codepen</li>
  </ul>
</footer>

In our example it becomes the preceding elements body and works as desired, but if you want to ensure an element preceding a variable is parsed as an individual tag then it's recommended you enclose either of the elements in a wrapper. Take a common example, a horizontal line:

hr
@social-links

We want the hr to be parsed as a single tag and it's recommended to be written as something similar to the following:

hr
div @social-links

Global Variables

You can configure global variables in a fthtmlconfig file. This allows you to quickly call and reference variables in any of your .fthtml files, without the need to declare or assign them in that respective file.

To demonstrate a global 'author' variable:

As demonstrated above in the index.fthtml file, referencing a global variable is literally no different than calling a variable declared in a file; ftHTML handles calling a global var if a local one does not exist. No special syntax, or different syntax, then what you already know.

It's important to note that globalvars cascade, much like CSS rules, these variables can be overwritten in a specific file, if so desired. There is nothing special to do here either, simply assign the variable like normal and the global variable's value will be overwritten for this specific file only:

Requirements

  • Global variable names must follow the same naming requirements as a tag name
Last updated: 15 Apr 2023

Attributes


ftHTML attributes behave just like HTML attributes but is syntax-sugar friendly

Attributes can be key/value pairs, variables, or individual elements.

Attribute values can be variables, variable values, macros, strings or an HTML equivalent

Syntax

Syntax Sugar Attributes

Class
.<class_name>
Alternative Class - with variable
.@<variable_name>
Id
#<id_name>

Requirements

  • Syntax sugar is encouraged, but when an attribute value has special characters not allowed for element names or includes spaces, it's required to wrap that value in single or double quotes.
  • Attributes must be enclosed in a parenthesis group: ( )
  • An attribute group must follow an element (tag)

Usage Notes

  • There's no specific order attributes should be placed
  • Variables can be used in tandem
  • For attributes with syntax sugar, it is optional
  • If syntax sugar is used for syntax-sugar friendly attributes, it does not merge it's counterpart. An example would be .className1 .className2 and class='className3' would parse into a duplicate class attr:
    <div class="className1 className2" class="className3" ></div>

Examples

div (.myClass #myId) "Hello World"

div (.myClass1 #myId .myClass2) "Hello World"

div (.myClass1 #myId readonly contenteditable) "Hello World"

a (href=www.google.com target=_blank data-attr=some_value) "Google"

//demonstrates using a macro as attr value
div (.myClass1 data-foo=__UUID__) "Some div with UUID attr"

//demonstrates special characters not allowed without quotes
a (href="../../somedir/about.html") "About Us"

//the following demonstrates variables as attributes
#vars

  btnCommon "btn btn-lg btn-primary btn-animated"
  styleCommon 'style="margin:0; padding: 0; overflow: hidden;"'

#end

div (#myId .@btnCommon @styleCommon) "Hello World"
<div class="myClass" id="myId">Hello World</div>

<div class="myClass1 myClass2" id="myId">Hello World</div>

<div class="myClass1" id="myId" readonly contenteditable>Hello World</div>

<a href="www.google.com" target="_blank" data-attr="some_value">Google</a>

//demonstrates using a macro as attr value
<div class="myClass1" data-foo="5f0517c8334890f58d26ba74c12226f3">Some div with UUID in data-foo attr</div>

//demonstrates special characters not allowed without quotes
<a href="../../somedir/about.html">About Us</a>

//the following demonstrates variables as attributes
<div id="myId" class="btn btn-lg btn-primary btn-animated" style="margin:0; padding: 0; overflow: hidden;">Hello World</div>
Last updated: 15 Apr 2023

Comments


All comments are omitted when interpreting, except the DOM comment. DOM comments explicitly ensure the comment renders in the HTML document, otherwise it's only for the developers' eyes

Syntax

Line Comment
// <value>
Block Comment
/*
  [<...values>]
*/
DOM Comment
comment "<value>"

Requirements

Line comments must end with a new line character or at EOF
Last updated: 15 Apr 2023

imports

Importing files acts as an easy way to write what we call 'soft templates', in the sense that you can't pass information into the 'template'. This is a file that can help separate markup, create a modularized project and include the same information across multiple files giving the advantage of only needing to update one instance of markup and keeping the infrastructure D.R.Y

Syntax

import "<file_name>"

Requirements

  • Import statements only assume .ftHTML files
  • Imports will always assume and try to parse the file given, therefore an import files syntax should only be ftHTML syntax, otherwise it's recommended to use a variable, or template, to quickly re-use markup, ftHTML - native or foreign
  • All import statements must exclude the extension name
  • If you wish to use an absolute path, for say a file out of project scope, you can but it must exclude the .ftHTML extension
  • Import filenames can not be remote URL links

Usage Notes

  • When not using an fthtmlconfig file, all imports are relative, otherwise the context path will begin from the dir you specify in the fthtmlconfig file's importDir setting
  • When using an fthtmlconfig file and setting the 'importDir', you can now explicitly specify a relative path by prefixing the path with the pass by reference symbol, &

Examples

Last updated: 15 Apr 2023

Templates

And Property Binding


Templates are a great way to quickly and easily import frequently used syntax while making them dynamic.

ftHTML templates are flexible and promotes dynamic syntax via imports.

Templates are different than imports; in that templates allow you to bind to a property, or many properties, to use across different pages for different needs.

Syntax

Declaring a binding property in a template file:

"${ <property_name> }"

Declaring a null safe binding property in a template file:

"${ <property_name>? }"

Referencing the template file and setting the value of a property:

import "<file_name>" {
  <binding_property> "<value>"
  <binding_property> @variable
  <binding_property> @json_dot_notation
  <binding_property> <__MACRO_NAME__>
  <binding_property> <function>
  <binding_property> { ...ftHTML }
}

Requirements

  • Binding properties can only be declared in a string using interpolation
  • When declaring a property via interpolation, it is expecting a single property name.

Usage Notes

  • Binding properties do not support complex operations or logic, as noted, the interpolation syntax is strictly expecting a single value.
  • There is no limit to the amount of binding properties per template
  • Null safe binding properties allow the template to be imported without setting the value of a particular property. If this value is not provided it will be replaced with an empty value
  • When using an fthtmlconfig file and setting the 'importDir', you can now explicitly specify a relative path by prefixing the path with the pass by reference symbol, &

Example


Tiny Templates

Tiny templates are ways to quickly create re-usable elements that only take a single value argument. These are different than templates that use the import keyword. Templates are set up in a way in which you define the property names and bind to those names. Tiny templates expect a single tag or string value that you don't bind to, you simply just call the tag name per normal which keeps the vertical space lightweight.

You can consider tiny templates to be aliases of frequently marked up elements

Syntax

Declaring a tiny template:

<tinytemplate_name> "${val}"
<tinytemplate_name> <tag>
<tinytemplate_name> <tag> "${val}"
<tinytemplate_name> <tag> ( ,[<...attrs>] )
<tinytemplate_name> <tag> ( ,[<...attrs>] ) "${val}"

Referencing the tiny template:

<tinytemplate_name> "<value>"
<tinytemplate_name> <__MACRO_NAME>
<tinytemplate_name> <function>
<tinytemplate_name> @variable
<tinytemplate_name> @json_dot_notation
<tinytemplate_name> { ...ftHTML }

Requirements

  • Must be declared within the tinytemplates pragma
  • Tiny template names must follow the same naming requirements as a tag name
  • Placeholder values, ${val}, are implicitly applied when you don't include string values. If you include a string when declaring a tiny template and want the value interpolated, you need to provide at least 1 placeholder value explicitly
  • Because tiny templates are intended for elements with single value arguments, declaring them only accepts string values

Usage Notes

  • Tiny templates can be re-instantiated at any time
  • You can define global tiny templates in your fthtmlconfig file to easily write once and use everywhere

Examples

#tinytemplates
    //implicit placeholder
    shell code(.code-inline data-lang=shell)

    // another implicit template demonstrating a common bootstrap button
    primarybtn button(.btn .btn-primary .btn-sm .animated)

    //explicit placeholder - requires at least 1 ${val} placeholder when a string is provided
    pwsh code(.code-inline data-lang=powershell) "PS D:\User\Documents\Programming> ${val}"
#end

shell "> cat $PROFILE"
primarybtn "Run shell"

pwsh "Get-Help Foobar"
primarybtn "Run powershell"
<!-- implicit placeholder ->
<code class="code-inline" data-lang="shell">> cat $PROFILE</code>
<button class="btn btn-primary btn-sm animated">Run shell</button>

<!-- explicit placeholder - requires at least 1 ${val} placeholder when a string is provided -->
<code class="code-inline" data-lang="powershell">PS D:\User\Documents\Programming> Get-Help Foobar</code>
<button class="btn btn-primary btn-sm animated">Run powershell</button>

Since the Heliotrope version, tiny template callers can now extend attributes, therefore making them behave as any other element:

#tinytemplates
    icode code(.code-inline)
    pwsh  code(.code-inline data-lang=powershell) "PS D:\User\Documents\Programming> ${val}"
#end

icode(data-lang=shell .bold readonly) "> cat $PROFILE"
pwsh(.bold readonly) "Get-Help Foobar"
<code class="code-inline bold" data-lang="shell" readonly>> cat $PROFILE</code>
<code class="code-inline bold" data-lang="powershell" readonly>PS D:\User\Documents\Programming> Get-Help Foobar</code>

Since the Heliotrope version, you can now instantiate a tiny template with a placeholder in an attribute kvp only, though, this doesn't change requirements and at minimum, 1 placeholder needs to be provided somewhere in the tiny template. The following demonstrates:

#tinytemplates
    href a(href="${val}") "here"
#end

div(#disclaimer) {
    "For more info please click "
    href "www.google.com"
}
<div id="disclaimer">For more info please click <a href="www.google.com">here</a></div>

Though, you can still use more than 1 placeholder if you desire

Last updated: 15 Apr 2023

Control Flow


each

Also known as a for-each loop, this control flow element loops through a provided iterable object and outputs duplicated html, n times.

Syntax

each <variable | keys() | len() | range() | sort() | str_split() | values()> { ...ftHTML }

Referencing the current iterator element:

@this

If the current iterated value is an object or array, dot-notation is supported:

@this.foo.bar[0]

Requirements

  • The value provided must resolve to an iterable object, meaning an array of values to some degree

Usage Notes

  • There is currently no limit to the amount of nested control flow elements provided, but please note that there is currently no way to name your own iterable value, so @this only refers to the each loop it's scoped to
  • The @this keyword can be used anywhere and any way a normal variable can be referenced

Examples

ul {
    each range(1 16) {
        li(data-value=@this) "This is example #${@this}"
    }
}
<ul>
    <li data-value="1">This is example #1</li>
    <li data-value="2">This is example #2</li>
    <li data-value="3">This is example #3</li>
    <li data-value="4">This is example #4</li>
    <li data-value="5">This is example #5</li>
    <li data-value="6">This is example #6</li>
    <li data-value="7">This is example #7</li>
    <li data-value="8">This is example #8</li>
    <li data-value="9">This is example #9</li>
    <li data-value="10">This is example #10</li>
    <li data-value="11">This is example #11</li>
    <li data-value="12">This is example #12</li>
    <li data-value="13">This is example #13</li>
    <li data-value="14">This is example #14</li>
    <li data-value="15">This is example #15</li>
</ul>

Example using complex objects:

Last updated: 15 Apr 2023

Embedded Languages


The embedded languages feature allows for an easy way to incorporate other languages/markup into your ftHTML files

Embedded language tags allow raw input, as-is, for its respective language. The parser does not restrict syntax to ftHTML syntax for embedded language tags.

Currently, the supported embedded language tags are:

css      js       

Syntax

<lang_name> {
  ...
}

Requirements

  • Embedded language tag names are case sensitive and can not be used as variables or other element names
  • Embedded language tags do not support attributes

Usage Notes

  • If you are using the vscode ftHTML extension, embedded language tags support syntax highlighting for the respective language
  • You can not nest embedded languages since raw input is strictly expected

Examples

html
{
  head
  {
    title 'Home'
    script(src='https://code.jquery.com/jquery-3.4.1.min.js')

    css {
      * { box-sizing: border-box;}

      body, html {
        width: 100%; height: 100%;
      }

      h1 {
        color: tomato;
        font-size: 3rem;
      }
    }
  }

  body
  {
    h1 'Hello World'
  }
}
html
{
  head
  {
    title 'Home'
    script(src='https://code.jquery.com/jquery-3.4.1.min.js')
  }

  body
  {
    h1 'Hello World'
  }

  js {
    $('h1').css('font-size', '3rem');
  }
}

String Interpolation


String interpolation is pretty straight-forward. It emulates a template literal in javascript.

Syntax

Variable

"... ${ @<variable_name> } ..."

Macro

"... ${ <__MACRO_NAME__> } ..."

Binding Property

"... ${ <property_name> } ..."

Json Value

"... ${ @<json_dot_notation> } ..."

Piped Lambdas

"... ${ <value> | <piped function name> } ..."

Piped lambdas can cascade and pipe into multiple piped lambdas

Supported piped lambda values:

value        |       alias
-----------------------------------------------
asc          |  sort(<value>)
desc         |  sort(<value> 'desc')
lower        |  tcase(<value> 'lower')
upper        |  tcase(<value> 'upper')
capital      |  tcase(<value> 'capitalization')
kebab        |  tcase(<value> 'kebab')
snake        |  tcase(<value> 'snake')
camel        |  tcase(<value> 'camel')
pascal       |  tcase(<value> 'pascal')
alternating  |  tcase(<value> 'alternating')
title        |  tcase(<value> 'title')
keys         |  keys(<value>)
values       |  values(<value>)
choose       |  choose(<...values>)
reverse      |  str_reverse(<value>)
len          |  len(<value>)
trim         |  trim(<value>)
trimEnd      |  trim(<value> 'trimEnd')
trimStart    |  trim(<value> 'trimStart')
trimLeft     |  trim(<value> 'trimLeft')
trimRight    |  trim(<value> 'trimRight)

Usage Notes

  • ftHTML interpolation doesn't support complex logic operations, expressions or statements. It expects a single variable or a single property name.
  • Interpolation does not support regular text or another string

Examples

#vars
  author "john doe"
#end

h1 "Created by ${ @author }"
h1 "Last modified: ${ __LOCAL_DATE__ }"
Last updated: 15 Apr 2023

JSON


Native JSON support is provided to quickly import and call properties in a given JSON file

Syntax

Declaring a json variable

#vars
  <variable_name> json("./somejsonfile")
#end

Calling a json property

@<json_dot_notation>

JSON dot-notation syntax is supported natively as well in string templates (interpolation)

As of Indigo Optional Chaining keys is supported, i.e. ?.

Requirements

  • json files can only be called and assigned to a variable, via the vars pragma, and only by using the 'json' keyword
  • json statements only assume .json files
  • Imports will always assume and try to parse the file given, therefore an import files syntax should only be json syntax.
  • All import statements must exclude the '.json' extension name
  • If you wish to use an absolute path, for say a file out of project scope, you can but it must exclude the .json extension
  • Filenames can not be remote url links

Usage Notes

  • When not using an fthtmlconfig file, all imports are relative, otherwise the context path will begin from the dir you specify in the fthtmlconfig file's jsonDir setting
  • When using an fthtmlconfig file and setting the 'jsonDir', you can explicitly specify a relative path by prefixing the path with the pass by reference symbol, &
  • The dot notation syntax supports indices (shown in the example below with animals)

Examples

Destructoring variables:

With destructoring using dot notation, the json keyword supports special sytnax for piping filters, as noted above. The following demonstrates usage:

Destructoring variables with piped filters:

Last updated: 15 Apr 2023

Functions


Syntax

<function_name>(<...args>)

Usage Notes

  • Functions are considered reserved keywords and can not be used for tag names, variable names or otherwise. Functions can only be values
  • Functions can be used as values of other functions, when applicable

addslashes

Syntax

addslashes(<string | variable | macro | function> value)

Returns

String with backslashes added before characters that need to be escaped. These characters are:

  • Single Quote: '
  • Double Quote: "
  • Backslash: ""

Examples

addslashes("Foo bar isn't bazz")
// Foo bar isn\'t bazz

choose

Choose a random item from a given list of items. The number of items you can provide is not restricted. This is randomly generated each time the file is rendered.

'Word' datatype indicates that you can use unquoted strings for values

Syntax

choose(<string | variable | word | macro | function> ...value)

Returns

The value of a randomly selected item.

Examples

div choose(foo bar 123)
// <div>bar</div>

div choose(foo __UUID__ random(1 10))
// <div>5</div>

fallback

Falls back to a default value when the provided value is 'absent'

Absent, defined as:

  • When `value` is data-type of string and is empty or otherwise nullable (trim is applied)
  • When `value` is data-type of object and has no keys
  • When `value` is data-type of array and has no values

Syntax

fallback(<string | variable | function> value, <string | variable | function> defaultValue)

Returns

Value when not absent, otherwise defaultValue


html_encode

Convert applicable characters to HTML entities

Syntax

html_encode(<string | variable | function> value)

Returns

A string with html entities encoded

Examples

pre {
  code html_encode("<div>foo</div>")
}
// <pre><code>&#x3C;div&#x3E;foo&#x3C;/div&#x3E;</code></pre>

html_decode

Convert applicable HTML entities to human-readable symbols

Syntax

html_decode(<string | variable | function> value)

Returns

A string with html entities decoded

Examples

pre {
  code html_decode("&#x3C;div&#x3E;foo&#x3C;/div&#x3E;")
}
// <pre><code><div>foo</div></code></pre>

join

Return a joined iterable object by a given delimiter. You must only pass variables as the value argument. Throws if the object in the variable is not an array or object. When an object is provided, the keys will be joined

Syntax

join(<variable> value, <string | variable> delimiter)

Returns

A delimited string of given array or object keys

Examples

#vars
   date str_split("01 01 1999" " ")
#end

join(@date "/")
//01/01/1999

len

Returns the length of a given string, object or array dynamically

When passing a variable as the value argument:

  • If the variable holds an array, the number of elements in the array will be returned
  • If the variable holds an object, the number of keys in the object will be returned

Otherwise, the length of the value will be returned via it's 'toString()' method

Syntax

len(<string | variable | function | word> value)

Returns

The quantified length of the given value

Examples

#vars
  cars json("foo")

  bmws json("${ @cars.bmw.models }") //get only the bmws of the cars json file

  m3Values json("${ @bmws.m3 | values }")
#end

len(@bmws)
//returns the number of keys in the object

len(@m3Values)
//only the values of the m3 model

len(str_split("01/01/1999" "/"))
//10 because it's split into an array of: [01, 01, 1999] but not assigned to a variable, so it uses the arrays toString() method

#vars
  date str_split("01/01/1999" "/")
#end

len(@date)
//3 because it's assigned to a variable therefore the raw type is maintained (an array)

keys

Return the keys of a given object. Throws if the provided value does not resolve to a literal object

Syntax

keys(<variable> value)

Returns

any[]


random

Generate a random number between a min and max value (inclusive). The value returned will always be resolved to an integer.

All datatypes used for min/max arguments must resolve to a number. For example, when using a variable for min, the value of the variable should be of number datatype.

'Word' datatype indicates that you can use unquoted strings for values

Syntax

random(<string | variable | word | function> min,
       <string | variable | word | function> max)

Returns

A random number between, and including, the values provided

Examples

div random(1 10)
// <div>5</div>

div random(-10 -5)
// <div>-8</div>

div random(-10 10)
// <div>-6</div>

Usage Notes

  • Both arg values need to be numeric
  • Decimal values are not supported
  • Negative values are permitted.
  • This is randomly generated each time the file is rendered
  • Min can not be greater than max

range

Returns an array of numbers within the given range provided (exclusive). If the upper bound number is omitted, the starting value is always 0 and the value provided becomes the upper bound

Syntax

range(<word | len()> start)
      <word | len()> end [optional])

Returns

int[]

Examples

range(5)
// [0, 1, 2, 3, 4]

range(2,8)
// [2, 3, 4, 5, 6, 7]

replace

Replace a pattern of values with a given replacement value.

Requires SINGLE escape characters per usual literal pattern rules. For example, whitespace only needs '\s'

Pattern uses regular JavaScript regex flavor

Syntax

replace(<string | variable | macro | function> value,
        <string> pattern,
        <string | variable | function> replace_value)

Returns

A string replacing a global pattern of matches with a provided replace value

Examples

div replace("Telephone: 515.987.6543" "\." "-")
// <div>Telephone: 515-987-6543</div>

sort

Sort a given value. This is not a true deep sort and does slight validation of data types, but it sorts strings or arrays of strings accordingly, in addition to numbers and objects

Syntax

sort(<variable> value,
     <string> sort type [optional] = { "asc", "desc" },
     <word> member name [optional])

Returns

any[]

Examples

// sort string
div sort("onomatopoeia")
// <div>aaeimnoooopt</div>

// sort array
#vars
    author str_split("David Freer" " ")
#end

div sort(@author)
// <div>David,Freer</div>

div sort(@author "desc")
// <div>Freer,David</div>

// sort object:
// animals.json
[
  {
    "type": "dog"
    "name": "buzz",
    "age": 8
  },
  {
    "type": "cat"
    "name": "bar",
    "age": 4
  },
  {
    "type": "horse"
    "name": "foo",
    "age": 3
  }
]

// fthtml
#vars
    animals json("animals")
#end

div sort(@animals "asc" name)
// [ { name: bar }, { name: buzz }, { name: foo } ]

div sort(@animals "desc" age)
// [ { age: 8 }, { age: 4 }, { age: 3 } ]

str_repeat

Repeat a string or value a given number of times

'Word' datatype indicates that you can use unquoted strings for values

Syntax

str_repeat(<string | variable | macro | function> value,
           <string | word> quantity)

Returns

A duplicated string dictated by the quantity

Examples

div str_repeat("Hello. World. " 1)
// <div>Hello. World. Hello. World. </div>

Usage Notes

  • Quantity values must resolve to an integer

str_reverse

Reverses a given string

Syntax

str_reverse(<string | variable | macro | function> value)

Returns

A reversed input string

Examples

div str_reverse("Hello. World.")
// <div>.dlroW .olleH</div>

str_split

Split a resolved string by a given delimiter

Syntax

str_split(<string | variable | macro | function> value,
          <string | variable> delimiter)

Returns

object[]

Examples

#vars
   date str_split("01 01 1999" " ")
#end

div join(@date "/")
//<div>01/01/1999</div>

str_format

Format a number to currency, units, percents etc, or a date.

This uses the javascript native Intl.NumberFormat method for number formatting. See MDN docs for a complete overview of usage

This uses the javascript native Intl.DateTimeFormat method for date formatting. See MDN docs for a complete overview of usage

The 'value' argument must resolve to a number if the style is anything other than 'date'

Syntax

str_format(<string | variable | function> value,
           <string> style = { "currency", "number", "unit", "percent", "decimal", "date" },
           <string> options [optional])

Returns

A formatted number configured by options and style

Examples

div str_format("12345.0" "currency")
// <div>$12,345.00</div>

div str_format("12345.0" "currency" "currency: JPY, maximumSignificantDigits: 3")
// <div>¥12,000</div>

div str_format("123.0" "unit" "unit: mile-per-hour")
// <div>123 mph</div>

div str_format("March 19 2000" "date" "dateStyle: full, timeStyle: long")
//<div>Sunday, March 19, 2000 at 12:00:00 AM PST</div>

Usage Notes


substring

Return a substring from a given start and end index

Indices are 1 based

Negative values are permitted

Syntax

substring(<string | variable | macro | function> value,
          <string | variable | word> start,
          <string | variable | word> end [optional])

Returns

A substring from the given start and end indices

Examples

div substring("Hello. World" 7)
// <div>World</div>
div substring("Hello. World" -5)
// <div>World</div>
div substring("Hello. World" -5 -3)
// <div>Wo</div>
div substring("Hello. World" 3 -3)
// <div>lo. Wo</div>

tcase

Transform a given value to a specificed text case.

Note: This does not convert cases, only transforms

Syntax

tcase(<string | variable | macro | function> value,
      <string> text case = { "capitalization", "upper", "lower", "alternating", "title", "snake", "kebab", "camel", "pascal" })

Returns

A string formatted in the desired text case provided

Examples

div tcase("Hello. World" "upper")
// <div>HELLO. WORLD</div>
div tcase("Hello. World" "lower")
// <div>hello. world</div>
div tcase("Hello. World" "alternating")
// <div>HeLlO. wOrLd</div>
div tcase("hello. world" "title")
// <div>Hello. World</div>
div tcase("Hello. World" "snake")
// <div>Hello_World</div>
div tcase("Hello. World" "kebab")
// <div>Hello-World</div>
div tcase("Hello. World" "camel")
// <div>hello.World</div>
div tcase("Hello. World" "pascal")
// <div>Hello.World</div>

trim

Trim whitespace dictated by a specific style

Syntax

trim(<string | variable | function | macro> value,
     <string> trim style [optional] = { "left", "right", "start", "end", "trim"})

Returns

A trimmed value provided by given trim type

Examples

div trim("   Hello. World.   ")
// <div>Hello. World.</div>
div trim("   Hello. World.   " "left")
// <div>Hello. World.   </div>
div trim("   Hello. World.   " "right")
// <div>   Hello. World.</div>
div trim("   Hello. World.   " "end")
// <div>   Hello. World.</div>
div trim("   Hello. World.   " "start")
// <div>Hello. World.   </div>

values

Return the values of a given object. Throws if the value provided does not resolve to a literal object

Syntax

values(<variable> value)

Returns

any[]


Last updated: 15 Apr 2023

Macros


Syntax

<__MACRO_NAME__>

Usage Notes

  • Macros are considered reserved keywords and can not be used for tag names, variable names or otherwise. Macros can only be used as values
  • If there is a 'JS' prefix before a macro name, then a <script> will be inserted instead of the value, that way the value is derived at runtime from the clients' request. If the ftHTML is interpreted at runtime, with something like expressjs, then the JS prefix isn't really needed.

__DATE__
__JS_DATE__

Returns

A UTC date in dd Month YYYY format

Examples

__DATE__
//10 Nov 2020

__DATETIME__
__JS_DATETIME__

Returns

A UTC date with 24h time in dd Month YYYY HH:mm:ss format

Examples

__DATETIME__
//10 Nov 2020 00:00:00

__ISO_DATE__
__JS_ISO_DATE__

Returns

A ISO date value

Examples

__DATETIME__
//2021-02-13T22:56:51.826Z

__LOCAL_DATE__
__JS_LOCAL_DATE__

Returns

A users local date in dd Month YYYY format

Examples

__LOCAL_DATE__
//10 Nov 2020

__LOCAL_DATETIME__
__JS_LOCAL_DATETIME__

Returns

A users local date with 24hr time in dd Month YYYY HH:mm:ss format

Examples

__LOCAL_DATETIME__
//10 Nov 2020 00:00:00

__NOW__
__JS_NOW__

Returns

Number of millesconds since Unix Epoch of user

Examples

__NOW__
//1613257805987

__UUID__

Returns

Crpytographically well-built psuedo-random data of 16 bytes using nodejs crypto#randomBytes

Examples

__UUID__
//ffe4c5e88bc7fd4ee84cd8570a5c5576

__JS_AGENT__

Returns

User agent of client

Examples

__JS_AGENT__
// <script>document.write(window.navigator.userAgent);</script>

__JS_URI__

Returns

Entire uri of client

Examples

__JS_URI__
// <script>document.write(window.location.href);</script>

__JS_URI_HASH__

Returns

The hash value of the uri

Examples

__JS_URI_HASH__
// <script>document.write(window.location.href);</script>

__JS_URI_HOSTNAME__

Returns

The hostname portion of the uri

Examples

__JS_URI_HOSTNAME__
// <script>document.write(window.location.hostname);</script>

__JS_URI_HOST__

Returns

The host portion of the uri

Examples

__JS_URI_HOST__
// <script>document.write(window.location.host);</script>

__JS_URI_PORT__

Returns

The port number of the uri

Examples

__JS_URI_PORT__
// <script>document.write(window.location.port);</script>

__JS_URI_PATH__

Returns

The context path portion of the uri

Examples

__JS_URI_PATH__
// <script>document.write(window.location.pathname);</script>

__JS_URI_PROTOCOL__

Returns

The protocol portion of the uri

Examples

__JS_URI_PROTOCOL__
// <script>document.write(window.location.protocol);</script>

__JS_URI_SEARCH__

Returns

The search values of the uri

Examples

__JS_URI_SEARCH__
// <script>document.write(window.location.search);</script>
Last updated: 15 Apr 2023

Operators

Currently, operators are only valid in #if-elif expressions


eq equals

Compare left hand side value to right hand side value; case-sensitive
Does not account for data type, uses string representation of both sides


ie case-insensitive equals

Compare left hand side value to right hand side value; case-sensitive
Does not account for data type, uses string representation of both sides


ne not equals

Compare left hand side value to right hand side value and assert they don't match; case-sensitive
Does not account for data type, uses string representation of both sides


gt greater than

Assert that left hand side value is greater than the right hand side value; case-sensitive
Does not account for data type, uses string representation of both sides


lt less than

Assert that left hand side value is lesser than right hand side value; case-sensitive
Does not account for data type, uses string representation of both sides


ge greater than or equal to

Assert that left hand side value is greater than or equal to right hand side value; case-sensitive
Does not account for data type, uses string representation of both sides


le less than or equal to

Assert that left hand side value is lesser than or equal to right hand side value; case-sensitive
Does not account for data type, uses string representation of both sides


contains

Assert that left hand side value contains a right hand side element; case-sensitive
This accounts for data type. For example, if a variable contains an array of objects or object, it will not use the toString() representation, instead it validate either the array contains an element and index of the query, or the object contains a valid key


icontains case-insensitive

Assert that left hand side value contains a right hand side element; case-insensitive
This accounts for data type. For example, if a variable contains an array of objects or object, it will not use the toString() representation, instead it validate either the array contains an element and index of the query, or the object contains a valid key


starts

Assert that left hand side value starts with a right hand side query; case-sensitive
Does not account for data type, uses string representation of both sides


istarts case-insensitive

Assert that left hand side value starts with a right hand side query; case-insensitive
Does not account for data type, uses string representation of both sides


ends

Assert that left hand side value ends with a right hand side query; case-sensitive
Does not account for data type, uses string representation of both sides


iends case-insensitive

Assert that left hand side value ends with a right hand side query; case-insensitive
Does not account for data type, uses string representation of both sides


match

Assert that left hand side value matches a right hand side regex pattern; case-sensitive


imatch case-insensitive

Assert that left hand side value matches a right hand side regex pattern using the i regex flag