HFL ADVANCED CONCEPTS
- Like most interpretive languages such as javascript, HFL has an evaluator subsystem that parses text content into instruction sequences, and then evaluates (executes) them.
- And like most interpretive languages, this capability can be directly invoked via a function called eval().
- SYNTAX:
-
- The eval() function takes a string, and parses it as if it were enclosed in the HFL <\ and \> delimiters, executes the HFL instructions, and then returns the result, if any.
- The eval() function can be used in expressions, anywhere that a regular function can be used. The evaluated code will obey scoping rules, which means that the result will be the same as if the text of the string was physically located in the original code.
-
EXAMPLE:
- The following three sets of lines have the same result:
-
// Evaluate an expression that adds two variables
var a = 2, b = 3;
var c1 = a + b; // c1 = 5
// Evaluate an expression that adds two variables, using 'eval'
var c2 = eval('a + b'); // c2 = 5
// Do the same thing, but construct the string, then evaluate it
var $szA = 'a', $szB = 'b';
var c3 = eval("$szA + $szB"); // c3 = 5
- The eval() function can be applied to scope blocks when used in conjunction with the $text pseudo-variable. This allows entire sections of code to be assembled, and then executed.
-
EXAMPLE:
-
var $txt;
// Read in a file into div:3, and then capture the text into var $txt
div:3 {
include('sample.text', 'raw'); // Read in HFL instrs as just text
$txt = $text; // Extract the text into a var
}
// Perform some editing actions on var $txt
... // Modify it
// Now evaluate the modified string
eval($txt); // Execute it
-
- Precise alignment in HTML is difficult, for two reasons. First, the W3C specification allows browsers a lot of leeway in how they lay things out. Second, the W3C removed what little alignment there was, by removing the 'align' attribute. The result is that exactly what one must do to achieve a particular layout effect can depend greatly upon the context in which one is trying to do it. There is not a simple formula that will achieve effects such as 'center' or 'right-align' in all cases, or even most cases. So now it takes an expert understanding of HTML and CSS to align HTML elements with each other, in anything other than normal text-flow layout.
- To address the problem, HFL has an align() function that has a uniform syntax for all normal alignment orientations. It has internal logic to try to choose the best method of achieving a specific alignment behavior by considering the context of what is being aligned. It's purpose it to reduce the level of expertise required to do alignments, so that formats can specify layouts that will work across a wide variety of content.
- Alignments can be specified either directly using the align() function, or using shorthand alignment macros such as _center, _right, etc. that expand to calls to the align() function.
- SYNTAX:
-
where:<align-spec>:=[<scope-ref>] (<al-coords>) | <align-coord><al-coords>:=<align-coord> [, <align-coord>]<align-coord>:=<origin> [+ <offset> | - <offset>]<origin>:=<origin_keyword> | <n-coord><origin>:=left | center | right | top | middle | bottom<n-coord>:={x | horiz | y | vert} <percentage><percentage>:=a number between 0 and 100<offset>:=a dimension, e.g. '30px'
- The concept is that to align two cells to each other, you express a relationship between a coordinate in one scope and a coordinate in the other. The resulting alignment will be when those two coordinates are coincident to one another. Each of the two coordinates is a combination of two values: a percentage (or 'normalized coordinate'), and an offset in display units such as 'px'. Alignments can be specified as either pure percentages or pure offsets, or as a combination of the two.
- To help make the code readable align provides <origin> keywords that express both a direction (or 'axis') and a percentage at the same time. Thus 'left' means 'horiz 0%', 'center' means 'horiz 50%', and 'right' means 'horiz 100%'. Similarly, 'top' means 'vert 0%', 'middle' means 'vert 50%' and 'bottom' means 'vert 100%'.
-
For example:
-
align(#img1(center, bottom + 20px), #img2(center, top))
-
- would ensure that the center of the bottom edge of the cell with 'id=#img1' would align with the center of the top edge of the cell with 'id=#img2', with a 20px spacing between them. This relationship would obtain regardless of where either of the two cells were to end up.
- Any number of such relationships can be specified, allowing the creation of complex layouts when needed. The HFL align() function sorts through the alignment specifications, and assembles the specified spacing and indentation to create the desired effect.
-
A Limitation
- There is however a restriction.
- The 'align' function is greatly handicapped by the fact that HFL, being a compiler, does not have access to the run-time-generated data such as font tables that browsers use. Even if it did, the dimensions of such things as the display size of character strings in fonts can vary from browser to browser. Without knowing the exact size of HTML elements (cells) the HFL alignment algorithm may not be able to do a precise layout. In many cases, it can create the layout relationships without knowing the dimensions of the cells. But in other cases, the dimension data is required.
- For the align command to work at compile-time, it is often necessary for the application to set the dimensions of any cell that is aligned to other than the 'left' or 'top' of its parent. In some cases it may be required even then.
- If the dimension information is not provided, the HFL alignment algorithm will try to generate HTML code that does not depend upon knowing the dimensions. (A common example is to do centering by using 'margin:auto;'. But this does not work in many contexts.) When there is no dimension-independent way of aligning the cells, HFL will make a guess as to how to align things, but it may be inaccurate.
-
In cases where it must have the dimension information to be able to do the
alignment, HFL will issue a warning message that will look similar to this:
-
WARNING: ALIGNING CELL ORIGIN OF 117 TO PARENT BY PERCENTAGE: 100%
BUT CELL 117 NOT DIMENSIONED FOR X AXIS
-
- Rule of thumb: If you see such a warning message, provide dimensions for the axes (horiz (left to right) or vert (top to bottom)) that are being aligned. It is usually not necessary to provide dimensions for the other axes that are not aligned.
- For alignments to objects that may or may not exist, you can specify '?' after the keyword 'align'. This will suppress the 'SCOPE NOT FOUND' message when one of the objects does not exist. This allows you to specify alignments to create flexible layouts that can incorporate optional elements.
Scope-lists And Scope-list Functions
- Scope-lists are arrays, of cell numbers and/or scope references, that make it possible to apply a uniform set of actions or properties to a disjoint set of scopes. Where normal scope specifications must apply effects directly upon a range of cells, scope-lists allow for delayed action.
- Scope-lists are much more flexible than direct scope specifications, because they are simple arrays that can be constructed by any HFL application code. The code can create an array of cells or scope references at one point, then apply that scope-list to a block of code at a later point. The arrays can be constructed as the result of calculation, or by calling certain scope-list functions that return scope-lists (arrays of cells) and then manipulating them.
-
For example, when doing complex construction, it is often necessary to process
scopes in an order other than purely sequential by type. This is easily
done by creating an array that lists the scopes in the desired order, then
later apply that scope-list to a block of code. For example:
-
// Create a scope-list
var $my_scope_list = scope(p:2, p:3, p:1);
...
// Later process items in scope-list
scope($my_scope_list) {
// Do something to p:1-3 out of order
}
-
-
SYNTAX:
-
where:<scope-refs>:=<scope-ref> [, <scope-ref>]*<scope-ref>:=<scope-string> | <cell-num> | <cell-array><cell-array>:=an array of <cell-num><cell-num>:=an integer index number of a cell
-
- Scope-lists are just arrays, and can be created by simple application code. One easy way is to create an array whose values were assigned from the pseudo-variable $cell_num.
- Scope-lists can be also be created by scope-list functions such as the 'scope' function, with a parenthetical list of arguments separated by commas.
-
Each argument can be one of these types:
- An unquoted scope specification
- An array of cell numbers
- A cell number
- The scope-list functions compose a scope-list (array) by evaluating their arguments. Unquoted strings are treated as scope specifications, the specified scopes are searched for, and any cells that match are added to the match array. Array and cell number arguments are appended to the match array as is.
- The scope-list functions have two behaviors, depending upon whether they are running in scope context (used as scope specifications, i.e. are followed by braces), or running in expression context (used in an expression as an ordinary function). Once the scope-list match array is constructed, the scope-list functions check their context.
- If running in scope context (have braces), they execute the associated code block one time for each cell in the match array.
- If running in expression context (as functions), they return the array of cells that match the scope specifications.
- As a special case, a single scope reference can be specified without an enclosing 'scope()' function when used as a value in an expression (in expression context). This is just syntactic sugar that generates an implicit call to 'scope()', and returns a list of matching cells.
- For more information on the scope-list functions and their usages, see the section Scope-list Functions .
-
EXAMPLES:
-
IN SCOPE CONTEXT:
-
scope(header, body, footnote) { ... }
cut#js($js_cells);
cut#discard{scope($cell_num){}}
scope($scope_type:$scStart - last) { ... }
-
-
IN EXPRESSION CONTEXT:
-
if (scope(photo_gallery)) {
...
}
$js_cells = scope(js:1, js:5, js:9);
-
-
IMPLICIT SCOPE CALL IN EXPRESSION CONTEXT:
-
$div_cells = div:..all;
-
-
IN SCOPE CONTEXT:
-
An Example: Solving Complex Layout
- Scope-lists can help solve complex cell construction problems.
- As an example, to build a set of nested lists, the lower lists need to be organized into sublists, and then used as elements to the outer list. The simplest code to do that is a recursive function that processes depth-first. But this is not compatible with trying to enclose ranges in an outer container cell, because the enclose actions create intermediate cells.
- So this would require something tricky like creating temporary marks, building the containers, then cleaning up when done. Not only is this a lot more code, but it is inefficient, requiring several passes.
- With scope-lists, the application can collect the list of cells at one time, and perform operations upon them at a later time, without having to search for them again. In the nested list example, the depth-first scope search would build up the cell tree as an array of arrays. Then an outer 'scope' call could process them in top-down order, walking the cell tree and using sub-scope-lists extracted from each level of the tree.
- That is how the format that created this document calculates and creates the indentation levels.
- HFL provides another layer of abstraction with the concept of a 'state'. States are the foundation of the animation and morphing capabilities of HFL.
-
State containers
- HFL states are named containers for alternative versions of cells.
-
These alternative versions can simply be a different set of properties,
such as having a different color or visibility. They more often are
different physical arrangements, such as having a different size or
position. For example:
-
state (state1) {
p:1 {color:red; width:200px; left:10px; }
}
state (state2) {
p:1 {color:green; width:100px; left:110px; }
}
-
- The state containers are otherwise ordinary cells, and any normal HFL property assignments are valid within their code blocks. Any HFL code instructions are also valid, with the restriction that the code will be run at compile-time, not run-time.
-
Using states to do animations
-
Once a set of states have been declared, they can be used to perform animation
effects, by defining a timed transistion between two or more states.
For example:
-
morph (state1, 0, state2, 1);
-
- The above would activate an animation that would transition the cell properties of p:1 from those in state 'state1' to those of state 'state2', over the period of 1 second. The net effect would be that p:1 would change color from red to green, and its left edge would appear to slide to the right by 100px.
- State definitions make it very simple to define animations and morphs, and the scope syntax makes it very clear as to what will happen.