Program
*******

 (The Program class was one of the first prototypes created, and has evolved poorly with the rest of the system. It is the base class for all compiled programs, and it glues together too many other systems with a terrible API and little to no encapsulation.

With that said, it is one of the least touched classes (thus its state); developers rarely have the need to touch Program.)

The Program is a declarative representation of an entire system. It is the highest level of abstraction from a data perspective. The user observes and interacts with a Program using the Program UI.

Programs contain a lot of metadata that is not in a convenience human-readable (or modifiable) format, some of which are redundant. Programs are ideally compiled from a Program XML document.

Program UI
==========

The Ui class, in addition to src/client/Client,Client (see Client), represent the two monoliths of the system. This mediates all UI-related tasks, and still has far too many concerns with far too many dependencies. Code is to be extracted out of this class as it is touched.

The Program UI renders a Program as a form.

At the highest level, steps are rendered in a tab-like manner, above the main form content. A step contains groups, which in turn contain elements such as questions. Groups are delimited in some manner defined by their style (see Group Styles).

Questions are rendered as form fields. Any time the respective Bucket field is changed, the form field is updated to reflect those changes, after having first been formatted with the appropriate validator (see Formatting Values). When a question is changed by the user, the value is expected to be propagated to the Bucket (see Bucket Assignment).

Navigation between steps can be done via the Navigation Bar above the step content, or using ``Go Back'' and ``Continue'' buttons at the foot of the step content.

A Sidebar is rendered adjacent to the step content. It displays the name of the Program, as well as configurable metadata (usually through the sidebar node of the Program XML). It also displays question help text (also configured through the XML) and any error messages (see Error Handling).

Group Styles
------------

Some group styles still use jQuery; they should be modified to use modern formatters and Liza DOM abstractions (see src/ui/field and src/ui/styler).

Groups support a number of group styles that determine how they are delimited from other groups (see Defining Groups); how the elements they contain are rendered and laid out; and how multiple indexes are displayed, added, and removed. A list of available styles is detailed in t:group-styles.

Name   Description   Multi-Index?   Add/Remove Index?

default

Groups are unstyled by default mdash they render elements as flat fields like a traditional form.
Only the first index of elements is rendered.
  N
  N

accordion

Styled as a stacked group with a header that toggles
the body associated with that index.
When collapsed,
only the header is visible for that index.
The default styling indicates the collapsed status using an arrow in
the header.
  Y
  N

collapsetable

Renders element label in the leftmost column like sidetable.
Indexes are groups of rows delimited by headings,
which collapse the respective group of rows when clicked.
  Y
  Add

sidetable

Renders elements as rows with label in the leftmost column rather
than the top row.
Each index is rendered as a column.
  Y
  Add

stacked

Groups respective indexes of elements such that one set of indexes
appears atop of another set,
much like separate groups are placed.
  Y
  N

tabbedblock

Each group is rendered as a block,
with each index rendered as a tab to the right of it.
Clicking a tab toggles the body content to the associated index.
Elements are rendered within the box.
  Y
  N

tabbed

Like default,
but each index has a tab at the top of the group.
Clicking a tab toggles the body content to the associated index.
  Y
  Y

table

A vanilla table with elements as columns,
their labels across the top row.
Each index is rendered in its own row.
  Y
  Y

Table: Group styles and index support

DOM Abstraction
---------------

jQuery is still used throughout parts of the framework and is a performance bottleneck mdash it needs to be fully removed and replaced with this DOM abstraction. (See src/ui/ElementStyler.)

Liza was conceived long before frameworks like React existed. The implementation originally used Dojo because of its broad widget set, but it was later dropped because of extreme performance issues, especially on the browsers of the day (Liza had to support Internet Explorer 6!); at one point, certain steps took over a minute to load for the most unfortunate of users. jQuery was then used for various parts of the UI and for ease of DOM manipulation, because of the lack of good and universal DOM APIs back then. It too became a bottleneck. Using DOM APIs is now easy with modern browsers.

Liza's DOM abstraction contains a couple of components:

  * DOM Fields represent a field on the DOM. Each field has a name and an index associated with the DOM node. Nodes are cached in memory after first access and queue requests during lookups to prevent stampeding. Provides basic DOM operations, including styling, containing row, and  parent/sibling selecting. See src/ui/field.

  * DOM Context is a slice of the DOM used for restricting queries. It can attach and detach sections of the DOM, and be further split into a context hierarchy. The src/ui/context,DomContext provides field querying (see src/ui/field,DomField) and caching. See src/ui/context.

It is important to always use these abstractions for any portions of the DOM under control of this abstraction; otherwise, assumptions used for caching may result in unintended behavior.

Using DOM contexts, DOM operations can be restricted to small windows (for example, groups or tabs), further reducing the impact of DOM queries.

The root context is represented by src/ui/context,RootDomContext mdash sub-contexts can be obtained by invoking slice on any context, which creates a new context from a subset of the parent. Detaching a parent will detach all child contexts.

