Workflow Information Storage Toolkit ("WIST") is a set of libraries and tools that allow multi-step workflow systems to be designed and deployed rapidly by abstracting workflows into reusable core components that can be added and arranged through a simple, intuitive configuration and template mechanism. The system also acts as a uniform application layer, which hides the details of the backend storage of information from the frontend user interface. This decoupling allows the backend storage engine and/or user interface to be changed independent of any other components in the system.
Workflows generated with WIST require the end-user to use a modern web browser, that supports at least DOM level 2 and ECMA-262 edition 3 standards. While our goal is to support the most common browsers and platforms, our testing is limited to Microsoft Internet Explorer 6 and 7, and Mozilla Firefox 2.0 on Windows XP. Some additional testing is performed using Mozilla Firefox 1.5 on Linux and on OS X. In general, your browser must support the Document Object Model (DOM), Javascript, and some form of the XMLHttpRequest or equivalent object for AJAX. Typically, this includes Internet Explorer 5+, Firefox 1+, Mozilla 1+, Safari 1.2+, and Opera 7.6+. Finally, the end-user's browser must have cookie support enabled.
Workflows are defined using a special template language. Each
workflow must contain a minimum of one workflow step as well as
information that allows WIST to properly store the data it has
collected from the various steps in your workflow. An unlimited number
of steps are supported. Even though workflow branching is supported, it
is recommended that the steps in a multi-step workflows be defined in a
linear fashion. WIST currently does not validate that a defined
workflow is properly configured to allow a user to reach the final commit
step (see Internal Block Declarations
section, below). Similarly, if branching is used, WIST cannot validate
that your workflow is free of cycles. Workflows should be thoroughly
tested prior to deployment!
Workflow templates are stored in the WIST workflow template
directory of your particular installation. You should consult with your
WIST administrator to determine where to create new workflows. Workflow
templates have the extension .wf
. The filename chosen for your workflow template (excluding the extension .wf
) becomes the name of your workflow in the WIST system. For example, if your workflow template has a filename of my_test_workflow.wf
, then the name of your workflow is my_test_workflow
. The workflow template contains two types of sections -- step declarations, which define each step of your workflow and internal block declarations,
which define how WIST handles your data for various operations. To
support creating records, each workflow template must contain at least
one step declaration and one commit
declaration. The following two sections describe how to create step declarations and how to define internal block declarations.
Each step declaration contains three parts. First, steps must be defined using a step block declaration, which minimally contains:
[stepName]
Step names must be a single word beginning with a letter followed by
zero or more word characters ([_A-Za-z0-9]). There are several step
names which are reserved by WIST as internal block identifiers and
which cannot be used to label any steps in your workflow. These names
currently include global
, load
, browse
, view
, edit
, and commit
.
These internal block identifiers define how WIST interacts with the
backend storage engine and therefore must usually be defined. Please
see the Internal Block Declarations sections below for more information about each of these special blocks, how to define them, and how WIST will use them.
You may also provide an optional description for any of the steps you are defining:
[stepName:Insert Description For This Step Here]
Step descriptions are not required however their presence will greatly assist end-users in identifying which step of a workflow they're completing. The description is used in the HTML document title and displayed as a heading on the rendered form. If no description is given, the workflow step's block name will be used instead and in most cases due to its formatting limitations, is less useful to end-users.
The second part of a step declaration is to configure step-specific options. At present these include the template
, nextStep
, exportEnv
, and type
attributes.
The template
value specifies which layout template
WIST will use to render this step of the workflow. If this option is
not specified, the automatic layout engine will be used to produce a
simple tabular layout (example below). The template
name will correspond to a WIST HTML template located in the HTML template directory of your installation with the prefix layout.
and extension .tmpl
. For example,
[step1:The Initial Step] template=myworkflow ...
will cause WIST to use the HTML template called layout.myworkflow.tmpl
in the WIST HTML template directory. For more details on creating WIST HTML templates, please see the WIST Macro Markup Language
section below. Writing custom WIST HTML templates is not required
unless the layout provided by the automatic template isn't suitable for
a particular workflow or workflow step. In all other cases, we
recommend using auto
for an aesthetically pleasing tabular form output (example below). The auto
template is used by default if a template is not specified or inherited from a declaration in the global
block.
The nextStep
value tells WIST to which step a user
should be directed upon completion of this step. In general, this
should refer to the next step in your workflow. There is an internal
block called commit
(described in more detail below in the Internal Block Declarations
section, below) to which the last step in your workflow should point.
Failing to configure the last step of your workflow to direct to commit
will prevent workflow data from being saved. Each step must explicitly define a nextStep
value. Branching is supported by specification of a field value's macro as part of the nextStep
value. This allows certain portions of your workflow to take different
paths based on the value or values specified in any previous step. For
example,
[step1:The Initial Step] template=auto nextStep=step2_%analysisType ... [step2_type1:Form for Analysis "Type 1"] ... [step2_type2:Form for Analysis "Type 2"] ...
specifies that the second step in the workflow be a function of the value specified for a field called analysisType. This could be a drop-down selection box with a number of different analysis types with values type1, type2, etc. It is also perfectly reasonable to branch, and eventually merge back into a single workflow step if only a portion of the workflow differs.
The exportEnv
value allows a particular workflow
step to export any one of the available environment variables to be
used internally by WIST, either as a display template macro value or as
a value in any of the internal block declarations. For example, this is
useful to capture variables exported by the web server, which often
includes the remote user's IP address and any authentication
information being used. For example, the Apache web server often
exports REMOTE_ADDR
, which contains the remote user's IP
address. Please see your web server's documentation for a list of
variables exported as part of the Common Gateway Interface (or CGI).
The type
value specifies the storage engine WIST should use. At present, only the type db
is supported, however we may support a file
based storage engine in the future.
The third and final part of each step declaration are the field declarations. A step declaration need not contain any fields. For example, in the last step of your workflow you may wish to present the user with the information they supplied and ask them to verify it prior to committing the information. In this or any similar confirmation step, only information from previous steps will be used in the display and no additional data is collected, therefore this particular step will not have any fields declared. In general, however, each step will contain at least one field declaration. Each field has a specific type, optional descriptive label, and optional verification criteria. There are also options specific for each field type. The general field declaration will look like:
fieldName = { type=fieldType ...fieldOptions... verification=...verificationOptions... ...otherFieldOptions... }
fieldName is a one word string defined similarly to the step name (above) and must be unique for each field within a workflow. The fieldName is referred to later in designing custom layout templates as well as in internal block declarations and therefore should be short, relevant, and easy to remember. Mixing up field names may result in your form being improperly rendered, or during other operations such as creating a new record or updating an existing record, may result in loss or corruption of data.
fieldType specifies the input user interface component to be
used in rendering the field. At present, ten (10) input component types
are supported, as defined by the table below. The column Supports Multi indicates whether the input component type supports the allowMulti
option. This option allows the input component to self-replicate up to the maximum number of components specified by the multiMax
attribute and is useful in cases where a particular field can support one or more values. Details on using the allowMulti
option are described below in the Field-Specific Options section.
Type | Description | Supports Multi |
---|---|---|
checkbox | On/off check box | no |
date | Date input component | no |
datetime | Date and time input component | no |
file | File upload component | yes |
multiselect | A list of options allowing a user to select one or more options | no |
parsed | A pseudo-field used to accept bulk data to be parsed and inserted en masse (see Parsed Fields below) | no |
radio | Radio buttons allow a user to select one of a number of predefined options where all options are visible | no |
select | Drop down box allows a user to select one option | yes |
text | Single-line text input box | yes |
textbox | Multi-line text input box | no |
time | Time input component | no |
WIST supports fields that can be used to accept bulk data to be parsed
and inserted en masse. Parsed fields are different from the other field
types in that it only makes sense to use them when creating new
records. When editing an entry from a workflow that contains a parsed
field, the parsed field will be disabled and a message will be
displayed above the form element stating This is a parsed field and is only used when creating new records
. When viewing an entry from a workflow that contains a parsed field, the parsed fields are treated as hidden
(see Field-Specific Options, below) and will not be displayed. The WIST
Browser supports parsed fields however you must configure the field to
be shown and define the appropriate database queries for populating the
field. Parsed fields still rely on an underlying field in order to
accept information. At present, only text
, textbox
, and file
fields are allowed. Please see the special parsed field options below.
Some attributes are always required and are indicated as such in their
respective descriptions.
Field Type Attribute | Description |
---|---|
subtype=<text,textbox,file> | (required) Specify the field to be used to accept the parsed data. At present, only text , textbox , and file field types are supported. |
format=<tab,csv,custom> | (required) Specify the format of the bulk data to be input. tab , the default if no format is specified, indicates the bulk data will be in tab-delimited format. csv
indicates the bulk data will be in Excel CSV, or comma-delimited
format. Data containing embedded delimiter characters must be enclosed
in double quotes to prevent incorrect parsing. The custom type allows you to define a regular expression using the customRegExp
attribute to capture entries from the input data. Use this type for any
data that is not encapsulated in tab- or comma-delimited formats. |
customRegExp=<regexp> | (required if format=custom)
Specify the regular expression to be used to extract individual entries
from the bulk data. Your regular expression must export subpattern
groups representing individual fields from the data that correspond to
the columns definition. |
columns=<c1,c2,...> | (required) Specify the names of the fields included in each entry in the bulk data. For tab and csv formats, this corresponds to the columns in the spreadsheet. For the custom format, this corresponds to each subpattern group that is exported by customRegExp . |
strict[=<boolean>] | Enable strict parsing. By default, entries that do not contain sufficient fields according to the columns
definition are still added with any missing fields blank. Also,
individual fields from each entry that do not match their specified
regular expression pattern regexp_<columnName> will still be added. Enabling strict parsing will prevent these rows from being added. |
regexp_columnName=<regexp> | Each column defined in the columns
attribute can also have an associated regular expression. Data from
this field or column will be tested against the specified pattern and a
warning will be generated if the input data does not match. In strict mode, the entire row will be rejected. columnName is case sensitive and must match exactly the column name provided in the columns attribute. |
Additionally, any of the field-specific options supported by the specified subtype
field are also supported. Please see the Field-Specific Options, below.
The data that is exported for parsed fields to the commit
block is also slightly different. The following table explains what macros will be exported and the format of the data.
Macro | Description |
---|---|
%fieldName |
This is the primary data structure which will contain the bulk data in
an array, therefore to access all data you must iterate over this data
structure using the foreach construct. Each entry contains exported macros according to the column names defined in the columns attribute. For example if you specified columns=a,b,c,d, each iteration of the foreach loop will export %a , %b , %c , and %d macros. |
%fieldName_file_id | If the parsed field subtype is file , the Pcapstore id for the stored parsed file will be exported using this macro |
%fieldName_num_entries | This value corresponds to the number of extracted entries. For tab and csv types, this will correspond to the total number of non-empty lines in the input data. For custom data, this will correspond to the number of entries extracted using the supplied regular expression customRegExp . |
%fieldName_bad_entries | This value corresponds to the number of rejected entries. This value will always be 0 unless strict mode is enabled |
%fieldName_bad_fields | This value corresponds to the total number of field values that failed to match their specified regular expression patterns. Note this does not necessarily mean the row was rejected. |
Each field type listed in the previous section supports its own set of modifiers, which generally control how the input component is rendered. For example, if you have a single-line text-input box, one option controls how wide the box is. Since there are very few field-specific options that are universal, each set of options for each input component type will be described below. Some attributes may be replicated from type to type and except as noted have the same modification properties across types. The following is a table of all presently supported field-specific options, by field type.
Type | Field Type Attribute | Description |
---|---|---|
global | default=<value> | Set the default value for any field. You must use a format compatible with the field type. For field-specific usage, see the default
attribute for the specific WIST field type. All fields support
retrieving the default value from a database query or on-the-fly using
an external function or field-dependent database query called using
AJAX. To use a database query use a value formatted as db:(host,user,password,database):<query> where host is the database hostname, user and password are the database credentials, and database is the name of the database or schema that contains the table or tables from which your query obtains the value, and query is an SQL query which must return at least one row with a column value corresponding to the value you wish to use as default. If multiple rows are returned, the value
from the first row is used. On-the-fly default values via AJAX can be
generated using an external function or database query. If your
database query does not depend on a value in the current workflow step,
you should use the database method outlined above. The AJAX method is
only required for external functions or for database queries that
depend on values in the current workflow step. To use the AJAX method
for an external function specify a value of ajax(function):<Namespace::Function(%field1,%field2,...)> where Namespace::Function
is the full namespace and function name of the external function and
%field1, etc represent field identifiers from previous workflow steps
or from the current workflow step whose values are required in order
for the external function to function. Only the fields you specify will
be exported to your external function. To use the AJAX method for a
database query specify a value of ajax(db_query[,host,user,password,database]):<query> where the database parameters are optional and identical to those described above and the SQL query follows the same conventions as with the database method described above. It must select at least one row containing a column value and should include references to at least one %field in the current workflow step. |
global | readonly[=<boolean>] | If true, the field's value cannot be changed |
global | hidden[=<boolean>] | If true, the field is not displayed in the entry viewer; this is useful for internal values |
multi | n/a | multi fields allow individual fields to be replicated dynamically by the user or by a linked value or field. multi is currently supported for text , select , and file and all multi options are available for each of those types |
multi | allowMulti[=<boolean>] | Allow multiple values to be submitted for a single field component. By default, multiShowMin input fields are displayed (or the value defined in the WIST configuration property multi[multiShowMin] , if multiShowMin is not declared) and up to multiMax (or the value defined in the WIST configuration property multi[multiMax] , if multiMax is not declared) input fields may be added dynamically by the user. |
multi | multiShowMin=<value> | If allowMulti is enabled, show <value> fields by default. If not declared, the value from the WIST configuration property multi[multiShowMin] will be assumed. |
multi | multiMax=<value> | If allowMulti is enabled, allow up to <value> fields to be present. If not declared, the value from the WIST configuration property multi[multiMax] will be assumed. |
multi | multiNumFields=<int or %field > | If allowMulti is enabled, the number of fields will be the number specified if multiNumFields is set to an integer value. If multiNumFields
is linked to a field and the field's value controls the number of
displayed fields. The linked field must be in the same workflow step or
a previous workflow step and its value must be an integer. The linked
field type can be text or select only. Specifying multiNumFields disables user-controlled adding/removing of fields and overrides any settings in multiShowMin and multiMax . |
checkbox | default=<boolean> | Set whether the checkbox should be checked by default; use a boolean value: true/false corresponding to checked/unchecked, respectively |
date | useCalendar[=<boolean>] | Enable the pop-up calendar for selecting dates? If this option is specified without a value, true is assumed. |
date | useFreeform[=<boolean>] | Enable free-form text input of the date? By default, each field of the date is selected from a drop-down box or selected from a calendar if useCalendar is enabled. If this option is specified without a value, true is assumed. |
date | default=<value> |
Set the default date for the input field. The date must be specified in
a format consistent with the WIST configuration property date[format] . The keyword now is supported and is also default if this option is omitted. |
time | useFreeform[=<boolean>] | Enable free-form text input of the time? By default, each field of the time is selected from a drop-down box. If this option is specified without a value, true is assumed. |
time | default=<value> |
Set the default time for the input field. The time must be specified in
a format consistent with the WIST configuration property time[format] . The keyword now is supported and is also default if this option is omitted. |
datetime | useCalendar[=<boolean>] | Enable the pop-up calendar for selecting dates? If this option is specified without a value, true is assumed. |
datetime | useFreeform[=<boolean>] | Enable free-form text input of the date and time? By default, each field of the date and time is selected from a drop-down box or selected from a calendar if useCalendar is enabled. If this option is specified without a value, true is assumed. |
datetime | default=<value> |
Set the default date and time for the input field. The date must be
specified in a format consistent with the WIST configuration property datetime[format] . The keyword now is supported and is also default if this option is omitted. |
multiselect | allowNewValues[=<boolean>] |
Allow the user to add new values to this select list? By default,
select lists are read-only. If this option is enabled, you must also
define the newValues attribute, which defines how WIST stores new values added through the user interface. |
multiselect | maxSelected=<value> | Limit the number of options that can be selected for an individual field to <value>. By default, unlimited options may be selected. NOTE: This feature remains unimplemented. |
multiselect | valuesSource=<source> |
Defines how WIST should populate this select list. As of the time of
this writing, select list values may be declared as a fixed set of
options or retrieved dynamically from a database using the following
syntax. For fixed option sets, define the list of values and
descriptions using opts:<value1:description1,value2:description2,...,valueN:descriptionN> . You may also omit the description for any of the values in a fixed set of options. The value will be used as the description if no description is specified. For example opts:<value1,value2:description2,value3> is valid and equivalent to opts:<value1:value1,value2:description2,value3:value3> . For database option sets, define the database parameters and SQL query for retrieving the value and description list using db(host,user,password,database):<SQL query> . The SQL query must alias the value and description columns retrieved to id and value respectively, such as in this example: <SELECT `userId` AS `id`, `name` AS `value` FROM `mydb`.`myusers` ORDER BY `name` ASC> . The id column contains values equivalent to the set value1,value2,...,valueN from the fixed option set and the value column contains values equivalent to the set description1,description2,...,descriptionN . In both cases, the id values represent the values that are internally stored by WIST whereas the value values represent the display values used in rendering the list only. |
multiselect | newValues=<storage> | If allowNewValues is enabled, and valuesSource
is not read-only (such as a fixed option set), this attribute defines
how WIST should store new values supplied by the user. Unfortunately,
since WIST deals with only an internal id value and display value, the
user interface only supports adding new entries by display value only.
For example, if selecting from a list of PCAP users where the user's
name is the option description, it must be possible to create new
values in the PCAP user database by simply inserting a row with the
name of the new user. In short, the id value must be auto-generated by
the database table and all other fields must be optional. WIST
currently does not support pop-up forms for creating new entries with
the ability to populate other fields. At present, only database storage
of new values is supported with the following syntax: db(host,user,password,database,table,id_key,value_key) . The table value specifies the name of the database table to which new values will be inserted and id_key and value_key specify the names of the fields representing the id and value
columns, respectively. When adding new values that require a unique
integer identifier, the table must automatically generate this id
through the use of an autoincrement integer primary key as WIST is
unable to generate these id values. |
multiselect | default=<value1[,value2,...,valueN]> |
Specifies which options in the select list should be selected by
default. Note, the value must match or or more of the values in the id column if valuesSource
specifies a database option set. Multiple values may be selected by
default by supplying a comma-delimited list of option values. By
default if this attribute is omitted, none of the options will be
selected. |
radio | default=<value> | Specifies which radio button option is selected by default. If not present, none of the options will be selected by default. |
select | allowNewValues[=<boolean>] | Allow the user to add a new value to this select list? Works similarly to the allowNewValues attribute for the multiselect field type; see description, above. |
select | valuesSource=<source> | Defines how WIST should populate this select list. Works identically to the valuesSource attribute for the multiselect field type; see description, above. |
select | newValues=<storage> | If allowNewValues is enabled, and valuesSource
is not read-only (such as a fixed option set), this attribute defines
how WIST should store the new value supplied by the user. Works
identically to the newValues attribute for the multiselect field type; see description, above. |
select | default=<value> | Specifies which option in the select list should be selected by default. Note, the value must match one of the values in the id column if valuesSource specifies a database option set. By default if this attribute is omitted, none of the options will be selected. |
text | width=<value> |
Specifies the width of the text input field, in <value>
characters. This modifier is browser-dependent and may not produce
identical results across different browsers. If not specified, the
value in the WIST configuration property text[width] will be assumed. If this value is not defined or if the value is set to 0 , the browser's default width will be used. |
text | maxLength=<value> |
Specifies the maximum number of characters that can be supplied as
input for the text input field to <value> characters. Note this
is an HTML limit, which some browsers may choose to ignore. It is
therefore recommended that this attribute not be used in place of the maxLength verification option, described below in the Field Verification Options section. If not specified, the value in the WIST configuration property text[maxLength] will be assumed. If this value is not defined or if the value is set to 0 , the HTML-based restriction is imposed. |
text | default=<value> | Specifies the default value for the text input field. If the default value exceeds the maximum length defined by the maxLength attribute described above, the value may or may not be truncated depending on the browser. |
textbox | width=<value> |
Specify the width of the multi-line text box, in characters. If this
attribute is not defined, the value in the WIST configuration property textbox[width] will be assumed. |
textbox | height=<value> |
Specify the height of the multi-line text box, in lines. If this
attribute is not defined, the value in the WIST configuration property textbox[height] will be assumed. |
textbox | default=<value> | Specifies the default value for the multi-line text box field. |
Values supplied by the user can be verified against any of the
following criteria by specifying the desired verification keyword, and
any required arguments in the formats described below. When multiple
verification criteria are specified, they are evaluated left-to-right
and must all evaluate to true. The only exception is when a field's
value is not required using the required
keyword. In this case, if the user's supplied value is empty or
contains only whitespace characters the value will be considered empty
and none of the verification checks will be performed. Most of the
verification checks are performed in Javascript, however some are
processed by WIST and require the form to be posted before the checks
can be performed. This accounts for the difference in behavior between
some checks being instantaneous versus requiring an additional
page-load.
Verification Option | Javascript? | Description |
---|---|---|
lengthRange=<range> | Yes | Requires the length of the supplied value be within the inclusive range specified as min-max, min ≤ max. Any leading or trailing whitespaces are trimmed before this verficiation criteria is tested. |
maxLength=<value> | Yes | Requires the length of the supplied value be less than or equal to <value>. Any leading or trailing whitespaces are trimmed before this verification criteria is tested. |
minLength=<value> | Yes | Requires the length of the supplied value be greater than or equal to <value>. Any leading or trailing whitespaces are trimmed before this verification criteria is tested. |
required[=<value>] | Yes | A value is required for the specified field. Any leading or trailing whitespaces are trimmed before this verification criteria is tested. For multi fields, specify as the value the minimum number of required values for the specified field, or the special keyword all that requires all multi sub-fields are given a non-empty value. For multi fields, if no value is specified with this attribute, one value is required. |
valueRange=<range> | Yes | Requires the supplied value be within the inclusive range specified as min-max, min ≤ max, for integer fields only. Javascript's parseInt is used on the trimmed string value to determine its integer value. |
valueRegExp=<regexp> | Yes | Requires the supplied value match the specified regular expression. |
function=<function> | No |
Requires the specified <function> return a true (integer value
'1') status value when given the supplied value as an argument. When
specifying the function, you must specify the full Perl namespace
unless the function is globally exported (which is not the case for
most user-written functions). The function takes minimally one input
argument, which is the user-supplied value, however when your function
is called two arguments will be passed in as arguments. The second is a
reference to a hash containing all of the current session variables,
which allows you to access the user-supplied values for any other field
in the current step of the workflow or from any previous step. To
access session values, use a key corresponding to the fieldName
specified for the field whose value you wish to retrieve. Your function
must return a reference to an array containing two elements. The first
is a status code -- an integer value '1' corresponds to successful
validation of the value and an integer value '0' corresponds to
validation failure. The second field is optional and generally only
used when a non-successful validation has occurred. It is used to
specify an error message to be returned to the user. The error message
will be prefaced by the string Field '<fieldLabel>' .
Your function should attempt to deal with all possible errors, however
in the event of a fatal error your function can return a scalar status
code. If the returned value is scalar, it is treated as an error
regardless of the value of the status code. |
in_set=<source> | No |
Requires the supplied value match one of the values in the specified
set defined by <source>. The set is defined similarly to the valuesSource attribute for select and multiselect fields. You may specify a fixed set of values by using the syntax opts:<val1,val2,...> . For example, the following would require that the user's supplied value be either 1 , 3 , or 5 : in_set=opts:<1,3,5> . You may also specify an SQL query to retrieve a set of values from the database using the syntax db(dbHost,dbUser,dbPassword,dbDatabase):<SQL query> . The <SQL query> must retrieve or alias at least one field called value
and only the values from this column will be used to build the set. The
query can reference any value from a previous step or the current step
in the workflow through the use of %macros . |
not_in_set=<source> | No |
Requires the supplied value not match any of the values in the
specified set defined by <source>. The set is defined identically
to the above in_set verification directive. |
There are several optional field attributes that generally provide for a more user-friendly workflow. It is recommended that as many of these field attributes be used when appropriate to assist the end-user in using the workflow. Other field attributes control how empty values are treated by the database storage engine and for providing more descriptive error messages for verification failures. You may also selectively disable the use of certain WIST features for a given workflow. The table below describes all of the optional field attributes.
Field Option | Description |
---|---|
dbNullValues=<val1,val2,...> | Specify a list of values which should be interpreted as NULL values by the database storage engine. The special keyword _blank_
can be used to describe an empty value. All leading and trailing
whitespace characters are trimmed from the supplied value before being
compared to this set. If this option is not specified, the value as
supplied by the user will be sent to the database storage engine. |
description=<value> | Specify a description of the field's purpose and any restrictions placed its acceptable values. The description is displayed when the end-user hovers the mouse over the field's display label. |
label=<value> | Specify the field's display label. This is used in the workflow to describe each input element. If this option isn't specified, the field's name will be used as its display label. |
verificationDescription=<value> |
Specify a more descriptive error message that encapsulates the
restrictions placed on the values for this field. By default WIST will
generate its own error messages, which are often not very
user-friendly. The error message is prefixed with the string Field '<fieldLabel>' .
Currently it's not possible to specify a different error message for
each verficiation criteria so a single message must be all-encompassing
of restrictions placed on this field's value. |
Internal block declarations are defined similarly to workflow step declarations, however the block identifier name is reserved and each internal block serves a specific function. Specifically, each block defines a basic operation required by WIST in order to interact with the backend storage engine. Not all internal blocks must be defined however your workflow will lack some functionality, according to the table below.
Internal Blocks Required | WIST Function/Operation |
---|---|
browse | WIST Browser capability allows users to browse data for a particular workflow allowing the user to filter and sorting data using any of the configured fields and presenting information in an easy-to-read paginated format |
commit | WIST's add record capability allows users to create new records for a particular workflow |
load , edit | WIST's edit record capability allows users to modify a record in a particular workflow |
view | WIST Viewer capability allows users to view a record from a particular workflow |
These blocks are required because certain functions require a field's display value whereas others require the field's internal id value. For example, a drop-down field is a list of options where each option has a unique identifier and some descriptive text. When you select a value, WIST stores only the unique identifier to save space in the storage engine, however when viewing an entry one would generally like to see the descriptive text instead of the unique identifier. Essentially, conversion of the WIST's internally stored values to the desired values is accomplished through the use of SQL queries, which must be defined in the blocks listed above if the associated functionality is desired.
Another example of this is a date field. SQL databases have an internal representation of dates and times that can be used for sorting and range/delta operations that may or may not be the same as the date and time format defined by your WIST administrator. Therefore, when a date or time is displayed it must be converted from the SQL internal format to the format defined by your WIST administrator, however if the user is sorting on a date field, we want to ensure that the internal SQL value is used in order to ensure proper sorting.
global
Block
If defined, this should be the first block defined
in your workflow. This block can be used to set global values for
certain attributes that apply to all workflow steps and/or some or all
internal block declarations. For example, if all of your workflow steps
use template=auto
, you can simply set the template
attribute in the global
block once instead of replicating it for every step. This has the added
benefit that if you wish to change a particular attribute later, you
need only modify it in one place. Other than the template
attribute, you may wish to define the storage engine type
attribute, along with the database parameters that would otherwise have
to be defined for the other internal block declarations: dbHost
, dbUser
, dbPassword
, dbDatabase
.
Use of the global
block is not required and it is
perfectly acceptable, albeit potentially more difficult to maintain, to
simply replicate the attributes for every block even if they have the
same value.
Here, you may also disable certain WIST workflow features by using the disableFeature
attribute:
Attribute | Description |
---|---|
disableFeature=<f1,f2,...> |
Specify a comma-delimited list of WIST features that you wish to
disable for this workflow. Select one or more from the following list: create , edit , view , browse . |
browse
Block
This block defines some necessary parameters in order for the WIST
browser to view the data generated through a particular workflow.
First, you must define the fieldOrder
,
which lists all the desired fields you wish to display in the browser
as columns and the order in which the fields should sppear. It isn't
required and it often isn't desired to display all workflow fields as
this may result in a view that requires the user to horizontally scroll
to see the entire table. The value for the fieldOrder
attribute should be a comma-separated list of fieldNames as defined in the various steps of the workflow.
If a field's value can be used for hyperlinking to another workflow browser or entry viewer, you should define its fieldUrl
attribute. The fieldUrl
attribute is an associative array where the fieldNames are used as keys and the value contains a URL generated using macros (see details below). Any of the retrieved values from this block's script
definition can be used, along with any global WIST attributes as defined by your WIST administrator. These include at least %cgiUrl
, %workflowCgi
, %workflowViewCgi
, %workflowBrowseCgi
, %workflowGetFileCgi
, and %workflowImageThumbnailCgi
. Here is a complete example:
fieldUrl[contact_user_id]=%cgiUrl/%workflowViewCgi/user/%contact_user_id_id
As mentioned above concerning internal vs. displayed date and time formatting, all date and time fields present in the fieldOrder
attribute must also have a sort
attribute. The sort
attribute is an associative array whose keys represent fieldNames and whose values map fieldNames
to internal table values to be used when sorting on date/time fields in
the WIST browser. The table field reference should include the table or
table alias as well, for example:
sort[start_datagen]=`tagless_frac_em_analysis`.`start_datagen`
The optional fieldLabel
attribute can be used to
overwrite the label given to a particular field. It is also an
associative array whose keys represent fieldNames. For example, if the label defined for contact_user_id
is too long for browsing purposes, one need only overwrite it using:
fieldLabel[contact_user_id]=Contact
The maxRows
attribute sets the maximum number of entries/rows to be displayed per page.
If the browser detects that a displayed file
field
contains an image, it will attempt to generate, cache, and display a
thumbnail if the image. You can control the thumbnail's width by
setting the thumbnailWidth
attribute. Image thumbnails
cannot be disabled other than by disabling the column containing the
image from being displayed in the browser.
Finally, the script
attribute defines the SQL query used by the browser to retrieve data from your workflow. The query must be defined on a single line.
This query is quite complex and you should start by first defining a
query which retrieves all of displayed field's internal WIST values,
along with the record's primary id value, which must be aliased to id
. If your data is stored across multiple tables, this will require JOIN
or sub- SELECT
queries. You must alias each retrieved field to match its corresponding fieldName
as defined by the workflow, except for internal id values which must be
mapped to display values. For these fields, you should alias them to
their corresponding fieldName and append the suffix _id
. For example, if a drop-down field's name is contact
, you should alias the internal contact id as contact_id
.
Next, you must join to all supplemental and referenced tables in order
to map internal id values to display values. The display value must
always be assigned to the fieldName defined by the workflow.
In the previous example, we would join with the referenced contact
table and retrieve the name value from that table aliased as contact
. Again, note, the internal id should be given an alias of the fieldName with a suffix of _id
(contact_id
in the example) whereas the display value is given an alias of the fieldName (contact
). Date and time fields, which require conversion from the SQL format to the WIST format require the use of the DATE_FORMAT
(present in MySQL) or equivalent function. Keep in mind that a literal %
(percent character) has a special notation of %%#
due to its use in the WIST Macro Markup Language.
Now that you have this query, it should retrieve a total of i + 2j + 1
fields, where i
is the total number of fields listed in fieldOrder
and j
represents the number of fields from fieldOrder
whose display values must be mapped from internal values, j ≤ i
. This query should retrieve all records associated with your workflow.
There are several internal macros defined specifically for the WIST browser and these must be appended to the query generated above in the correct order according to the SQL syntax of your backend database. The example given below indicates the exact SQL query suffix for MySQL.
The %sort_filters_
macro contains a HAVING
clause limiting which rows are returned by the database storage engine. HAVING
is preferred over WHERE
due to the latter's inability to deal with aliased columns, despite additional overhead incurred in using the former. The %sort_field_
macro contains the name of a field which should be used to sort the results in an ORDER BY
clause. Note, if you've defined a sort
attribute for a particular field, it's value from the sort
attribute is substituted as %sort_field_
instead of the field name itself. The %sort_direction_
is either ASC
for ascending sort or DESC
for descending sort and generally follows the ORDER BY
clause. Finally, the %start_record_
and %maxRows
macros define the starting record and maximum number of rows to return, respectively and in MySQL are used in the LIMIT
clause.
In MySQL, the following suffix should be appended to the query you generated above:
%sort_filters_ ORDER BY %sort_field_ %sort_direction_ LIMIT %start_record, %maxRows
The following is a fictitious example, to illustrate a proper browse
block. Note that if all of your workflow values are stored in a single
table with references to other tables, you may be able to use the WIST Builder to generate the entire workflow for you. See below for more details on the WIST Builder.
Our example workflow contains three values: a
, b
, and c
, stored in the table foo
corresponding to the workflow fields alpha
, bravo
, and charlie
, respectively. The table field c
is an SQL DATE
field and the WIST preferred date format is dd-MM-YYYY
or %d-%b-%Y
in strftime
format. Refer to your database storage engine's Date and Time types
section for conversion functions and how to properly use them. This
example assumes use of MySQL. The table field b
is an integer id value which references the table bar
. This table contains a number of fields, however we wish to use the name
field as b
's display value. The following browse
block is required for our example workflow:
[browse] fieldOrder=alpha,bravo,charlie fieldUrl[b]=%cgiUrl/%workflowViewCgi/bar/%bravo_id sort[charlie]=foo.c maxRows=10 script = { SELECT foo.id AS id, foo.a AS alpha, foo.b AS bravo_id, bar.name AS bravo, DATE_FORMAT(foo.c, '%%#d-%%#b-%%#Y') AS charlie FROM foo JOIN bar ON (foo.b = bar.id) %sort_filters_ ORDER BY %sort_field_ %sort_direction LIMIT %start_record, %maxRows }
commit
Block
The commit
block defines how workflow values are saved to the backend storage engine. In general, it involves defining the script
attribute, similarly to that defined in the browse
block, above. However, in addition, once values are saved, a template
is displayed to the user that usually notifies the end-user that
his/her entry has been saved. The template
attribute
defines which template is displayed to the user and its value will
correspond to a template file in the WIST template directory with the
prefix commit.
and suffix .tmpl
.
The script
attribute should define one or more SQL
statements, which will be executed sequentially, to properly store all
workflow field values into the database. Each SQL statement must be
wholly contained on a single line. All field value macros are available
and any values that must be post-processed or converted prior to
insertion into a database table must be handled by the SQL only. Any date
, time
, or datetime
field must be converted from the WIST string format to a format
accepted by the database server for each data type. In MySQL, this can
be done using the STR_TO_DATE
function, which uses strftime
macros, similar DATE_FORMAT
. Please see your database server's date/time functions for an equivalent function if you're not using MySQL.
Based on the example from the browse
block, here is the corresponding commit
block:
[commit] template=done script = { INSERT INTO foo (a, b, c) VALUES (%alpha, %bravo, STR_TO_DATE(%charlie, '%%#d-%%#b-%%#Y')) }
load
Block
The load
block only has a single attribute script
,
which defines how a single entry from your workflow is loaded for
editing. WIST allows users to edit entries using the same user
interface that allows users to create entries, therefore we wish to
load internal values as opposed to display values as in the browse
block except for date
, time
, and datetime
fields. These fields need to be converted from SQL internal values to WIST display values using the DATE_FORMAT
or equivalent function. Since this query is retrieving a single entry, you must limit the results using a WHERE
clause along with the special macro %edit_id_
.
[load] script = { SELECT a AS alpha, b AS bravo, DATE_FORMAT(c, '%%#d-%%#b-%%#Y') AS charlie FROM foo WHERE id = '%edit_id_' }
edit
Block
The edit
block is almost identical to the commit
block. The template
attribute specifies a display template to be used upon a successful
record update. The corresponding template file is also given a prefix
of commit.
and a suffix of .tmpl
, since both commit
and edit
use the same underlying processing engine. Finally, the script
attribute defines the query to use to update a single record. As with the load
block, a special macro %edit_id_
specifies the record's primary record id value. The script
attribute, like in the commit
block, must also convert display values for date
, time
, and datetime
fields to their SQL-equivalent format using the STR_TO_DATE
or equivalent function.
[edit] template=editdone script = { UPDATE foo SET a = %alpha, b = %bravo, c = STR_TO_DATE(%charlie, '%%#d-%%#b-%%#Y') WHERE id = '%edit_id_' }
view
Block
The view
block is similar to the load
block in that it contains information that tells WIST how to load values for a single entry. The main difference is that the view
block is used to load the display values for every field in the workflow whereas the load
block was used to primarily load the values stored by WIST (with the exception of date
, time
, and datetime
fields). Since this data is used to generate the view for a single record, it has some similar features to the browse
block, which controls how data is retrieved and formatted for displaying multiple records. As with the browse
block, fields which can be hyperlinked to other workflows or to external references can be configured via the fieldUrl
attribute. Likewise, you may also overwrite the defined label for a given field by using the fieldLabel
attribute. Also, file
fields that are determined to be images will be shown with a thumbnail preview automatically and as with the browse
block, the thumbnailWidth
attribute controls how wide the thumbnail is, in pixels. Finally, the script
attribute contains the SQL query to load the display values for every field in the workflow. As with the browse
block, fields that internally contain ids that reference other tables should have the id value aliased to the fieldName with a prefix of _id
and the display value aliased to the fieldName. The browse block contains more details. The record id is passed through a special macro %view_id_
.
[view] fieldUrl[b]=%cgiUrl/%workflowViewCgi/bar/%bravo_id fieldLabel[b]=Bravo! script = { SELECT foo.id AS id foo.a AS alpha, foo.b AS bravo_id, bar.name AS bravo, DATE_FORMAT(c, '%%#d-%%#b-%%#Y') AS charlie FROM foo JOIN bar ON (foo.b = bar.id) WHERE foo.id = '%view_id_' }
WIST Builder is a tool to create single-step workflows where data from all of the fields in a workflow are stored in a single table. You must first create the underlying table and establish all foreign key relationships before using WIST Builder to create the workflow template.
WIST Builder is divided into several steps. The first step is to configure the database parameters, then to select the database and table for which you wish to build a workflow. At this time WIST Builder only supports InnoDB tables in MySQL. As mentioned above, you must already have created the underlying table and established all foreign key relationships. In addition, your table must have an integer auto-incrementing primary key to be used as one of the unique record identifiers.
Once you have selected the table you wish to use, you are asked to configure some basic parameters about each WIST field derived from the fields in the selected table. The WIST Builder attempts to automatically set the basic parameters based on information retrieved from the database server, however you should check all fields for correctness. Fields identified as being foreign keys are automatically referenced to their parent record by WIST Builder. You may also exclude fields extracted from the selected table for which you do not wish to expose a workflow step field.
After configuring the basic parameters, the next step allows you to configure all of the WIST field details, such as the field label and any restrictions on the data type, such as its maximum length or regular expression pattern. For fields that are foreign keys to other tables, you are asked to select which field from the parent table will be used as the display value.
For fields that are foreign keys to the PCAP-specific enumerated value table, you are asked to select which value group label identifies the values you wish to use to populate the list. You must create any new groups in advance of using WIST builder as otherwise they will not be available for selection. PCAP-specific enumerated value groups are not present or available in non-PCAP installations of WIST.
Next, you will be asked to configure some workflow details, such as the workflow's name and some other attributes such as the maximum number of rows to display in the browser. After completing this step, WIST Builder will generate the workflow template for you and output it to the screen. At this point you can copy and paste it into a new workflow template file, modify anything the WIST Builder did not allow you to configure and finally, deploy the form for testing.
All web user-interface templates and SQL scripts (when appropriate) in WIST use the WIST Macro Markup Language to allow on-the-fly substitution of values using a macro replacement system, as well as basic value formatting, conditional statements, and iteration. This section is divided into 6 sections cover Macros, Data Formatting, Conditional Statements, Iteration, Display Templates, and SQL Script Templates.
Macros are specially formatted variables whose values are replaced on-the-fly by WIST. They must begin with %
sign and be followed by a macro identifier. This identifier must begin
with a letter and can be followed by one or more optional letters,
numbers, or underscore (_
) characters. Identifiers may be
of any length, however they must be unique within a template. Basic
variable scoping is supported such that new macros introduced within
the context of an iteration block may safely co-exist with other macros
having the same name. In this case, all global macros are copied and
new macros are added, overwriting any global macro that has the same
name. Once the iteration block terminates, the global macros are
restored.
A WIST display template contains a mix of WIST macros and HTML and is automatically expanded with all available macros replaced. For examples of how to write custom WIST display templates, please see the existing templates in your WIST template directory and see the section below on Display Templates.
Here is a short example:
<HTML> <HEAD> <TITLE>%title</TITLE> </HEAD> </HTML>
If the %title
macro contained the string "This is a
test!", the following would represent the translated template as it
would be displayed to the end-user:
<HTML> <HEAD> <TITLE>This is a test!</TITLE> </HEAD> </HTML>
Finally, if a macro must be separated from trailing word characters, you must enclose the macro's name in {
}
, for example %{title}
otherwise any valid characters will be assumed to be part of the macro name. For example, if you wish to append the word foo
to the macro %test
, specifying %testfoo
is invalid, however %{test}foo
will work as expected.
There are several built-in data formatting and conversion options,
generally meant for string formatting. They are listed below in a table
and any number of data formatting commands may be specified
comma-delimited following the macro name, enclosed in {
}
braces. If multiple data formatting options are specified, they are applied in left-to-right order. For example, %{test,lc,uc}
will first apply lc
(lower-case; see table below) and then will apply uc
(upper-case).
Formatting Option | Description |
---|---|
[i] | For array values, return a scalar corresponding to the specified index i ; see iteration below |
lc | All alphabetic characters in the string will be made lower-case. |
lcf | Only the first character in the string will be made lower-case. If the first letter is not an alphabetic character, this formatting option has no effect. |
len[gth] | Replace the string with a numeric value corresponding to its length |
ltrim | Remove leading whitespace characters from a string |
proper | The first alphabetic character of each word token will be made upper-case while all other letters in the word token will be made lower-case. |
rtrim | Remove trailing whitespace characters from a string |
substr(start:[len]) | Extract only the substring defined by the starting position (0-based) and length. For example if the macro %test contains the string "hello world", %{test,substr(0:5)} would display "hello". |
trim | Remove leading and trailing whitespace characters from a string |
uc | All alphabetic characters in the string will be made upper-case. |
ucf | Only the first character in the string will be made upper-case. If the first letter is not an alphabetic character, this formatting option has no effect. |
unquote | Unquote an escaped string, such as one escaped using DBI->quote() |
%printf | Reformat the value using the specified printf formatting option. For example, %{value,%0.2f} will format value according to the printf formatting option %0.2f . |
Conditional statements allow you to display (or not display) certain
elements or portions of your display template based on the value or
certain macros. For example, if there are no rows in a table one could
use a conditional statement to display an error versus displaying a
table header with no rows. The basic if
and else
constructs are supported using the syntax below. Having an else
block is not required. Unfortunately, a Perl-like elsif
construct is not supported and must instead be written using nested if
and else
statements.
%[if condition] ...display element 1... %[else] ...display element 2... %[endif]
The condition is a statement that is evaluated by Perl using the eval
function. This generally works as expected, with one exception as explained below. For example, the condition could be %value > 0
. You can even use the formatting options from the previous section in the condition, such as %{value,length} > 0
.
All macros and optional formatting options in your condition string
will be replaced first, then the string will be evaluated by Perl. For
this reason, when comparing string values, you must enclose macros in
double quotes. For example, if the macro %test
contains the string "this is a test", and the condition is %test eq "this is a test"
, the final string will be this is a test eq "this is a test"
,
which of course will not evaluate to a proper Perl expression. Adding
the double quotes around all macros solves this issue: "%test" eq "this is a test"
will work as expected.
Data structures generated by WIST that contain multiple records or values can be used for iteration using a Perl-like foreach
construct. If a macro %array
contains multiple scalar values, it will be treated as an array of
records containing a single key with the same name. As an example, if I
assign the array [1, 2, 5, 7]
to the macro %array
, the following display template:
%[foreach %array] one value from the array: %array %[endforeach]
will produce the following output:
one value from the array: 1 one value from the array: 2 one value from the array: 5 one value from the array: 7
For macros referencing an array of records, during each iteration pass,
the record's internal macros are exported. Since this block exports
macro values, you should pay close attention to variable scope. In
addition, a special internal macro %i__
is exported, which corresponds to an internal counter starting at 0
and incrementing for each iteration loop until n-1
for n
loops. This macro is generally not used for single array iteration but
is useful for parallel arrays (see SQL Script Templates, below).
%[foreach %array] one value from the array: %array [index: %i__] %[endforeach]
will produce the following output:
one value from the array: 1 [index: 0] one value from the array: 2 [index: 1] one value from the array: 5 [index: 2] one value from the array: 7 [index: 3]
There are two classes of display templates -- one class controls the layout of the various components of WIST such as the layout of fields in a workflow step or the layout of data in the WIST Browser, and the other class of templates are used for general display purposes, such as for notifications. In general, one need not ever create a display template as WIST is bundled with stock templates that work in most cases, however WIST's templating system provides a very flexible means to customize the look, feel, and usability of workflows and other WIST components.
General templates are further divided into two types -- internal templates and workflow-specific templates. Internal templates control the general look and feel of most WIST-generated pages and includes the page header and footer. Workflow-specific templates control all other non-layout aspects of the look and feel of WIST-generated pages, such as the message displayed to users when data they've submitted has been accepted and a new record created. Internal templates contain components that must be present in order for WIST to function properly and thus are described in more detail below.
For rendering of workflow-specific display templates, WIST will
always export scalar global attributes from the WIST configuration,
including attributes useful for building URLs, such as documentUrl
, cgiUrl
, imageUrl
, workflowCgi
,
etc. It is important to use the global attributes to build URLs as
static URLs may no longer function if WIST's configuration is modified.
Please see the table below of typical WIST attributes used in building
URLs. Please contact a WIST administrator for assistance with other
WIST global attributes.
Attribute | Description |
---|---|
cgiUrl | Contains the absolute URI path to the WIST CGI root (Default: /wist/cgi-bin ) |
documentUrl | Contains the absolute URI path to the WIST document root (Default: /wist ) |
imageUrl | Contains the absolute URI path to the WIST static image directory (Default: /wist/images ) |
jsUrl | Contains the absolute URI path to the WIST javascript directory (Default: /wist/js ) |
workflowCgi | Contains the name of the primary workflow CGI script (Default: wist ) |
workflowViewCgi | Contains the name of the WIST entry viewer CGI script (Default: wistView ) |
workflowBrowseCgi | Contains the name of the WIST browser CGI script (Default: wistBrowse ) |
workflowGetFileCgi | Contains the name of the WIST tool for retrieving documents from PCAPStore (Default: wistGetFile ) |
workflowImageThumbnailCgi | Contains the name of the WIST tool for generating thumbnails of image files asynchronously (Default: wistImageThumbnail ) |
In addition to scalar global attributes, WIST will also export one
macro for each field completed in previous steps. It is important to
note that the values associated with these macros are WIST internal
values and not display values. For example, a drop-down field will export a value corresponding to the id of the selected option rather than the description of that option. In addition, if you've configured exportEnv
as part of the workflow's global
block or current step's block, any of the listed environment variables
to export that exist will also be exported to WIST. For example, if the
workflow specified exportEnv=REMOTE_USER,REMOTE_ADDR
, the two macros %REMOTE_USER
and %REMOTE_ADDR
would be exported (assuming an Apache web server).
To summarize, any scalar value from the WIST configuration, values from exported environment variables, and values from fields of previously completed steps are all available when designing general workflow-specific templates.
There are three general internal templates that allow you to customize the overall look and feel of WIST pages, the footer
, header
, and error
templates. The header
and footer
are displayed before and after every page generated by WIST and
generally contain javascript, style sheets, and other basic formatting.
The error template is displayed for all WIST errors. These templates
have special macros and components without which portions of WIST will
not function. These macros and components are described below.
header
Internal Template
The header component is displayed before each page generated by WIST. It includes the page's title (%formTitle
),
loads required style sheets and javascript used by WIST, provides a
placeholder for WIST javascript data structures, and provides a hook to
allow javascript code to execute when the entire page has finished
loading. The general header structure should remain as is, however
changes to style sheets or the addition of a logo or other navigation
components can be added to the header.
The %dynamicScript
macro is a placeholder for
WIST javascript data structures. Since the macro's value contains
javascript data structure declarations and assignments, the macro
itself must be contained within tags otherwise it will not be correctly parsed by the end-user's browser.
Finally, WIST will export a macro %bodyOnload
which contains javascript to execute when the page has finished loading. Note that the ONLOAD
directive is guarded by a condition so that if its value is blank, the ONLOAD
directive will not be used. This is primarily used by the WIST browser
for asynchronously retrieving image thumbnails however it may be used
by other WIST components in the future. Omitting the BODY
statement shown below will result in these features no longer working.
The stock header
template is shown here:
<HEAD> <TITLE>%formTitle</TITLE> <style type="text/css">@import url(/wist/js/jscalendar/calendar-win2k-1.css);</style> <script type="text/javascript" src="/wist/js/jscalendar/calendar.js"></script> <script type="text/javascript" src="/wist/js/jscalendar/lang/calendar-en.js"></script> <script type="text/javascript" src="/wist/js/jscalendar/calendar-setup.js"></script> <script type="text/javascript" src="/wist/js/wistFunctions.js"></script> </HEAD> <SCRIPT LANGUAGE="javascript"> <!-- %dynamicScript // --> </SCRIPT> <BODY%[if %{bodyOnload,length} > 0] ONLOAD="%bodyOnload"%[endif]>
footer
Internal Template
Similarly, the footer
template is displayed at the
bottom of every WIST-generated page. It is much simpler than the header
having only one requirement, which is to insert a javascript
placeholder %postCheckAlerts
, which contain javascript-generated warnings and error messages for WIST-generated pages. As with the %dynamicScript
macro in the header
, the %postCheckAlerts
must also be contained within tags. The
footer
is a great place to put contact information for your organization and
to give users a way to contact a WIST administrator for assistance.
error
Internal Template
Finally, the error
template is used to display all WIST-generated errors. It has only one exported macro, %error
, which contains the specific error message. The header
and footer
are not displayed when an error message is generated.
This section describes what macros are exported for a given field in your workflow step and globally for all workflows, and how to use these macros to design your own display template. There are also required elements for every display template and some feature-specific elements that will prevent certain features from working if not implemented correctly. There are two types of display templates based on how information from the workflow is accessed. The first is an iterative display template that uses iteration to automatically display each field. This has the benefit of being fairly simple but has less flexibility as it requires all fields be rendered in a similar fashion, such as one field per row in a table. The second type is a custom display template. These templates allow you to place fields anywhere you want and are very customizable with respect to look and feel, however they are typically designed in a manner that does not allow the template to be reused for any other step in your workflow, or for other workflows.
Some components of a layout template are identical regardless of whether the fields are rendered iteratively or through custom placement. The first is the layout template header, which contains internal information used by WIST. An example header is shown below.
<form method="post" enctype="multipart/form-data" action="%nextUrl" onsubmit="return validateForm(this);"> <input type="hidden" name="__thisStep" value="%formStep"> <input type="hidden" name="__referer" value="%referer">
The layout template footer minimally contains workflow step navigation buttons, such as to return to a previous step or continue to the next step. Some of the following footer example may be changed so long as the display logic remains:
%[if %{prevFormStep,len} > 0] <input type="submit" name="__backTo" onclick="bypassValidation=true;" value="<< Previous step"> %[endif] %[if %{referer,len} > 0] <input type="submit" name="__backToReferer" onclick="bypassValidation=true;" value="Cancel"> %[endif] <input type="reset" value="Reset form"> %[if %nextConfirm] <input type="submit" value="Submit data"> %[else] <input type="submit" value="Next step >>"> %[endif] </form>
Some features of WIST require that field elements be encapsulated in table cells, where the cell is given an id
of field_%name
.
For example, when a validation criteria fails, WIST will attempt to
highlight the field in red so that the end-user is able to see the
problem field more easily. If the field elements are not encapsulated
in table cells, this functionality is disabled.
For example, you may have chosen to encapsulate the display of your workflow into a table. If you would like the navigation elements to be part of this table, you will need to modify the above footer appropriately. For more information on how to display the fields in a workflow step please see the following two sections.
Iterative display layout templates are the simplest way of creating
your own display template although it requires each field in a workflow
step to be rendered more or less the same way. This can be done in any
number of ways however in general, you will probably display the fields
top-down, one field per "row". Iterative display layout templates do
not allow you to choose the placement of each field manually, but you
can accomplish this instead using a custom display layout template. For
iterative display layouts, WIST will export a single macro data
structure called %formElements
containing all of the fields for a given workflow step. Using a foreach
loop, you can iterate over each field in turn accessing information
specific to each field that you'll need in order to display it. The
following table contains a list of the macros exported by each field
element:
Macro | Description |
---|---|
%element | The field's HTML element, self-encapsulated |
%label | The field's display label, or the field's internal name if no display label was defined in the workflow template |
%name | The field's internal name |
One example of how you might iterate over the workflow step elements follows:
%[foreach %formElements] <tr> <th class="vertical">%label</th> <td id="field_%name"><a name="anchor_%name"></a>%element</td> </tr> %[endforeach]
Here is an example of the layout generated by the layout.auto.tmpl
template:
It is recommended that you look at the layout.auto.tmpl
template, as it is an iterative display layout template.
Custom display layout templates allow you full flexibility in
placing the fields within a workflow step, however it requires that you
know a lot more about HTML and each step within a workflow will need
its own template as custom display templates are not portable to other
steps within the same workflow or to other workflows. Instead of
exporting a single data structure containing all fields, WIST will
export two macros for each field with the names %label_fieldName
and %element_fieldName
containing the field's label and self-encapsulated HTML element. As such, one must have a priori knowledge of all fieldNames for a given workflow step in order to design a custom layout template.
Using iterative display layout templates requires that each field be rendered independently, however in some cases you may wish to place two or more fields adjacent to each other and/or change the orientation of the field labels with respect to the fields themselves, such as in this example:
The above sample workflow is shown with three fields with names firstName
, middleInitial
, and lastName
, respectively. The custom layout template used to achieve the above display layout is shown below:
<link rel="stylesheet" type="text/css" href="/wist/css/wist.css" /> <table> <form method="post" enctype="multipart/form-data" action="%nextUrl" onsubmit="return validateForm(this);"> <input type="hidden" name="__thisStep" value="%formStep"> <input type="hidden" name="__referer" value="%referer"> <tr> <th class="alt" style="background-color: #a1cbf7;" colspan="3"><h1><font color=black>%formTitle</font></h1></th> </tr> <tr> <td id="field_firstName"><a name="anchor_firstName"></a>%element_firstName<div style="font-size: xx-small;">%label_firstName</div></td> <td id="field_middleInitial"><a name="anchor_middleInitial"></a>%element_middleInitial<div style="font-size: xx-small;">%label_middleInitial</div></td> <td id="field_lastName"><a name="anchor_lastName"></a>%element_lastName<div style="font-size: xx-small;">%label_lastName</div></td> </tr> <tr> <th class="alt" colspan="3"> <p> <center> %[if %{prevFormStep,len} > 0] <input type="submit" name="__backTo" onclick="bypassValidation=true;" value="<< Previous step"> %[endif] %[if %{referer,len} > 0] <input type="submit" name="__backToReferer" onclick="bypassValidation=true;" value="Cancel"> %[endif] <input type="reset" value="Reset form"> %[if %nextConfirm] <input type="submit" value="Submit data"> %[else] <input type="submit" value="Next step >>"> %[endif] </center> </th> </tr> </form> </table>
It is recommended that you avoid the use of custom display layouts as they are typically difficult to debug and maintain.
SQL scripts, such as those found in the internal block script
declarations, also use the WIST macro markup language. In general, the script
declaration contains just a single query (on one line), however both the edit
and commit
blocks allow two or more queries, one query per line. It is important
to reiterate that a single query must be wholly contained on a single
line. Queries may not be split over multiple lines at this time.
The use of macros within the SQL scripts should be obviously--simply use a macro in place of the actual value that you wish to substitute in before the query is executed. However, conditional and iterative constructs may also be used as needed. For example, a particular field may allow a variable number of values which are stored in a separate table and linked by the parent record's id. In order to accomplish this, one must first create the parent record, obtain its newly created id, then iterate over the field with the variable number of values inserting each value into a referenced table along with the parent record's id. Here is an example using MySQL:
[commit] template=done script = { INSERT INTO mytable (field1, field2, ...) VALUES (%field1, %field2, ...) SET @id = SELECT LAST_INSERT_ID() %[foreach %field3] INSERT INTO mytable_field3data (mytable_id, data) VALUES (@id, %field3) %[endforeach] }
If your commit
script inserts multiple records into one or more tables, you must insert the primary record last such that a query SELECT LAST_INSERT_ID()
will correctly retrieve the record's id. In cases where you must create
the primary record first, then subsequently add child or related
records referencing the parent record's id, such as in the example
above, you must store the primary record's id in a special variable @id
. Failure to do this will result in improper navigation links following the commit.
If you wish to create a parent record and along with multiple child records, where each child record has multiple fields, you must make use of the parallel array technique explained in the Iteration section above since each child record's fields will be returned to WIST as parallel arrays. Each child record's constituent fields will have the same index position in the parallel arrays, thus:
script = { INSERT INTO `table1` (....) VALUES (....) SELECT LAST_INSERT_ID() INTO @id %[foreach %childField1] INSERT INTO `table2` (...) VALUES (..., %{childField2,[%i__]}, %{childField3,[%i__]}, ...) %[endforeach] }
In the above example, we use the [i]
modifier described above (Data Formatting) with the internal iteration macro %i__
exported by the foreach
loop iterating over %childField1
to access each child entry's corresponding field values from the %childField2
and %childField3
arrays.