Style Guide - AppDaddy-Software-Solutions-Inc/framework-markup-language GitHub Wiki
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.
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" />
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 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')"/>
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}"/>
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}"/>