Contexts can be manipulated in memory before being re-attached. Detach a context from the DOM with detach, and attach with attach. A context is aware of its parent and will re-attach itself to the DOM in the correct place. A child context always attaches to the parent, and so will not be rendered until the parent attaches.

Always detach from the DOM before performing extensive manipulations; this prevents the need for expensive re-painting until manipulation is done, at which point the context can be re-attached.

Field Styling
.............

src/ui/field,DomField is styled using field stylers (see src/ui/styler). The two most notable stylers are src/ui/field/ErrorFieldStyler and src/ui/field/NaFieldStyler, which style fields in error and hide fields that are no applicable respectively.

Program XML
===========

Defining Groups
---------------

A group organizes and relates entities. If given a title, a header will be displayed above the group with that title. A group may optionally be given a unique identifier id, which is useful for debugging and scripting; any such identifier should be snake_case.

       <group title="Foo Group">
         <question id="question_1" ... />
         <question id="question_2" ... />
       </group>

Figure: Defining a simple group with a title

Groups can be independently styled in a number of different ways to provide different data representations (see Group Styles). Style is optional mdash the default group displays only the first index of each entity. Further styling can be done using CSS using class.

All questions within a group share the same number of indexes; this is accomplished by monitoring the group leader. By default, the leader is the first indexable entity in the group (question, answer, or display); this can be overridden with the indexedBy attribute. This attribute is only practically meaningful if the chosen group style supports indexes (see Group Styles).

       <group id="leader_override" indexedBy="question_2" style="tabbed">
         <question id="question_1" ... />
         <question id="question_2" ... />
       </group>

Figure: Overriding group leader using indexedBy

Some group styles allow the user to add indexes; set locked to true to suppress this feature.

Linking Groups
..............

Data collection for similar entities may span multiple steps or groups; for example, one group may allow the user to define their risk locations, and a future group may ask for additional information for each of those locations. To have all entities within each of those groups share index length, they may be linked.

A group link is an arbitrary name given to a set of groups. Each group that wants to be part of the same link must set link to the same string. The name of the link does not matter mdash it is not a reference to a group id.

       <group id="location" link="locations" style="tabbed">
         <question id="address" ... />
         <question id="city" ... />
       </group>

       <group id="underwriting" link="locations" style="tabbed">
         <question id="diving_board" ... />
         <question id="rabid_dog" ... />
       </group>

Figure: Linking groups using link

In f:group-link, each question in LOCATION and UNDERWRITING will have the same number of indexes mdash any time a new index is added to LOCATION, UNDERWRITING questions too will gain another index and vice versa. There is no limit to the number of groups that can share the same link.

Linked groups are implemented such that the union of all fields in each of the groups of a given link are assigned to each of the individual groups. When the leader of any group changes, a new index is initialized for each group field, which (in the case of linked groups) is comprised of all fields in the link.

Specifying Predicates
---------------------

Object predicates (see Predicate System) are specified using the when attribute of certain nodes. It must contain a string of references understood by the system (see domain of discourse, Predicate System), all of which much match for the predicate to be true.

       <question id="describe" type="noyes"
                 label="Any special notes for this location?" />

       <question id="vacant_desc" type="textarea"
                 when="q:describe vacant property"
                 label="Show only when a vacant property with the
                        question 'describe' non-empty and non-zero" />

Figure: Using the when attribute

In f:pred-when above, question vacant_desc will be applicable when all of the values of vacant, property, and q:describe are true. (See Predicate System for what ``true'' means for a particular variable in the domain of discourse.) Within the context of the, this concretely means that the classifications vacant and property are true, and that the question describe is answered ``yes''. It reads as a sentence: ``vacant_desc'' is applicable when we should  ``describe a vacant property''.

Document Metadata
=================

Document metadata are metadata that describe certain aspects of the document; they are stored adjacent to the bucket in meta on the document root. (Terminology note: ``document'' and ``quote'' are the same thing; the latter is transitioning to the former for generality.) They should be used in place of a bucket field any time the client has no business knowing about the data. The meta record is called the Metabucket.

Metadata in the Metabucket should not be directly populated by external systems mdash integration should be used instead (see below).

Metadata can be populated using any mdash return data populate the Metabucket in the same way that they populate the Bucket. Definitions are stored in meta.fields, as shown in f:meta-fields.

     "fields":{
       ["string(name)": {
         "desc": "string",
         "dapi": {
           "name": "string",
           "map": {
             "string(dest field)": "string(source field)"
           }
         }
       }
     }

Figure: Format of meta.fields.

Further, a key-value mapping of all bucket fields that mdash when modified, need to result in a metadata API call mdash are stored in the mapis object; this is shown in f:mapis.

     "mapis":{
       ["string(field name)"]: [ "string(dapi name)", ... ]
     }

Figure: Format of mapis.