This draft is confidential property of FundsXpress, Inc.
Sam Hartman
Charles Lowell
Zane Rockenbaugh
Abstract:MIC, or Mesa Interface Compiler, is a tool meant to simplify Web interface design. MIC allows the embedding of Perl code and special MIC tags into an otherwise normal HTML document. The MIC code is then (com)piled by MIC to produce what is known as a pile (a partial CGI script) which is run via a pile driver.1
One central idea of MIC is to take the awkward HTML out of CGI and put the power of CGI into HTML. This is accomplished by providing HTML-like tags, which controls page look and data presentation, and the full functionality of CGI scripting in a simpler, more familiar environment. MIC can be thought of as a tool for creating dynamic HTML pages. In fact, MIC pages (i.e., HTML pages with MIC code) can be viewed directly in a standard HTML browser and will produce sensible, though probably not very pretty, results.
There are many other advantages that MIC has over standard CGI scripting, such as automation of security, field propagation and other features that are built into MIC.
This document is both a reference guide and a tutorial. If you are just learning MIC, you might find many of the concepts in this document a bit unclear at first.
It is recommended that new users of the system first skim through the examples found at the end, read the Overview chapter, then skim through the Conceptual MIC chapter and the Using MIC chapter2. Skimming the Suggested MIC-Compliant Datatype and FieldSpace Specification chapter (Appendix C) is also a good idea, as long as the new user takes note of the introduction to this section. Then, one should familiarize themselves with the various MIC tags, and then return for a more in-depth reading of the document.
Experienced users will find the document more helpful as a reference manual. The MIC Tags chapter has the syntax and description of each tag. The Cross Interface Requirements chapter might be useful to the experienced developer, but it is meant primarily as an implementation guide for the subsystems utilized by MIC. It is not really a user interface spec as it is a MIC interface spec.
Much of any Web interface is going to be a lot of HTML. If one is using traditional CGI programing, this means an endless repetition of print statements, here docs, or function calls punctuated by code. With MIC, the HTML portions of your page become simple, you write them just as you would any other. It is also trivial to take a concept or template page and make it into a fully functional interface. You need only embed the logic; the HTML will work just as it is. In fact, the completed MIC site source is logically laid out, as the user would think of it, in pages.
Though MIC is certainly useful on any size site or project, it is most useful in producing large interfaces which span many logical pages. MIC allows the programmers to treat the interface on a page per page basis; thus, site design and CGI programming are brought closer together. Besides this, however, MIC natively provides many useful features that enhance productivity and security.
With MIC, one is able to associate user data with arbitrary1 datatypes and perform arbitrary verification on the user supplied data. A good datatype will implement standard checks to further ease this process.
Furthermore, MIC will take note of what data is being asked for and only allow that data to be changed. Thus, MIC coders know what to expect and when to expect it. And since verification has been done by the time it gets to the developer’s code, they can trust that the data is atleast as good as the verification procedures.
One of the biggest advantages of MIC is native support for data propagation. So that data is not lost, all data entered into the fields of that fieldspace will be automatically propagated along an unbroken chain of pages which all use a given fieldspace2. This allows the generation of multiple page forms without worry about manual propagation.
Another important feature in MIC3 is its native support for robust error reporting and tracking. This allows a MIC-coded interface to easily resolve, report and prompt users to fix error conditions in user supplied data.
Finally, MIC has native support for dynamically generated fields. This allows users to enter as many logically-connected clusters of data as the MIC coder desires. That is, given a field template and rule, MIC will generate the necessary data fields as necessary. For example, we might use MIC to create a Web-based phone book, which could handle the addition and display of new entries. We define two fields, name and number, in a dynamic context (covered later). We tell MIC to display as many such clusters as are requested. In this example, we decide to display ten clusters at a time. The user would then get a page of ten name/number field clusters. They can enter data, then page on to the next set of ten clusters. Thus, users could enter 1, 100 or 1,000,000 bits of data, all using the same code.
To create a MIC pile, one creates a series of MIC-HTML pages, which may or may not have MIC-specific tags. All these pages must be under an arbitrary directory which we will call the Root-pile directory. When it is time to compile, the path to the Root-pile directory is given to the MIC-compliant piler, and it will then recursively process all pages under this directory which have a .html, .HTML, .mic, .MIC, .fs or .FS extension. Be aware that all other pages will be ignored unless explicitly included in a parsed file (by use of the MICinclude tag).
A control file is a file which, by convention, contains all the special MIC-defined subroutines setup, cleanup and handle_exception, which are useful programs to have for a given pile. 4 These special files are discussed in detail later.
The control file must be named ’control.pl’ and will be copied literally into the pile. This means that one should not HTML-escape within this file, since it is pure Perl code. One may wish to put some library subroutines in this file, although this is discouraged unless the subroutines are used directly and primarily by the special MIC-defined subroutines mentioned above. The recommended way of including library functions for use in the MIC code is to place the library file at the top of the control file and then calling the functions normally.
A compliant MICpiler takes all the .mic, .html, .fs5 and the optional control file (and other MICincluded files) to produce a pile. The pile should contain all the information necessary to properly execute the site, generate errors, control flow, etc. This pile is run by the Pile-Driver which interprets the code contained within the pile. The compiler must produce valid Perl code that conforms to the specifications in this document and is suitable to be run by an executable that conforms to the MIC-Driver specification (B). The driver component on the MIC system is the program that a Web server (or some other program) uses to execute the code contained within the pile.
MIC 3.0 designed on four basic concepts:
In a sense, MIC extends HTML with the above ideas. Of course, that analogy hardly does MIC justice.
The idea here is to simply add logic to to HTML pages which allow for conditional display and/or processing and to encapsulate pages into functions. The usefulness of this approach is shared code (HTML or otherwise) and more powerful, rich, and useful behavior of the pages without the clunkiness of CGI programming. Studying the example found in E.1 should provide sufficient insight into the meaning of this concept.
While not all forms must be associated with a fieldspace (see section 3.2.2, it is possible to do so using MIC. Associating a fieldspace with a form means that the data collected in the fields of the form is stored not only in the CGI object, but is also stored in a Fieldspace object. There may be numerous effects to this approach depending upon the implementation of the fieldspace and other factors. For example, it may cause updates in a database so that if a user’s computer crashes, the user can restart their session right where they left off. Apart from that, all fieldspaces form the basis for most of MICs more powerful features, aside from embedded logic.
All fieldspaces, no matter their implementation, are the basis of data verification and management, error reporting, etc. There are three central concepts concerning fieldspaces themselves:
A fieldspace contains, among other things, fields. Fields are associated with HTML input fields and are usually affected by user inputs1. Thus, it is best to think of fields as more or less the encapsulation of HTML input controls (readers will often find the terms used interchangebly).
MIC requires that every field be associated with a data type. The data type specifies what type of data to expect (e.g., a number, a name, a US state abbreviation, etc.), and how to display it. This is how error verification is handled2. It is through these fields, accessed through the fieldspace object, that data is most often manipulated and viewed within MIC.
There are two broad types of fields, static and dynamic. These names do not mean constant and variable, but are more closely related to an idea of static forms and dymamic forms.
A static field is one for which there will be only one instance. Drawing from HTML, if one were coding a form in HTML, all the inputs (i.e., fields) would be static. The distinction will be made more clear in the next section.
A dynamic field is best thought of in context of a dynamic form. A dynamic form is a form for which the number (but not the type) of inputs is unknown. A form to enter the number of new members to club might be a good candidate. Their might be one, two, or 100 new members. In this example, one could use statics, with member1, member2, etc. and just have an “Add More” and “Done” button, but there are other cases where such behavior is harder to code with statics (or standard CGI scripting) and dynmaics become far more attractive. This is especially so when tries to support error checking and reporting for the above mini-example.
Dynamic fields are coded somewhat as templates, and then instantiated as needed based on certain varying parameters, namely their index number and the value of the parameter num_display, which is covered in later discussions regarding dynamic fields. A single template can be coded and one, 100, or a million different fields can be created, tracked, reported and managed. This is especially useful when users are accessing existing data and want it displayed to them.
MIC provides numerous and rich facilities for data verification and error reporting. This was one of the primary forces behind the creation of MIC and was greatly expanded with MIC 2.0.
The idea here is to provide some basic security features that one would desire on all pages and make them automatic. This includes such things as helping to ensure data integrity and program flow.
One big concern with going through HTML is handling proper escaping and unescaping so that the user sees the proper value and the program sees the proper data. That is, if the user puts in <, we want the user and data to (usually) see < and not ‘<.’
Of course, it is important to understand how the myriad of pages, fieldspaces and bits will be executed. The first thing that happens when a page is requested is that the web server will receive the request and do its thing. Presumably, it will have some way of knowing that the request should be handled by a pile, say an extension or a certain directory and will redirect the request to the pile driver.
The pile driver then picks it up and will do its stuff. As far as the MIC coder’s code goes, this involves:
For more on the rules and specification governing fieldspaces and forms, see section 4.3 for more on forms, section ?? for more on default and arbitrary field code, and section ?? for specifics on MIC-compliant fieldspace implementations.
Because MIC is meant to be HTML-like and somewhat viewable by an HTML browser, it is necessary that all MIC code be HTML-escaped. How to and what to HTML-escape is not covered in this document, but users of MIC must be familiar with it.1
Do not confuse literal double quotes, < and > symbols with HTML control characters. For example,
<MICwhile test="test()"> hello </MICwhile>
Before discussing style and MIC coding standards, it should be mentioned that MIC currently has no native commenting. Commenting can be done through either Perl commenting (while within a MICPerl tag), or with HTML comments. Note that HTML comments, however, will be viewable in the final product. Thus, sensitive information should not be mentioned.
MIC style is compilicated by the fact that it involves not only HTML, but also logic and control code. Thus, one must approach the problem with an open mind. The following guidlines are the result of working with MIC and, thus, are in evolution. They are by and large, the work of Mr. Rockenbaugh and stem from his experience with MIC. As MIC comes to be used by others in different situations, it may certainly be found that the suggestions laid out here are non-optimal.
As noted above, the compiler will take direct cognizance of files ending in .html, .mic, and .fs (case-insensitively). Now the purpose of the latter two is clear and distinct. These files should (though, they are not required) to contain the definition for a single fieldspace.2
The difference between the code within the other two types, .mic and .html, is not so clear cut. Both types will be compiled into viewable pages, and in this respect, are the same as far as the compiler and driver are concerned. Stylistically, however, most pages should probably be of the .html type.
The .mic extensions should be used consistently within a site. Beyond that, they should, if nothing else, indicate ancillary pages that are mostly perl code. For instance, a page whose purpose is to look at state and direct users to another page (without accepting any user input or doing much output) could qualify for a .mic extension.
Proper indentation of a MIC page is one of the harder things to do. The main reason for this is that while HTML can be indented on conceptual groups, such as a table, rows, blockquotes, etc., and Perl and programming languages can be indented on logic blocks and lexical groups, how one properly indents a mixture of the two is a hard question.
In general, one must be more conservative about what is indented so that there is still room to indent when one wants to indent. Logical indentation should be favored over layout indentation, though large conceptual groups in the layout scheme should be indented for clarity, and these will often closely correspond to a logical block in any case.
A good MIC mode for emacs and/or other editors would be helpful as font coloring would add another dimension to the indentation scheme and make groupings clearer. For the time being, practice and common sense are the best guides.
Since MIC 2.0, compliant compilers must produce code that, if source code cooperates, be strictifiable. That is, MIC will introduce no undeclared or unscoped global variables. Since global variable errors have been found to be easy to produce and sometimes hard to identify, it is highly recommended that all but a few special variables be scoped to the page. To strictify a pile, one should include a ’use strict;’ statement at the top of the control file.
One should think of each of the following as a lexical block:
When, out of necessity or for the sake of efficiency, one wishes to pass variables between these lexical blocks, there are two recommended, but dependant, methods. The first is to include the ’use vars...;’ statement after the ’use strict;’ statement and simply have the listed variables be global. If this is done, be sure and include the special cleanup subroutine in the control file and undef each of the declared variables. This is to ensure that global state errors do not occur even when a FastCGI server is used to call the pile.3
There are two established cases where one should declare a global variable in this fashion. The first is to make global common objects or state indicators that will be needed by virtually every page and fieldspace.
For instance, if one were designing an interface to a MUD, then we might expect a Player object to be needed for the logic of virtually every page and fieldspace. To make said object available, we would do something like the following in the control file:
use strict; use vars qw($player); ... sub setup { #$cgi is made available by the pile driver my $player_id = get_player_id_from_cookie($cgi); $player = find Player($player_id); ... } sub cleanup { undef $player; ... } ...
The second established use for global variables is the use of a global variable used to pass information from one lexical block (see above) to another. This is often done for the sake of efficiency as it turns that a given page and its associated fieldspace (if there is one), will often have need of the same information. Also, the code within a MICdefine will very often require some of the same information that is determined in the MIC code in a different lexical block.
By convention, this special variable is called ’%pf_box,’ which stands for ’page/fieldspace box.’ Examples of how to use %pf_box can be found in various portions of this document.
Generally, if there is any setup or variables that need to be set up for a page, then these should be handled at the top of the page, as far as is possible and sensible. Variables local to the page should be declared, and if possible, set up at this point. This is to allow the page to be as much straight HTML, MIC logic-controls and snippets as possible (without random MICperl’s and such floating around).
By MIC data, we mean MIC fieldspaces. CGI data is the data found in HTML input controls. Both methods of passing and accessing data are available in MIC and each still have their place. There are two schools of thought on the subject.
The first is to only use the MIC facilities. That is, to have everything in fieldspaces and accessed through MIC functions.
The other method, preferred by the author, is to use MIC data for all user manipulated data and use HTML/CGI data for all flag data, or data that is never manipulated by the user or attached to user manipulated data. The advantage of this method is not usability or ease of use, but to maintain a logical division. Also, it has been found that this flag data can cross fieldspaces.
MIC provides many useful features regarding field management and such, but does allow one to use standard HTML forms. It used to be that you had to use standard functions in order to change directories properly. This is fixed in the latest release, but standard forms might still be used in order to reduce overhead for simple functions where MIC’s advanced features are not necessary.
The syntax for compiling a MIC pile is:
micpiler [-I <absolute include path from machine root>] <pile name> <output file name> <root of the pile source>
The optional -I argument specifies the directory to look for MIC included files (see 4.5.1) when they are not found in the proper place in the pile source.
The name of the pile is used internally, but, for convention sake, should be related to the output file’s name (which may be specified in a relative fashion). The output file name should generally be the pile name with a ‘.pile’ appended to it. The ‘.pile’ is the recommended extension used by servers to redirect proccessing to the piledriver (or a similiar script to handle the running of piles).
Finally, one must specify the root of the pile source. The compiler will start at this point (which may be specified relative to the current directory) and recursively traverse the subdirectories proccessing all files ending in ‘.html,’ ‘.mic,’ or ‘.fs’.
Compilers may take further options. See the compiler documentation for additional information.
By (enforced) convention, most MIC-specific tags begin with ‘MIC.’1 The few tags which do not begin with MIC are only found and are only valid within other MIC container tags. This helps to ensure that they will not be overrun by future HTML or browser extensions. There are basically three types of MIC tags. The first, a code snippet tag, is the only one that does not emulate HTML tag syntax and look. A second tag, the MICPerl tag, is for general purpose coding. There a number of other tags, however, that perform functions that could be coded directly in Perl, but which are so common as to be supported directly by MIC in order to maintain HTML consistency and ease the task of MIC markups.
Of these tags, some control program flow and page logic, such as MICif. Others are used within forms to display values or set up submit buttons.
[+ arbitrary evaluatable Perl token +] | (HTML-escapes) |
[− arbitrary evaluatable Perl token −] | (URI-escapes) |
[= arbitrary evaluatable Perl token =] | (verbatim) |
The Perl snippet mark is really not a tag, but simply declares a place to insert some arbitrary Perl code. The code cannot be greater than one line in length; that is, any code that requires a ‘;’ must go in a MICPerl and not a snippet. In fact, the ‘;’ is optional in the snippet.
Most generally, the snippet is used to print some value to the page. This value may or may not be viewed by the final user. That is, it could be used in an HTML link or what not. The three tags differ in their output. The first ( [+ ... +] ) will HTML-escape the result of the Perl code; it is therefore almost always the right thing to use except in links. The second ( [- ... -] ) will URI-escape, so it is almost always the right thing to use in links (and not elsewhere). The third ( [= ... =] ) does not process the code’s output and is rarely if ever appropriate.
Normally, code snippets will be inserted within an HTML document where
it is advantageous to maintain the look of the document, yet there is
some variable fragment which needs to be resolved at run-time (when a
user actually views the page). For example, one might have something
like:
Hello [+ $name +], how are you doing today?
or
<a href=http://[- $server || $default -]/face.html?flag=[- $flag -]>
Two notable limitations of the snippet are that commenting them out in any fashion will not prevent the code within from being executed, and that each snippet must be contained entirely on one line.
Note that since the [- ... -] snippet will URI escape, it cannot be used for the entire value of an href tag as it will likely screw up. ‘?’ and ‘&’ specifically will both be messed up.
<MICPerl>
arbitrary Perl code
</MICPerl >
The MICPerl tag defines a section of the HTML document as Perl code. It allows coders to integrate complex data gathering and processing functions directly into an HTML document. It functions much the same as the JavaScript tag in Netscape, except that it does not rely on a proprietary language.
The MICPerl tag is the preferred tag for any code over a line or so in length, or for any code not meant to print to the HTML page. It might be used to query databases, perform calculations or anything else Perl is capable of.
Only Perl code, and not MIC code, should appear within a MICPerl. Note also that MICPerl should not attempt to change the contents of the page2 as there is no guarantee that this will work as expected since the compiler will be unaware of changes made from within the MICPerl container tags. Also be aware that MICPerl tags are part of the re-evaluation process when pages are verified (see 5.2), and this fact needs to be taken into account since if a vpage is used, the code will be run twice.3
<MICif test="Perl conditional code">
arbitrary MIC-HTML code
</MICif>
The MICif is a special tag which allows for parts of a page to be conditionally constructed or proccessed4. This tag helps to maintain consistency in HTML look and avoids always having to use the MICPerl tag.
The MICif tag should be used whenever there are sections of the page or control code which should only be conditionally processed and/or constructed. As mentioned earlier, this tag could be subsumed into MICPerl (in certain cases), but that would break the HTML look and simplicity, which is the goal of MIC. Compare:
<MICPerl> if ($sufficient_funds){ </MICPerl> <h2>You have enough money</h2> <MICPerl> } else{ </MICPerl> <h2>Sorry, insufficient funds.</h2> <MICPerl> } </MICPerl>
to:
<MICif test="$sufficient_funds"> <h2>You have enough money</h2> </MICif> <MICelse> <h2>Sorry, insufficient funds.</h2> </MICelse>
The MIC code (which may include a MICPerl) contained within the opening and closing MICif tags constitutes a lexical block of code. This is true of all the MIC native logic tags.
MICif tags are only potent at runtime, however. A MICfieldspace within a MICif, for instance, is legal, but will actually have no effect. The MICfieldspace will be read at compile time and the fieldspace will end up being defined.
<MICelse [test="arbitrary test code"]>
arbitrary MIC-HTML code
</MICelse>
The MICelse tag subsumes the functions of an elsif (else if) and else. For a complete understanding of MICelse, be sure to reference the MICif section.
When given the optional argument, MICelse acts as an elsif statement. Otherwise, it will default to an else (essentially, elsif(true)...). This allows one to test for multiple possibilities and also provides the ability to hand control over a default section of code.
Note that a MICelse tag must immediately follow a MICif or another MICelse. There cannot be MIC-HTML between the end of one and the beginning of another. In fact, the only thing allowed between
</MICif>
and
<MICelse>
is whitespace.
<MIClist list="list or code to return a list" iterator=var
to map items to>
arbitrary MIC-HTML code
</MIClist>
MIClist is analogous to a ‘foreach’ command. MIClist is used to iterate over a list and perform operation on or display each element. The ‘list’ parameter defines how the list is to be generated, or may even specify a literal Perl list which is currently in scope. The ‘iterator’ parameter defines the name of the variable which shall contain each of the elements of the list. This variable will be lexically scoped to the block containing the MIClist. Example:
<table> <MIClist list="&get_accounts" iterator="$account"> <tr><td>Name: [+ $account->name; +] </td> <td>Acc. Number: [+ $account->number; +]</td> <td>Balance: [+ $account->balance; +]</td> </tr> </MIClist> <!-- $account is now out of scope --> </table>
might produce output something like:
Name: Mr. MIC Acc. Number: ad192381 Balance: $12,000.00 Name: Hojo McMorman Acc. Number: 918231 Balance: $0.27
<MICwhile test="arbitrary Perl code">
arbitrary MIC-HTML code
</MICwhile>
MICwhile provides a MIC native while loop that will iterate over the MIC-HTML code enclosed within the MICwhile environment until the conditional fails.
Generally, there will be some Perl within a MICPerl or snippet which will cause the loop to eventually terminate. For example:
<MICPerl>my $test = 0;</MICPerl> <MICwhile test="$test < 4"> Iteration: [+ ++$test; +]<br> </MICwhile>
would produce something like:
Iteration: 1 Iteration: 2 Iteration: 3 Iteration: 4
Like all the other MIC native logic tags, the MIC code between the opening and closing MICwhile tags constitute a lexical block.
Forms tags have been separated, because much of the complexity of MIC is introduced by forms.
<form ... [MICfieldspace=some legal name string]
[errorpage=a MIC-HTML page name]>
MIC-HTML code
</form>
MIC defines a necessary extension to the standard form tag. Each form that will contain MICinputs, MIChiddens MICdisplays, or that part of a page that is in a chain of pages for which the coder wishes to ensure data propagation, must declare its fieldspace name within the form tag.
The name must be defined somewhere within the files which MIC is compiling with a MICfieldspace tag. The fieldspace must be defined in a .fs file. For maintainability and style (though not mandatory), only one fieldspace should be defined per file. This does not mean that one cannot have non-MIC forms, however. It is possible to have such forms and access their variables while within MICPerl tags, as one would in standard CGI scripting.5 See ?? for stylistic notes on when to employ each of the differing forms.
The value of the errorpage attribute is the name of a MIC-HTML page in the pile to go to if there is an error encountered during the verification process. This will override the default value supplied in the fieldspace definition for this form only.
Note that it is at the form tag (if a MICfieldspace is specified) that the fieldspace object will be instantiated. Refer to ?? for how this will affect the execution of the page.
<MICfieldspace name=fieldspace name inherit=class name
error_page=an html page>
one or more MICdefines, zero or more MICverifies and no more than one
non-nested MICgroup
</MICfieldspace>
This tag and its included code defines a fieldspace object. These tags must appear in a .fs file and there should generally be one MICfieldspace tag per file with nothing but documentation and the tag in a given file.
The code bounded by the MICfieldspace form tags and external to all other MIC tags (MICdefine, MICgroup, MICverify) is treated as pure Perl code (though it is still necesarry to HTML escape the code). For this reason the logical MIC tags (MICif, MICelse, etc.) cannot be used here, and there Perl equivalents should be used (if, elseif, etc.). In addition, snippet markups or meaningless. Display tags also have no meaning and cannot be used. MICinclude may be used, however. This is because while a great portion of MIC code is meant to correspond roughly to HTML output, the code within the MICfieldspace is meant for proper setup and instantiation of fieldspaces, so has an inately different purpose, and therefore, form.
No MICfieldspaces (or MICdefines) parameters should contain hyphens (’-’).
It was true with MIC 2.0 and earlier that the name of the MICfieldspace must be unique with regards to page names. That is, if there was a page “new_accounts.html”, then one could not have name="new_accounts" in any fieldspace. Under MIC 3.0, there is effective mangling of the fieldspace names and this is no longer a problem.
It is recommended that the name of the file containing the fieldspace have the same name as the fieldspace plus ‘.fs.’ I.e., it is recommended that the line
<MICfieldspace name="new_accounts" ...
appear within a file called new_accounts.fs.
Note that there are a few reserved words that are disallowed as field space names. Specifically, ‘verify’ and ‘inherit’ are forbidden. Other than these, a fieldspace may by any string of alphabetic characters and the underscore. That is, it must match the Perl regular expression /\A[a-zA-Z_]+\Z/.
The inherit parameter specifies the class name from which the field space object to be constructed will inherit from. This will define certain behaviors, outside of the scope of this document, tied to the implementation of the MIC-compliant fieldspace. The type of behaviors this will control will be things like the life and scope of the data maintained by the fieldspace (subject to certain restrictions and minimums required by MIC), the mechanism of data propagation and retrieval, etc. It may even be possible to inherit from other existing fieldspaces, e.g., inherit="MICFieldSpace::new_accounts", but this is an untested feature which nevertheless should be supported in a later release.
The error page parameter defines the page to go to in case of an error. Further details are given later in section 5. Note that this is a default value and can be overridden by the errorpage attribute found in a form tag.
<MICgroup name=group name
[obj=name of special object variable]
[numvar=name of special indexing variable]
[numdisplay=default number to display per invocation of the MICdynamicdisplay]
[maxnum=absolute maximum number to display]
[dummyok="true"]
>
Group setup code and at least one MICdefine
</MICgroup>
All dynamic fields must belong to a MICgroup. There can only be one primary MICgroup in a fieldspace, although other MICgroups may be nested inside.6 This tag and its contents define the behavior and member fields for a dynamic field which can then be later accessed through a MICdynamicdisplay tag.
The group setup code is defined to be the Perl code within the MICgroup tags, but external to the MICdefine or other MICgroup tags. The expected and recommended use of this code is to set up $obj (discussed below). $obj can then be used as the information source for the field initializations within the MICgroup. It is common to have $obj be iterated (if indeed it is iterated) from some object or variable set defined in the initialization code (within the field space but external to the MICgroup). If $obj is static, then a statement such as:
$obj = $query_object;
is still required.
It is extremely important to realize the ramification for program execution, however. Unfortunately, the relationship of the $obj to the proper instantiation of fields is a bit involved.
The first thing to note is that the existence of $obj controls the halting of field instantiation in a non-dummy fieldspace and the point of dummy production in a dummy fieldspace. That is, if you have a fieldspace that is not a dummy fieldspace, and your code dictates the creation of 5 $obj’s, then you will get a maximum of five field groups total. If the fieldspace allowed dummies, the 6th field group and up will be dummies. Note that this means that in the initalization code of the MICdefine, one must not depend on $obj for dummy fieldspaces... it won’t be there. See section 4.3.4 for more information on this.
$obj should be independent of the order of indices defined by $index (discussed below). That is, it should either ignore $index or not depend on the order of $index. So, if we have:
$obj = $batch_retriever->get_nth($index);
If we get $index as 2, 20, 1, 5, in that order, the code should react reasonably. So, wanting to look back at the previous $obj or assuming that the previous $index was one less that the current will cause problems.
The fieldspace variable is made available as $fs within the group setup code.
A dummy field is a dynamic field for which there is no $obj (they, thus, must occur in groups since $obj is defined for a group). As for as ones MICdefine code goes, these fields must be handled (by testing on the existence of $obj or by not requiring $obj), but they act the same. The purpose of the distinction is to support two common functions of dynamic fields.
The first category is where a form is meant to support n user inputs where n may be limited (by maxnum) or infinite. In this case, we would want to support dummyok to be true since some or all of the fields might have no dependency on prior data.
The second category, for which we would want to set dummyok to false, or leave the parameter out, would be where we want to allow users to edit existing data, but not add anything of their own. In the latter case, it is obvious that once we run out of $obj’s (where each $obj is a package of existing data for a group of fields), we don’t need to create any more fields (or groups) and so stop.
This, in short, is the interaction of dummyok and the existence of $obj.
Generally, the value of the obj attribute should be $obj (which is the default if the attribute is left out), because this is safe and will be quickly understood by other MIC-coders by convention. Also, other names may overrun special variables or global variables. Thus, this convention also mandates that no global variable called $obj is created within a pile. (Note that $obj is used in the text to refer to that thing in code samples and in documentation.)
If there are nested groups, then a scheme such as $obj1, $obj2, etc. is preferred. If, however, this is unclear (especially if multiple objs are accessed in MICdefines which are members of nested groups, one could more reasonably consider more descriptive names. Nested names, however, must be unique within a fieldspace. No guarantee is made on what will happen if these names clash.
The value of numvar should generally be set to $index for the same reasons. $index is the default that will be used if the attribute is left out.
Within the MICgroup (and nested MICgroup’s), all MICdefine initialization code will have $obj and $index made available to it. While $index is set by MIC code, $obj must be set by the MIC-coder in the group setup code.
<MICdefine name=variable name type=IO class
data=data container class>
list to be passed to datatype constructor or list constructor[;;
Perl code to be executed in order to set up the field]
</MICdefine>
MICdefine is used to define field types—how they will be displayed and the type of data they contain. Any piece of data which may be queried from or displayed to an end user should be MICdefine’d. MICdefine tags have an undefined meaning outside of a MICfieldspace tag.
Putting conditionals around a MICdefine (or any other fieldspace tag) has no effect. There is a fundamental difference between the setup code or group setup code (the code external to the MICdefine but within a MICfieldspace and possible MICgroup) and they occupy different lexical groups, even though bad style may make this distinction unclear. For this reason and for simple style and purpose, code within the code blocks following should be side effect-free with regards to all data except for the field itself.
The name parameter of MICdefines within the MICfieldspace do not have to be globally unique, but must be unique within the entire MICfieldspace. MICgroups within a MICfieldspace do not constitute separate namespaces.
The type parameter identifies the datatype to associate with this field.7 This must be the name of a MIC-compliant datatype, discussed in 9.1.
The data parameter is the name of a data encapsulator class to be used by the datatype specified in type. Depending on the implementation of the MIC-compliant datatypes being used, the separation of these two parameters may seem unnecessary or even cumbersome and spurious, but examples and justifications can be found in 9.1.
Immediately after the > follows the default specifier. This is treated as the contents of a subroutine in the pile’s top package (i.e. global pile variables are available); braces are optional. Often this is a single constant value or a short constant list, but more programmatic code can be included. There are many cases where multiple values are expected; for more on this, see 8.
As noted in 3.1, this code block will not be executed if MIC believes that there is data present which should override the default data. It is a good idea to make your default data code side- effect free. Return the list of values, but don’t go off and execute arbitrary programs or mangle data, etc.
$obj and $index (and all the obj’s and indexes of parent groups) will be available in this code block and the arbitrary code block, if they themselves are available. Your code should never depend on any of these, however, as described in 8.2. Note that $fs and $field are not currently made available here.
The arbitrary and optional code defined within the block following the double semicolon (which is itself optional if no arbitrary code block is defined) is executed as the last step of field initialization (see 3.1). Within this block MIC coders will have the special variables $fs and $field made available to them; at runtime these will be the fieldspace object and the field object respectively.
Specifics on the field object can be found in the documentation accompanying the MIC-compliant fieldspace implementation being used in your MIC system. The MIC interface specification can be found in 9.2.
Dynamic MICdefines are any MICdefines within MICgroup container tags. Dynamic fields are discussed in more detail later. At this point, it suffices to note that within the code block, the object vaiarble and numvar variable will be made available through the action of the MICgroup tag.
<MICverify name=name for this verification test=test>
MIC-HTML code to be run... hopefully with a well defined purpose
</MICverify>
MICverify is used to provide special verification procedures which are not handled by the datatype verification procedures. It provides for arbitrary tests and reports.
MICverify’s are contained within a MICfieldspace tag. The name parameter assigns a name to this MICverify. Later, in the MICsubmit tag, one can specify MICverify names which must pass in order for the form to pass the verification process.
The test parameter may be either a block of code or a function name to call. A simple conditional statement is not sufficient because of the accounting necessary for MIC’s error tracking and reporting functions. More about the necessary accounting in ??. For now, it will simply be noted that the code or subroutine must return a boolean where a true value indicates that no errors where found and a false indicates that an error was found, and thus, the associated error text contained between the tags should be processed and displayed when requested (with a MICerrorreport).
One may use a MICverify for the purpose of conditional verification. That is, there may be a situation where the user may want to verify fields A and B and run the verification X if parameter P is set, and perform no verification otherwise. This may be accomplished by using the verify_fields() and verify_verifies() functions defined as necessary for a MIC compliant fieldspace implementation. See 5.1.2 and C.1.1.
It is assumed (and highly recommended) that one will redisplay any fields involved in a failed test. This will give the end user the chance to change faulty data without having to return to an old form. See 5.3 for more about this.
Note that the MIC-HTML contained between the tags is deprecated because it may not include certain MIC tags. Specifically, other MICverifies are excluded (as well as MICfieldspace and MICdefine, obviously).
<MICsubmit
name=binds to an HTML control
value=unique among MICsubmits of the same name, matches an HTML control
goto=absolute location to go to after successful verification
[unconditional="true"]>
[<vfield name=MICdefine’d field name within fieldspace to verify >]
[<vpage name=A page to be re-evaluated and verified >]
[<vverify name=A MICverify defined for this fieldspace to be called >]
[<vpresent>]
</MICsubmit>
This tag is used to declare how to handle submit buttons within a MIC form. Each MICsubmit must be associated with an HTML control of the same name/value designation.
The name parameter should generally be common to all the related submits (MIC and regular) buttons for the form which this tag appears on (though not expressly non-unique for other forms, even those sharing the same field name space). The recommended value for the name attribute is [page name]_submit. That is, if the submit buttons are to appear on a page called ‘result.html’, the recommended name value would be ‘result_submit.’ This is mainly to keep things regular and easy to follow, although just about any name will work. If one has multiple forms on a page, then the recommended naming convention is ’result_submit1’, etc. This is a style issue, though.
There are reasons to have MICsubmits with differing names, however. One is if one wants to implement variable goto’s. Because of the way MIC works, the goto parameter cannot be a variable. That is, ‘goto=“$foo”’ is not valid code. One could have something of the form:
<MICsubmit name=``test_submit'' value=``Submit'' goto=``analyze_test''> </MICsubmit> <MICsubmit name=``quiz_submit'' value=``Submit'' goto=``analyze_quiz''> </MICsubmit> <input type=``Submit'' name=``$destination'' value=``Submit''>
The name/value pairs are used to bind the MICsubmit with the standard HTML controls. Unlike MICinput and MICdisplay, a standard matching HTML control tag must also be included and will not be generated for you. The matching control will most often be a control button, but does not necessarily have to be. It may also be an image-map designation, or even some a hidden input or radio button. When the form is submitted, the value will be resolved control will be passed to the associated MICsubmit.
Thus, when one does have different names for the MICsubmits and their associated controls, one must be careful that two can never be defined at the same time. This is also a concern, actually, if they all have the same name. Thus, while the page flow can be directed by a hidden, a radio-button group, a button cluster, or an image map, having both a button cluster and a radio-button group will have unpredictable effects as MIC will not know which parameter to use.
The goto parameter defines the absolute URL within the system to go to after a successful submit. Refer to MICinclude for an example of this. This page does not necessarily have to be in the same directory and multiple submits can have pages in various directories (which is a win over regular HTML submits and form control). Realize however that each submit will share the target of the form tag, so to support multiple targets, it is still necessary to break the control over multiple forms.
If the attribute ‘unconditional’ is included with the value of ‘true’, then the goto parameter will be invoked even in case of error. This should be included only in the case where you want to go to the next page even if there are errors produced by the verifications associated with the MICsubmit where the unconditional parameter appears. This may be the case with certain styles of error reporting.
Note that old errors (from previous pages in a series) will not cause execution flow to redirect to the error page. Only errors produced by the current page/submit will be redirected.
The three optional included tags, vpage, vfield and vverify define pages (e.g., relative URLs), MICdefine’d fields and MICverify’s, respectively, that need to be checked to see if there was bad data entered in the form. You may have as many or as few of these optional tags as you wish. These tags, and the vpresent tag, are discussed in section 4.4. Note that these tags only have meaning in the context of a MICsubmit and that no other tags or naked text has any meaning when contained by a MICsubmit.
Finally, the no-reset-dynamic attribute should be included if one wishes to start counting dynamic fields from the current dynamic field. This should generally only be included if a page is self-referencing, in which case MICrollover and MICrollback should most likely be used.
An example of a MICsubmit would be:
... <MICsubmit name="application_submit" value="Submit" goto="application/process_application"> <vfield name="applicant_name"> <vfield name="applicant_ssn"> <vverify name="enough_money"> </MICsubmit> <input type="submit" name="application_submit" value="Submit"> <br> <MICsubmit name="application_submit" value="Cancel" goto="home"> </MICsubmit> <input type="submit" name="application_submit" value="Cancel"> ...
<MICdo name=name of tied dynamic field
numvar=variable in which to place the current index>
code to be executed upon each instantiation
</MICdo>
MICdo’s are only valid within forms. Their purpose is to “do” something to each instantiation of the dynamic field specified in the name attribute. Within the MICdo, $field is made available to the coder to modify and check. MICdo’s are not necessarily expected to be side effect-free with regards to other variables, but they should be nice from a maintainability/debugging standpoint.
Also available within the code block is the variable specified by numvar. Before we continue, let us look at an example:
<MICdo name="name" numvar="$index"> $val_hash{$index}->{name} = $field->value(); </MICdo>
For every field present, the group iteration index of that field will be used to key an anonymous hash. The string name will then key the value of the field name corresponding to the group iteration.
So, what do we mean by group iteration? When dynamic fields are created, the first one to be created is the first group iteration, the second the second, etc., etc.
Of course, the astute reader is now wondering what fields are present. Under MIC 2.1 and greater, the fields present are those which are needed to be displayed, those which have changed from their initial values (those fields which have had user input which is not exactly equal to the original value), those that are in error, or those that are members of a group where some field in that group meets the previous criteria.
These facts are often exploited in the use of a MICdo. For an example, see E.2.
<MICinput name=MICdefined variable name [no-format=“true”] [edit_test=“test”][changflag=variable]>
MICinput is analogous to the standard HTML <input ...> tag. The size of the input field created, its default value (if any) and other attributes are defined earlier in MICdefine.
MICinput is used to create input fields on forms for MIC defined values. It must only be used within the <form...> tags which have the optional fieldspace parameter. The name parameter takes a MICdefined name which has (or will be) defined for the MICfieldspace of the current form.
Note that the MICinput does not overwrite the normal <input ...> tag, but is in addition to it. That is, one may freely mix MICinput and input tags and make use of both. Realize, however, that there is no MIC-supported checking and verification for non-MIC input, nor will the data be saved to the database, etc.
Non-MIC fields should be controlled through standard HTML inputs and MIC defined fields should be controlled through MICinputs. A MICinput with a non-MICdefine’d field and a standard HTML input with a MICdefined field are both undefined.8
MICinputs handle both static and dynamic fieldspaces. If a dynamic field is requested outside of a MICdynamicdisplay, then the results are undefined. Currently, it is also not permissible to have non-dynamic field within a MICdynamicdisplay since this is almost always the wrong thing to do. This may be supported in future releases, however.
Also, any MICinput will automatically attempt to format the value before displaying it. This means that the data may change form, but not meaning, from one viewing to the next. This may be overidden by the tag no-format=true, or there may be mechanisms within the datatype object. The formatting is not only for viewing purposes; if successful, it will store the canonical form in lieu of the original. If unsuccessful (i.e., unable to canonicalize), the original form will be maintained. This functionality does not provide any error handling on its own. For that, you must specify the proper checks and reporting mechanisms as specified in 4.4.
The optional changeflag attribute takes the name of a Perl variable that will be set to true if the value of the named field ever changes due to end-user action. This variable will be introduced by MIC and will be scoped to the page.
The optional edit_test attribute allows us to test whether we want to do a MICinput or a MICdisplay. If the edit_test is true, then html input is generated for the associated MICdefine value. If the edit_test is false, then the value of the MICdefine is outputted to the user.
<MICdisplay name=MICdefined variable name [no-format="true" raw="true"]>
MICdisplay is used to display MICdefine’d variables. It will display the current value of the field. A MICdisplay is compatible with a MICinput and will cause no conflicts if both are used on the same page.
The raw option, if set, will cause the value contained to be displayed without HTML escaping. The intended purpose for this functionality is to allow the presentation of the data as HTML within the HTML. Note that raw displayed values are never formatted.
<MIChidden name=MICdefined variable name [no-format="true"]>
MIChidden will place the value of the proper field in a hidden HTML tag. Use this tag with caution. Usually, if you want to use it, you probably shouldn’t. Remember, the fieldspace will propagate all data for you.
<MICdynamicdisplay name=group name [numvar=index name]
>
deprecated mic code
</MICdynamicdisplay>
MICdynamicdisplay defines a set of mic-code to be repeated until a valid stop condition is met. This may be either:
The optional numvar parameter will allow one to specify the name of an index variable for use within the MICdynamicdisplay block. This variable will hold the index of the current iteration. If not specified, there is no default and the value will simply not exist. The recommended name for this variable is “$index.”
Note that when using a MICdynamicdisplay with MICrollover and MICrollback tags, the page must be able to be called again and again in succession. Each time, any new datatypes created are added to the fieldspace and remembered. Only the proper ones, however, are displayed.
<MICrollover name=name to associate with submits
assocdynamic=group name which this button should control
[text=text to appear on button]>
[<vfield ...>]
[<vpage ...>]
[<vverify ...>]
</MICrollover>
[<vpresent>]
The syntax for MICrollback and MICrefresh is the same.
These three tags indicate that a button should be placed at the point the tags are placed. These buttons will have the effect of going to the next page of the dynamic form and re-evaluating the page on which they display after starting MICdynamicdisplay at a new index point. The buttons are smart in that they know whether to display themselves or not. That is, the rollback will not display on the first page and the rollover will not display on the last. Neither will the rollover display if there are no more valid items to be considered. This will happen if any of the following conditions are met:
The assocdynamic attribute is the name of the group which this button should cause to roll back or forward. This must be specified due to support of nested MICdynamics.10
Other than that, they act much like submit buttons, and, like submit buttons, should have the same name within a form. One can place verification tags between the containing tags to one’s delight.
<MICreinitializefs test=perl code>
MIC Code to be run when the test is true
</MICreinitializefs>
When the test is true, this will cause the fieldspace associated with the form to be reinitialized at the point that this tag is dropped. The code contained by the tag may contain setup code of some sort, but may also contain messages to print to the user, etc. It is regular MIC code. This tag’s purpose is to refresh the fieldspace when actions on the current page have changed the nature of the data. For instance, if a user asks that certain items in a dynamic field be deleted, and the page is refreshed, then we must first instantiate the regular fieldspace and delete the fields. But, if we did not re-initialize, there might be blank items on the screen. And, depending on how initialization works, there is the possibility that a field will be missed since the data may collapse on the next page, and the item between the final on the current and the first on the next will never get shown.
<MICindexoverride test=perl code group=group to override [previous=“true”] [steps=integer]>
When test is true, then the index will either be set back to the previous iteration (which may or may not be back a step because of the MICrefresh tag) or back/forward a number of steps equal to the value given. Either may be set and previous will override if both are set.
MIC’s robust and flexible error handling system is one of its most useful features. This system allows one to verify data and then track, report and possibly correct errors. Both verification and reporting are rather flexible and powerful, while tracking is automatic. While the tags are discussed here, to fully understand MIC error handling, one must read section 5.
<vfield name=field name [ignore=“true”]>
This has the effect of saying “when the MICsubmit I am associated with (contained by) is hit, then check this field for errors with respect to its data type.”11
The name parameter identifies a field name within the associated fieldspace. Since names of all fields in a given fieldspace must be unique, MIC will know whether the field is dynamic or not. If it is dynamic, then all instantiations of that field present at the time of verification will be checked.
The effect is to call verify() (discussed in the cross interface section, 9.2) on the field contained within the fieldspace. The types of errors caught here are things like ‘I am supposed to be an integer... am I?’ as well as parameter limitation checks, if supported.
The optional ignore parameter will tell MIC to ignore any errors generated directly by this field. Furthermore, it will take the field out of error. This is to allow for the idea that certain submits may change the nature of what we care about and data that was previously in error is no longer in error. Note, however, that any verification will override ignore directives, so combining a vfield tag with an ignore directive and a vinistantiated tag will have the same effect as if the vfield tag were not there at all.
When we say “generated directly,” we mean generated by a vfield, vcurrent or vinstantiated. If the field is in error through the agency of an arbitrary verification (kicked off with vverify), then it will remain in error for that reason, even if the ignore directive is called.
<vpage name=page name>
This tag causes the named page to be reevaluated in the current context (meaning, among other things, that any global variables will have their current value). All fields which would be displayed (for input or display only) will be verified.
Realize that any pages specified by a vpage tag will essentially be re-run. If this is a concern, specify fields individually or use vinstantiated. In fact, it has been found that, in practice, vinstantiated works better and does what is wanted; be cognizant of the fact that the fields checked by each method are not the same.
As an example of the above, if on the first run through af a page, we increment a global var, then it will be the new, incremented value when the page is re-evaluated for vpage. This will also have the effect or incrementing the value again!
Note that there is no ignore attribute possible with vpage. This is because vpage is being deprecated.
<vverify name=verify name [ignore=“true”]>
This causes the test specified by the named verify to be run, and if it returns false, then the result of the MIC-HTML associated with the verify will be associated with the error-reporting mechanisms.
The optional ignore tag will remove the verification from error and all fields in error due to the verification. It will not remove direct field errors, though.
<vinstantiated [ignore=“true”]>
This causes all the fields which are instantiated at the moment to be verified.12 In general, this is usually the preferred alternative to vpage as it will generally have the desired affect without the side effects of vpage.
The ignore attribute has the effect of removing all field errors, but not verification errors. To remove all errors, use vignore.
<vcurrent [ignore=“true”]>
This tag has the effect of requesting a verification of all fields that have the potential of having been changed. It is, thus, different from vinstantiated in that past fields that may be hanging around due to change or what not, will not be verified. This may be the more efficient of the two to use, if it does what is needed.
The ignore directive will remove all fields from error that may have changed in the current form. Note that it will not effect errors due to verifications.
<vignore >
This tag will obliterate all errors, both field and verification.
<MICerrorreport >
MIC-HTML
</MICerrorreport>
This is used to iterate over all the error-packaging objects. Within the tag, the special variable $error is made available within the opening and closing tags. This variable can then be used to output those things which an error report should have.
At the time of this draft, the only real requirement to be a MIC-compliant error-packaging object are those methods necessary to create and iterate. For this reason, one must look to the documentation for the error packaging object to figure out how to do what one wants. Later versions of MIC will likely have a more integrated and user friendly interface.
<MICinclude src=a MIC-HTML file name>
This command is used to include repeated code or text. This command specifies a document or part of a document to include verbatim13 at the point at which the tag is included. You could think of it as simply dropping in the text of the file. Note that the MICinclude statement is evaluated at compile time, meaning that you cannot have variables in the src attribute.
The file is specified in an pile-absolute manner meaning that it is not relative to the current page, but relative to the root of the site to be compiled. The file is specified with path information, so if the ’hello’ was in directory ’/bob/micsite/branch’ where micsite is the root of the site to be compiled, then you would say ‘src="branch/hello".’ Note also that you never have a leading ‘/’ in the path information.14
To support files that are meant to be included in several different piles (and therefore cannot be strictly contained under a single pile root), one may use the -I option at compile time to specify an include directory (see 3.3). In this case, the pile-root relative file is first looked for and if net found, then the file is looked relative to the include directory. So, from above, if there were no file ‘/bob/micsite/branch/hello,’ and the pile was compiled with ‘-I /bob/include,’ then the compiler would search ‘/bob/include/branch/hello.’ Note the search order above.
Note that because they are already included, files with the extension .html, .mic or .fs that are within the site should never be MICincluded. By convention, included files should have a ‘.inc’ extensions.
It may be possible to MICinclude files which are external to the site (i.e., src="../style.inc"), but the feature is unsupported at the time of this writing.
User defined functions may be of two types, inline or called. The inline method should only be used for small snippets of code. Generally the accounting overhead that is currently necessary and the fact that most simple checks are generally handled by the fieldspace checks means that inline functions are, by and large, not the right choice. If a user defined function is used, don’t forget to use or require the module in the control file.
MIC defines that field supported error checks are done before user defined checks. This is done so that one can be sure that the data one is testing is at least canonically correct so far as the datatype can gurantee.
Though the exact interface to the fieldspace object, as far as accounting goes, is beyond the scope of this document, there are some general principles that can be discussed here. First of all, user defined checks should only be used if the checks supported directly by the field objects are insufficient. What is defined by MIC, however, is that the user functions must return a true false value in every call to the function.
By accounting, we mean that it is necessary to put fields in error and remove them from that state when appropriate. This should be done carefully and the logic of the functions should be carefully checked to make sure that the accounting is done correctly.
Additionally, MIC is also concerned with whether the MICverify itself is in error or not. Therefore, the function should return a true or false value to indicate that no errors or at least one error was found, respectively. As noted in the MICverify definition, this will control the display of the MIC-HTML error text contained by the MICverify open and close tags.
One important use of MICverifies is for conditional verification. Sometimes we want to verify certain fields and/or verifications based on parameters or data state. To do this, we use a MICverify which may call other MICverifies or field verifications directly.
The two MIC required functions (see ??) verify_fields() and verify_verifies() are used to make these calls. An example of how this is generally done is given in ??. Generally, however, the verification that determines what verifications to perform should always itself return true and do no accounting of its own as the fieldspace functions will do their own accounting.
Though usually less preferred than vinstantiated, there might be times in which a user wishes to use vpage. Such an instance might be if the verification for fields is particularly costly for some reason, and/or a great number of fields are being instantiated, many of which we do not wish or need to re-verify.
If vpage is used, one must be very cautious about state errors. Realize that all the code within a page will be run again in order to determine what is on the page. The page is essentially redisplayed at time of verification, although there is no output to the user. This means that for vpage to function without any unexpected side effects, the page must be more or less side effect free, at least when it is called again to be verified.
Though considered bad style, it may be necessary to case out when the page is being called. That is, put the sections of the page that will cause ‘bad’ things to happen if they are run twice in if-statements and have some sort of global flag1 or HTML parameter that signals that the block in question should not be run.
There are generally two types of error reporting as far as the user is concerned: contextual and non-. MIC supports both.
The idea for contextual reporting is that errors are reported where they occurred, or in context. This is accomplished by setting the error page for a particular page to be itself. The page should then be redisplayed with the appropriate error messages in an aesthetically pleasing spot.
Non-contextual error reporting should be reserved for pages that can yield very complex errors and/or dynamic fields.2 Realize also that the interface for dynamic error handling is, at the moment largely within the domain of the error packaging object and thus is not all that pretty. It is also outside the scope of this document.3
The control file serves two main purposes. The first is to make all the neccessary use’s and require’s that the pile will need. The second is to define zero or more of the three optional MIC defined subroutines.
Two of these subroutines will be executed before and after, respectively, each MIC-HTML page. They may set certain common variables, perform security checks, etc. They are named setup and cleanup. The third is used for handling pile errors. This does not mean field errors.
setup() is, as far as the MIC coder is concerned, called as the first step in any page evaluation (see 3.1). setup() is meant to initialize certain variables, and or perform security checks and such.
If setup returns some value, then this will stop the page which would have been processed/displayed from doing so. Instead, the return value of setup will be treated as what should be proccessed and output. If there is no return value, then the program will proceed normally.
Thus, perhaps there is a page ’session_lost.html’ which is meant to deal with the fact that a customers session has been lost or corrupted. We check for this fact in setup with something like:
... if (session_lost()) { return Pile::my_pile::session_lost(); } ...
If session_lost() is true, whatever page was requested will not be proccessed or displayed; instead, session_lost() will be. For this reason, be sure and return undef or an empty list at the end of the setup routine. By the rules of perl, simply ending the routine could cause erroneous misdirection.
cleanup()’s primary purpose is to do that: cleanup(). The first reason it was included was to be able to undef global variables set up in setup(). It may also be used to make database commits, or for any other reason.
The third subroutine is handle_exceptions. It is invoked if a Perl exception is caught by a MIC-compliant piledriver.1 If an exception is thrown, then it will be handed off to handle_exceptions().2 Whatever this page returns will be handed off to the customer. Therefore, handle_exception should generally retun a nice HTML page reporting the error.
Since MIC provides robust error handling for field related errors, this type of error reporting should generally be reserved for errors that “shouldn’t happen.” Of course, this doesn’t mean that the error shouldn’t look nice.
When programming, one may access the $cgi object from within any Perl snippets, MICPerl tags or within field or fieldspace definitions. One may even access this object from within the test parameters of logic/flow control MIC tags.
MIC provides a global hash, that is reset for each call to a MIC page,
which may be referenced from any page code (but not fieldspace code
unless passed in by some mechanism) called ‘headers.’ The keys of this
hash are intended to be header lines and the values their values. They
will be printed as <
key>
= “<
value>
”.
This hash is normally not accessible from the fieldspace because the fieldspace code gets compiled into a different package.
Any time one is within a form tag (with a MICfieldspace specified) or within a MICfieldspace tag, there will be a Perl object, $fs, available. It is through this object that one may access variables (which have been MICdefine’d) of the current fieldspace. This interface to this object is not totally defined by the MIC specification, though some of the methods on it are defined in 9.2, ?? and in the documentation for the implementation of the the MIC compliant fieldspace object that is being utilized.
This object is used to access fields and the informaiton within those fields. It as also used to ascertain certain state questions, especially regarding errors, about the fieldspace. As far as a MIC-coder’s code is concerned, the fieldspace should be used to get information, but not change it. Generally, when the MIC-coder is changing information (as in setting default values), they will be presented with the field itself. The MIC-coder should never change state information directly through the fieldspace object except in MICverifies. It is hoped that eventually, this will even be unnecessary.
This section outlines functions and objects (other than the $fs object, which is considered outside of, though compliant with, MIC) which MIC makes available within a Perl context. These may be used within a MICPerl tag, and will not, unless noted, function as expected in a snippet tag.
scalar return_page (scalar)
This function takes the name of the page to be returned and returns
the content generated by this page. Generally, this should be used
like “return return_page(`new_page');
” and not to rip content
from some page for insertion. This is better done with MICincludes and
by other methods.
The page specified should be MIC-root relative and can be in functional or HTML format. It may be a page within the current pile or a mounted pile (sub-pile) of the current pile, in which case the MIC-root relative designation is obviously through the mount point. The function will access the $headers variable and make drop the proper headers in order that relative paths don’t getted confused on the receiving page.
The MountManager object is made available to a pile in order that child or sub-piles may be mounted to directories within the primary or parent pile. Here, we specify the public interface on this object. The MountManager object may be accessed through the special variable $mount_manager, which is global to the pile and must be used in order for the pile to be strictifiable.
mount (scalar, scalar, scalar)
This function mounts the sub-pile named in the first argument to the directory named in the third. The second argument is the physical location of the sub-pile in the directory structure.1
register (list ref)
This is used to list all the variables which should be shared between parent and sub-piles. All the variables listed will be aliased across the piles namespaces when control is passed to the sub-pile and de-aliased when control is returned to the parent.
The idea behind mounting piles is much the same as mounting a Unix directory to a mount point. All requests through the mount point will be passed the sub-pile mounted to that point and any routing (directory or page) information following the mount point navigates within the sub-pile.
Currently, MIC only supports one level of mounting. Their can be one primary pile and one level of children. Future versions of MIC may allow for sub-piles to mount sub-piles as well. Programatically, this is not that hard, but may induce coders to create hard-to-resolve errors.
There are many times within MIC-HTML when one needs to specify a page. Within a MIC tag, it is done in the following manner:
See the section about MICinclude for an example.
Note, however, that within the HTML tags, there is no change from the
standard fashion. An <
a href="...>
tag stays the same
and does not follow the above procedure. You specify the link relative
to the page where the link is located on and it is allowable to have
‘..’ in the path information.2
The reason for this is the way that MIC thinks about pages versus how the web server thinks about them. The web server is requesting these pages through the agency of the piledriver. Within MIC, however, pages are functions. MIC takes your page specification and converts it to a function call.
In fact, sometimes you want to be able to redirect control flow explicitly. An example of this has already been provided in the discussion of the setup routine in the control file. Rarely, but, at times, you will want to do this for a page as well. That is, you might have something like:
... <MICPerl> if ($customer->secure()) { return return_page('login/secure'); } else { return return_page('login/insecure'); </MICPerl> ...
MIC 3.01 allows the return page to be in a directory other than the current directory. Users should note that this will only work as expected if the end-user’s browsers support the location tag. Care should also be taken if one is using frames and the user programmer wishes different buttons to have differnt targets. For this to work as expected, it is still necessary for one to have multiple forms.
The return_page() function is the only MIC-required library function that is required to be provided to the MIC coder by the MIC spec. Any particular implementation of MIC may provide other useful functions, but all must provide this function. The functionality and effect are specified above. Again, the effect of calling this function is undefined unless the user’s browser supports the location header.
It is common to share variables between fieldspaces and pages. When this is done, one must take careful note of any dependencies introduced, however. Remember that that the fieldspace will, in almost every case, be called in some context where the page is not called first, even if the fieldspace is only used on that page.3 Thus any variables that the fieldspace depends on should be declared/initialized/set in the fieldspace and not on the page.
Programmers must realize that MIC 2.0 implements a conservative instantiation routine. This brings up a couple of issues worth noting.
First, $fs->get_field(’field_name’)->value() and $fs->field_name() might cause runtime errors as the field, though defined, might not be present at the time it is called, and thus calling an object method of nothing will cause your program to break.
The recommended solution is the use of exceptions, which, in Perl, are handled through the use of eval. One should learn about this command if one is not already familiar with it.
Secondly, even using evals, if one has code like:
my $var; $var = eval {$fs->get_field('acc_number')->value();}; $account->set_acc_number($var);
then although one will not have a runtime error, unexpected behavior will most likely occur. Remember that fields are only loaded if they are changed from their initial value, are in error, or a member of a group where one or more members fall into the previous definitions.4
Let us say that the acc_number field is intially blank or set to the value of the current account, if there is any. The customer goes in to page, fills in the account number, and it gets updated. The next day, the customer goes back to the page. We find that we already have an account number associated with the customer, so the account number will display the number that they filled in the first visit. After hitting submit (or whatever), when the above code is called, if the user has not changed the account number, then it will get set to blank. This is because the field will not be instantiated, so the eval statement will return undef and $var will get set to undef. To avoid this problem, one might check $@ or rethink code.
Be aware that data propagates in a chain. If a programmer has a multipart form, then any page that a user could get to must include the fieldspace of concern or the data will be lost. Help pages generally present a challenge to interface design for this reason.
The other option, of course, is to store off the data and reload, this, however, is not preferred unless one is going to break from the form for more than a page or two.
Under MIC, the urge to conglomerate should be avoided. That is, pages should not, generally, submit to themselves and behave completely differently depending on whether they are the information page or the processing page. That is, a form should call another page to handle the processing of the data on the form, and not itself. Otherwise, one is not using the full power of MIC and maintainability and ease of reading and enhancing a site is, it has been found, generally decreased.
General error reporting has been discussed above, and will be discussed in greater detail in the cross interface specifications. Though related, we will not rehash those subjects here.
MIC, when fulfilling its purpose, must deal with and process gobs of end user information. This, of course, brings us into contact with forms and the carriers of that data, fieldspaces and fields. This sections intent is to help coders understand what these things are and how they should be used.
A fieldspace is conceptually the holder of all your fields. There is exactly one fieldspace associated with each MIC form. This fieldspace knows what fields might be present and how to initialize them.
The fieldspace object, presented to the coder as $fs, is created at
the point in the page where the user has <
form
MICfieldspace="...>
. After running through some trivial setup,
the fieldspace then recieves information encoded at compile time about
what fields the page might potentially need. With this information and
all the necessary state information propagated from the previous
page1, the fieldspace then goes on to instantiate
all the fields required by the MIC spec.
The fieldspaces primary purpose, as far as the MIC coder is concerned, is to provide access to fields. The fieldspace is also the recipient of the accounting information necessary in user defined verifications.
As mentioned briefly in the MICdefine reference, the function of the $obj object should be well understood to prevent odd errors. As described before, $obj is tied with the creation of fields and dummy fields. It is important to note in the field setup code, however, that one may never rely on the existence of $obj or $index.
At first, this may seem counter-intuitive; one might expect $obj, etc. to always be present under certain circumstances if one is using a non-dummy fieldspace. The reason that one cannot depend on this is because if a member of a group is changed and the other’s get carried along, then the changed member will obviously get its value from the user data and not from the default data, but the other members will also be filled from the value that they had at the time that the changed field was changed. Thus, the default code will be circumvented for the sake of efficiency.
After MIC 2.1 beta, MIC was able to support the concept of multiple values for one field. The impetus for this enhancement was the need to support select boxes, though it is also properly employed in checkboxes and may, in fact, be employed with any type of HTML control. It is suggested that the MIC coder become familiar with the idea of multiple values for a single parameter within HTML 4.0, as this is the model which drove the design of the MIC interface.
Generally, it is best to think of fields as always containing lists of data–it just so happens that in the common case, these are lists of one. A field may be initialized to contain multiple values, or it may recieve multiple values from an HTML page. Any values received override all previous values. That is, if a field is initialized to contain two values, ‘A’ and ‘B’, then if the page is displayed, user input is received and the HTML parameter associated with the field has only ‘C’ associated with it, then the field will contain only ‘C’ after the processing of that page. If the page were to have two, twenty, or one hundred values associated with the parameter associated with the field, then that is how many values the field will contain.
Note that there is no guarantee on the order in which the HTML parameters or field values will be processed, displayed or returned. This stipulation is without regards to any guarantee that the HTML specification may make.
See E.3.
The complete MIC system is an integrated set of parts. This helps ensure both maintainability and usability of the system. The interface to these sub systems utilized by MIC are described in this section. This chapter, while a user may find some of the funtions and/or specifications useful, is primarily meant for MIC itself. That is, the MIC compiler and/or generated code relies, or may rely, on the function being defined in this interface. In the appendix (??), one will find a suggested interface for fieldspaces and datatypes. This may be used as a starting point for implementers or as a conceptual reference for beginners, but should not be relied upon unless the documentation for the particular implementation of these sub-systems being utilized states that it conforms to this specification.
Note that this does not define requirements imposed by peers or lessers (if one views MIC as being the parent in this little hegemony). Specifically, there may be requirements imposed on the datatypes interface by the fieldspace system, or vice-versa.
In the parlance of MIC, a datatype is a field. That is, each field has associated with it a single datatype object that manages the values associated with that field. The term ‘field’ and ‘datatype’ will be used interchangeably as clarity dictates.
A datatype is an encapsulator of data that knows what type of data it expects to be encapsulating and how it expects to display itself. It will generally be able to detect errors in the form or range of the data, though exactly what will be detected is outside of the scope of this specification.
list/scalar value ()
This will return the value encapsulated and will function appropriately in either a list or scalar context. The value that is returned might not be the value that was received as the functions verify, format and canonicalize may all act to change the form of the value, though not its canonical value.
set_value (list/scalar value)
Will set the value to value. Note that this will not cause MIC to think that the value has changed if called directly in code. It can be used to set default values, though using the default value code portion of a MICdefine is the preferred method for accomplishing this.
set_possible (scalar values)
This function takes a reference to a hash of possible values. For all datatypes, it will make sure that the canonical form of the encapsulated data can be found in the list passed in (there are no constraints if there is no list), and for scroll list, check boxes, etc., it will use this list to generate the user displayed list. The keys are the value of the encapsulated data. See documentation of the datatypes for additional meaning and usage of the keys and values.
list/scalar canonicalize ()
This will examine all the values associated with the field and try and massage the data into canonical form as defined for the datatype specified for the field. If successful (i.e., all the data forms were recognized and successfully tranformed), then it will return the list or the first member of the list of values. If not successful it will raise an exception.
verify ()
This will run field verification functions on the field to make sure that the encapsulated data conforms to the canonical form and possibly further restrictions. If there is an error, then it will throw an error of a specific type. A human readable description of the errors should be accessible by the text() method defined on the error which should return a reference to an array of messages.
scalar/list format (bool quite)
This will format the canonical data as per the users request. If the quite flag is set, then errors will be quitely ignored. If not set, then this function may throw an exception. If successful, it will return the formatted value.
scalar call_me (scalar name)
This will return the name by which this field should be referred to for the end user. It will optionally take a new name. Note that there is not any requirement to treat various dynamics differntly. That is, it’s okay if all of them are required to have the same name.
This section details the functions which a MIC-compliant fieldspace object and the fields within it must support.
DataObj new (FieldSpace)
Takes a data object of some type, which may be various depending upon the implementation and/or desired characteristics of the FieldSpace and returns a properly instantiated, yet trivial, FieldSpace object. To fully instantiate all the data, the proper fields are then requested and instantiate() is called on the FieldSpace object.
The DataObj is the encapusalator or indicator on how to retrieve and/or resolve the data necessary for proper instantiation. It may be of various types; e.g., a CGI object, some sort of database table handle, or even a simple ID string.
request_group (scalar group_name)
Must be called before instantiate() to have a defined effect, this function requests that the named group be made available in the FieldSpace object. If the group_name is unknown, a warning will be sent to stderr, but program will otherwise continue unaffected.
Making a request for ‘_main’ is how one requests the static or root group. Requesting a dynamic group has the effect of instantiating the next set of fields from that group based on the current index numbers and the num_display var set in the MICgroup tag.
instantiate ()
Will possibly raise on exception if there are errors in instantiation.
datatype get_field (scalar field_name)
datatype <field name> ()
Takes field_name and returns the datatype associated with the field. It may also call the field name directly, though this method is not recommended. It will not work if the name of the field is the same as any functions defined within the fieldspace implementation, which will not be enumerated here.
scalar or null deposit_state (scalar data_obj, bool internal)
This function is meant to work in conjunction with retrieve_state, though exactly what it does is highly dependent on the nature of the fieldspace. It will take the data_obj figure out all the state data that it needs to continue operation when the next page in the chain is called. The return value, if defined, should be printed out to the HTML page before the close of the form.
If the boolean internal is set to true, the function may deposit state to the data_obj, but will not expect any sort of activity on MIC’s part. This is for propagation across other boundaries or sub-boundaries.
retrieve_state (scalar data_obj)
This function is called as part of the initialization process and sets the fieldspace into the proper state to comply with MIC.
This section details the functions which the error packaging objects which MIC makes use of must support.
The MIC driver should be an executable that expects to reside on a
machine and be called to handle certain HTTPD requests. It will
expect to look in the environment variables ‘REDIRECT_URL’ and
‘PATH_INFO.’ These should contain the appropriate information about
the url being requested. The driver will expect to find
/\/[\w_]+\.pile\//
where the characters before the ‘.pile’
indicate the pile name and the characters along with the extension
indicate the name of the file containing all the subroutines and
definitions for the pages within the pile.
The driver will then require that file and take everything after ‘.pile’ to be a page name. It will then call the function associated with the page name. This subroutine is formed by ‘Pile::<pile name>::<page>’ where page is the page name, sans valid extension, prepended by recursive parent directories seperated by ‘::.’ This function may or may not be mapped to a mounted pile function.
The setup function should be called unless it returns null, then the value returned should be returned by the driver (ostensibly to the web server) and driver’s job is done.
If setup runs successfully, then the page function will be called, either in the parent pile, or in the proper mounted pile. If no errors are thrown, then the cleanup routine should be called in a safe context and errors reported if the evaluation fails.
If the page routine throws an error, then the driver should call the function handle_exceptions function. This function is evaluated in a safe context, and if successful, the return value will be returned, cleanup will be called as above, and execution will cease. If there was a problem with the handle_exceptions function, then this problem should be reported.
If there is no handle exceptions function, then the error should be reported as gracefully as possible, cleanup should be called as above, and execution should cease. Note that cleanup is always called.
See 9.2 for functions required by MIC to compile. The functions listed here are not needed by MIC to compile, but are needed in order that required functionality be provided to the MIC coder.
bool verify_fields (array ref field_list)
This object method takes a reference to a list of fields to run field verification over and returns a true if none of the fields were found to be in error, and false otherwise. This method is not side effect free. The fieldspace object will take note of the fields errorfull state and act just as if a vfield tag were in place associated with the field.
bool verify_verifies (array ref verify_list)
Has essentially the same effect as verify_fields(), but will cause the verifications defined with the MICverify tag to be run at the point where this object method is called.
These functions are not required, but could be useful to programmers and so the functionality and names are suggested for the encouragment of consistent MIC code and standards.
bool changed_p (scalar field_name, bool virtual)
This function returns true if field_name has been changed during the lifetime of the current field chain (regardless of its current value). If the optional boolean arguement is set, then the function will check to see if any field of that virtual name1 has changed.
bool in_error (scalar field_name, bool virtual)
Same as changed_p excepting that the boolean returned will indicate whether the field is in error for any reason.
bool in_ferror (scalar field_name, bool virtual)
Same as changed_p excepting that the boolean returned will indicate whether the field is in error with regards to a field-data check.
bool in_vferror (scalar field_name, bool virtual)
Same as changed_p excepting that the boolean returned will indicate whether the field is in error with regards to an arbitrary verification check.
bool errors_p ()
Returns true if there are any errors in the fieldspace.
The required functions are outlined in ??, so here, we only enumerate suggested interfaces.
add_possible (scalar values)
values should be a reference to a hash like in set_possible, but this function should be provided for convenience to expand possible values.
int data_count ()
Will return the number of discrete data items encapsulated.
set_attribute (scalar attributes)
Takes a reference to a hash which will be used to define how the data should be displayed to end users.
set_parameters (scalar parameters)
Takes a reference to a hash defining constraints on data beyond the requirement that it be canonicalizeable.
set_format (scalar format)
Takes a reference to a hash defining how to format the canonical value when the format() function is called.
This section documents known bugs for which there are no plans to fix for the 3.0 release. They should be fixed for the final release, 3.01.
Note that portions of the code presented in this section are dependant on interfaces which are outside the scope of this document (e.g., the arbitrary code within a MICdefine). Thus, the exact syntax of the code that any given program may contain may differ. An effort has, however, been made to make the examples clear as to their meaning.
Consider the following snippets:
from login.html:
... Please enter your user name and password: <form action="check_password.mic"> User Name:<input name="username" type="text"><br> Password:<input name="password" type="password"><br> <input name="login_submit" type="submit" value="Submit"> </form> ...
*******
from check_password.mic:
... <MICif test="check_login($cgi->param('username'), $cgi->param('password'))"> return Pile::example::index($cgi); </MICif> <MICelse> return Pile::example::login($cgi); </MICelse> ...
*******
The above example illustrates the use of simple embedded
logic, calling pages as functions, and the use of HTML forms within
MIC (which is trivial). In the above example, we are using a direct
CGI call to check the value of the fields, which is discouraged in
general, but may be appropriate in certain cases (see ??. The above, in particular, is a bad example in that
respect as far as the style guidlines are concerned.
On the basis of the result of the function check_login, we either return the index page or return to the login page. Note that the browser will believe that the page being displayed is called ‘check_login.mic,’ but since all three of the pages of concern are at the same directory level, this is okay as far as functionality is concerned.
Consider the following code snippets:
from employee_entry.fs:
... <MICgroup name="employees" obj="$obj" numvar="$index" numdisplay="10" dummyok="true"> <Micdefine name="eid" data="employee_id" type="text"> get_employee_id($index); </MICdefine> <MICdefine name="name" data="text" type="text"> get_employee_name($index); </MICdefine> <MICdefine name="ssn" data="ssn" type="text"> get_employee_ssn($index); </MICdefine> <MICdefine name="salary" data="uscurrency" type="text"> get_employee_salary($index); </MICdefine> </MICgroup> ...
*******
from enter.html:
... <form action="overridden" MICfieldspace="employee_entry"> <MICdynamicdisplay> <hr> Name: <MICdisplay name="name"> SSN: <MICdisplay name="ssn"><br> Salary: <MICdisplay name="salary><br> </MICdynamicdisplay> <MICrollback name="entry_submit" assocdynamic="employees"> <vinstatiated> </MICrollback> <MICrollover name="entry_submit" assocdynamic="employees"> <vinstantiated> </MICrollover> <br> <MICsubmit name="entry_submit" value="Submit" goto="process"> <vinstantiated> </MICsubmit> <input type="submit" name="entry_submit" value="Submit"> </form> ...
*******
from process.html:
... <MICPerl> my %new_employees; </MICPerl> <form action="none" MICfieldspace="employee_entry"> <MICdo name="eid" numvar="$index"> $new_employees{$index}->{id}->{$field->value()}; </MICdo> <MICdo name="name" numvar="$index"> $new_employees{$index}->{name}->{$field->value()}; </MICdo> <MICdo name="ssn" numvar="$index"> $new_employees{$index}->{ssn}->{$field->value()}; </MICdo> <MICdo name="salary" numvar="$index"> $new_employees{$index}->{salary}->{$field->value()}; </MICdo> </form> <MIClist iterator="$index" list="keys %new_employees"> <MICPerl> my $new_id; if ($new_employees{$index}->{id}) { $new_id = new_employee_id(); $new_employees{$index}->{id}->{$new_id}; add_employee($new_employees{$index}); } else { update_employee($new_employees{$index}); } </MICPerl> </MIClist> ...
*******
The above code is meant to take new employee data and store it in a
database as well as display and update existing employee data. The
default code blocks will fill in the first n employees (where n is the
number of existing employees). Assume that the default code block
returns null when we go off the first n employees, leaving blank text
boxes.
Let us assume that we have strict error checking on all the data so that we know when we get to the processing page, it is all good data. That is, assume there is a lot of error checking and reporting that is not shown. Part of this error checking is to ensure that if one field is filled out, then the other two are.
Note that because of the instantiation rules of MIC, to change this form from only adding new employees, to adding and updating means that we only need to add 6 lines in the fieldspace file and 6 in the process.html (all of which are shown). When we get to the process page, we blindly load up everything that is there, only noting the state of the eid field at the very end. This is okay, since none of the blank fields or unchanged fields for existing customers will be instantiated, so all our data on the processing page are interesting.
So, we then MICdo over the fields, building up a hash, which is then passed into the add_employee function, which takes the information found in the hash reference and adds it to database or the update_employee function.
Consider the following code snippets:
from multiple.fs:
... <MICdefine name="selector" data="AtomicData::Text" type="HTMLIO::Select"> "daniel";; { $field->display({multiple => 3}}; $field->set_possible_hash({zane => Zane, daniel => Daniel, charles => Charles, sam => Sam, micheal => Michael}); } </MICdefine> ...
The above creates a field that will display itself as a select box
with the multiple param set to three and the items as indicated in the
anonymous hash passed to set_possible. Daniel (value daniel) will be
highlighted/selected initially.
*******
from select.html:
<html><body> <form action="overridden" MICfieldspace="multiple"> Please select everyone to invite to your party:<br> <MICinput name="selector"><br> <input type="submit" name="select_submit" value="Submit"> <MICsubmit name="select_submit" value="Submit" goto="display"> </MICsubmit> </form> </html></body>
*******
from display.html:
<html><body> <form action="none" MICfieldspace="multiple"> The revelers are:<br> <MIClist iterator="$reveler" list="$fs->get_field(`selector')->value()"> <b>$reveler</b><br> </MIClist> <input type="submit" name="multiple_submit" value="Revise"> <MICsubmit name="multiple_submit" value="Revise" goto="select"> <input type="submit" name="multiple_submit" value="Done"> <MICsubmit name="multiple_submit" value="Done" goto="done"> </form> </body></html>
*******
If we point a user to the select page, they will get a 3-row select
box with the name ‘Daniel’ highlighted. On this page, the field will
contain the single value, ‘daniel.’ Suppose the user selects
‘Charles,’ ‘Sam,’ and ‘Michael’ (poor Zane) and hits submit. They will
then go the display page and be presented with the names ‘Daniel,’
‘Charles,’ ‘Sam,’ and ‘Michael’1. Remember that ‘Daniel’ was never deselected. The fieldspace
now contains ‘daniel,’ ‘michael,’ ‘charles,’ and ‘sam.’ They then hit
the ‘Revise’ button and are taken back the revise page. The fieldspace
contains all value but ‘zane’ and the select box has all names
selected except ‘Zane.’ The user then selects ‘Zane’ and deselects
‘Daniel’ and resubmits. Now, we behave as before with ‘Zane’ and
‘zane’ substituted for ‘Daniel’ and ‘daniel.’ Happy with the
arrangements, the user then hits ‘Done’ and it does its trivial thing.
This document was translated from LATEX by HEVEA.