Skip to content

Style Guide

Brayden edited this page May 16, 2023 · 3 revisions

Overview

Welcome to the Flutter Markup Language style guide. This guide will help you make the best decisions when writing your code in FML. This is designed to be a general overview, and in depth examples of styling for things like databinding, evals, events, and more can be found in their respective wikis.

Widgets and Attributes

When defining a widget as an element name, the widget element name should be written in UPPERCASE.

<!--DO-->
<TEXT/>
<!--DON'T-->
<Text>

Attributes for the widget should be written in lowercase.

<!--DO-->
<TEXT value="Hello World!"/>
<!--DON'T-->
<TEXT Value="Hello World!"/>

When defining an attribute as an element, such as , it should be written in lowercase.

<!--DO-->
<TEXT>
     <value>
          Hello World!
     </value>
</TEXT>
<!--DON'T-->
<TEXT>
     <VALUE>
          Hello World!
     </VALUE>
</TEXT>

When defining an id for a widget, it is recommended to use lowerCamelCase. Never use a hyphen/dash -.

<!--DO-->
<TEXT id="bodyTxt" />
<!--DON'T-->
<TEXT id="body-txt" />

Event Strings

Events can either be called on specific id's, different scopes, specific attributes, or allowed to walk up the tree with no id. The syntax is: event(), id.event(), id.attribute.event() and can be appended with SCOPE if the id exists within a scope.

Events should be written in lowercase(), with attributes that are Booleans written in lowercase as well.

<!--DO-->
<VAR id="var1" onchange="alert('warning', 'This is an alert')"/>
<!--DON'T-->
<VAR id="var1" onchange="Alert('warning', 'This is an alert')"/>

Evaluations

Evaluations are always denoted with =, and evaluation functions should be written in lowercase.

<!--DO-->
<INPUT value="Hello" color="=noe({this})?'green':'blue'"/>
<!--DON'T-->
<INPUT value="Hello" color="=NOE({this})?'green':'blue'"/>

When changing attributes within a widget using ternary statements, it is recommended to return the type within the attribute.

<!--DO-->
<INPUT value="Hello" color="=noe({this})?'green':'blue'"/>
<!--DON'T-->
<INPUT value="Hello" onchange="=noe({this})?this.color.set('green'):this.color.set('blue')"/>

If a returned event string from a ternary statement contains over 2 events, or nested ternary statements it is best practice to use a TRIGGER widget.

<!--DO-->
<TRIGGER id="t1">
   <CASE when="={input} == hello" call="alert('warning', 'they said hi');"/>
   <CASE when="=!noe({input})" call="alert('warning', 'It is full');"/>
   <CASE when="=noe({input})" call="alert('warning', 'It is empty');"/>
</TRIGGER>
<INPUT id="input" value="" onchange="t1.trigger()"/>
<!--DON'T-->
<INPUT id="input" value="" onchange="={input} == hello ? alert('warning', 'they said hi'); : !noe({input}) ? alert('warning', 'It is full'); : noe({input}) ? alert('warning', 'It is empty'); : null"/>

Ternary statements cannot mix return types, they must be an event, a string, a bool, or an int in all cases.

<!--DO-->
<INPUT value="Hello" color="=noe({this})?'green':'blue'"/>
<!--DON'T-->
<INPUT value="Hello" color="=noe({this})?'green':this.color.set('blue')"/>

Databinding Style

When defining Databindings, the general syntax is {SCOPE.id.attribute}.

The SCOPE such as USER, GLOBAL, or APP, should always be UPPERCASE.

<!--DO-->
<TEXT value="{GLOBAL.username}">
<!--DON'T-->
<TEXT value="{global.username}">

Value is bound to by default and should not be specified as an attribute.

```

The case of the binding should match that of the widgets case.

<!--DO-->
<VAR  id="bodyVar" value="hello"/>
<TEXT value="{bodyVar}"/>
<!--DON'T-->
<VAR  id="bodyVar" value="hello"/>
<TEXT value="{BodyVar}"/>

Binding to returned Data

When binding to data, the element you are binding to should match the case of the returned document.

<!--Returned data is <DataField>value</Datafield>-->
<!--DO-->
<TEXT value="{broker.data.DataField}"/>
<!--DON'T-->
<TEXT value="{broker.data.datafield}"/>

When binding to the same repeated element, or the same root, a root="" should be set on the Datasource.

<!--DO-->
<GET id="broker" root="Node.Node1.Node2"/>
<TEXT value="{broker.data.Node3}"/>
...
<!--DON'T-->
<GET id="broker" root=""/>
<TEXT value="{broker.data.Node1.Node2.Node3}"/>
...

If multiple levels of the data document are being traversed frequently, a DATA widget should be used and nested to segment levels of the tree with their own respective roots.

<!--DO-->
<GET id="broker" root="">
     <DATA id="broker2" url="broker" root="Node.Node1.Node2"/>
</GET>
<TEXT value="{broker.data.Node2}"/>
<TEXT value="{broker2.data.Node3}"/>
<!--DON'T-->
<GET id="broker" root=""/>
<TEXT value="{broker.data.Node1.Node2}"/>
<TEXT value="{broker2.data.Node1.Node2.Node3}"/>

Clone this wiki locally