The web application developer may use so-called placeholders in the source document for [Templating]: the bracy template files. [The Basic Idea] wiki page already mentioned the placeholders that this page will discuss further.
<p {quantifier} title={substitute2a} class="beautiful emphasized {substitute2b}">Dear {substitute1},</p>
{substitute1} in the example above.){substitute2a} in the example above); or as a part of that (See {substitute2b} in the example above.) {quantifier} in the example above.) The value of the quantifier will not appear in the resulting DOM, but it will affect template instantiation.Note: the template should be syntactically correct as an HTML fragment, and will be parsed as such. The quantifier gets parsed as an attribute without a value. You can't use characters such as >, /, &, ", ', =, whitespaces in the placeholders because HTML rules apply.
Note: the substitution value of {substitute2a} may or may not have spaces in it, and even though the placeholder itself is not between quotation marks, the value is substituted as a whole in the title attribute.
{name} contains a variable name that is in scope of the backing javascript; by type:
name[i] gets inserted as its value,name[i] gets inserted as the text node,name[i].field can be referred to as {field} from the child text nodes.attr="" if true,== 0@expiry{i:name} make {i} refer to the value of the variable name in this element of the template document
{i} refers to the value stored in the Observable object{i} (be it numeric or string); refer to the value as {@i}{@i} explicitely appears{name}{name}t:times="1" or "1+" and the value == 0: just assign to {i}{i}, fail with error for boolean and string value for others{i}{name(arg1,arg2)}
@Observables)@expiry and expires{i:name(arg1,arg2)} function call, store its return value as {i}
{name1}{name2} several placeholders in the same element:
* Cartesian product of elements get instantiated,
* i.e. removed if any of the names evaluate to empty object or null or false, and
* N times M instances appear if name1 has N entries and name2 has M.
=) sign, the and (&) ligature and whitespaces among others;{v|0} or short {v?} converts anything to boolean (potentially removes the element if it is a quantifier)!= 0,"null": false,!= 0,{p|q} OR-combines booleans (result is guaranteed to be boolean);{p*q} AND-combines booleans, same as {p}{q} but with precedence over |& entity for * but it would look cluttered;{!p} negates boolean, top precedence;{p!} negates boolean but on lower precedence level than | (or even +, which is discussed below);{i+1} converts a 0-based index into 1-based ordinal;{obj-1} to get the highest existing 0-based index of an object;{v+0} or short {v#} converts anything to number/string{s~t} equals (the = sign is to be avoided in a start tag because of html parsing;){s~_} true if the string is blank; distinguishes "" from "0", latter is not blank;{booing(s)} boolean string (either "true" or "false" as string;){join(a)} convert an array to string by joining;{obj.field} field selector - second argument is taken as a name, not evaluated{obj[i]}indexing - evaluate even the second operand to its value, unlike with the dot operator{!p*q} (NOT p) AND q, because prefix ! is top precedence,{p|q*r} p OR (q AND r), because * has precedence over |,{w:p|q} assign (p OR q) to w, because : has the lowest precedence,{i-1|0} (i-1) to boolean, because arithmetic - is prior to |,{w:v-1!} convert v to number, decrement, convert to boolean then negate as boolean and finally assign to w,{i+j-k} (i+j)-k, because of left-associativity,{j~i+1} j=(i+1), because precedence of ~ is in between logic binary and arithmetic operators. 1. x.w (field selector; w taken by name!)
2. x(v), x[y] (function call and indexing)
3. !x, ?x, #x, @w (prefix unaries: one thing negate etc.)
4. x+y, x-y (left-to-right; arithmetic add/subtract)
5. x~y (equality)
6. x*y (boolean and)
7. x|y (boolean or)
8. x!, x?, x#, w@ (postfix unaries: whole shit negate etc.)
9. x,y (argument list separator)
10. w:x (assignment)
Formally:
class CalculateOperations {
// {v|w}
or(u, v) {
return this.toBoolean(u) || this.toBoolean(v)
}
// {v*w}
and(u, v) {
return this.toBoolean(u) && this.toBoolean(v)
}
// {v~w}
matches(u, v) {
if (isNaN(v)) {
return ("" + u).trim() == ("" + v).trim()
}
return this.toNumber(u) == v
}
// {v|0} - result is guaranteed to be boolean
// a string converts to false if (and only if) any nullish value would
// convert to that string
toBoolean(v) {
return !!this.toNumber(v)
}
// {!v} negate as boolean, result is always boolean
not(v) {
return !this.toNumber(v)
}
// {v+1} - numbers increment, result is never nullish (except for v = -1)
successor(v) {
var num = this.toNumber(v)
return isNaN(num) ? v : (num + 1)
}
// {v-1} - numbers decrement, booleans negate and convert to number
predecessor(v) {
var num = this.toNumber(v)
return isNaN(num) ? 0 : (num - 1)
}
// {v+0} - try converting to number, leave alone strings that fail parsing
toNumber(v) {
return Subtype.toNumber(v)
}
// {v~_} whether the string is blank; "" differs from "0" unlike in {!v}
blank(v) {
if (typeof v == "string") {
return !(v.trim())
}
return this.not(v)
}
// {booing(v)}
booing(v) {
return this.toBoolean(v) ? "true" : "false"
}
// {join(v)}
join(v) {
if (Array.isArray(v)) {
return v.join(" ")
}
return v.toString() //object? Observable?
}
}
Wiki: Calculate Language
Wiki: Home
Wiki: Scopes
Wiki: Templating
Wiki: The Basic Idea
Wiki: The Templating Program Data Block
Wiki: Two-way Binding
JavaScript keywords should be preserved, like true and false. Some engine-defined variables would be useful to enable more no-script functionality, like
observable[1], observable[2]as intrapage communication pipes? String literals are missing so much!Last edit: Csaba Skrabák 2024-04-20