Полезная информация

Interchange Templates



Table of Contents


1. Interchange Templates

Interchange is the industry's most widely distributed and implemented open source e-commerce platform. Interchange is designed to build pages based on templates from a database. This document discusses, in detail, how to build forms and report templates with Interchange's tag language, ITL (Interchange Tag Language).

1.1. Overview

The search builder can be used to generate very complex reports on the database, or to help in the construction of ITL templates. Select a "Base table" which will be the foundation for the report. Specify the maximum number of rows to be returned at once, and whether to show only unique entries.

The "Search filter" narrows down the list of rows returned by matching columns of the table based on various criteria. Up to three separate conditions may be specified. The returned rows must match all criteria.

Finally, select any sorting options desired for displaying the results, and narrow down the list of columns returned if desired. Clicking "Run" will run the search immediately and display the results. "Generate definition" will display an ITL tag which can be placed in a template and which will return the results when executed.

To build complex order forms and reports, Interchange has a complete tag language with over 80 different functions, dubbed ITL, for Interchange Tag Language. It allows access to and control over any of an unlimited number of database tables, multiple shopping carts, user name/address information, discount, tax, and shipping information, search of files and databases, and much more.

There is some limited conditional capability with the [if ...] tag, but when doing complex operations, use of embedded Perl/ASP should be strongly considered. Most of the tests use Perl code, but Interchange uses the Safe.pm module with its default restrictions to help ensure that improper code will not crash the server or modify the wrong data.

Perl can also be embedded within the page, and if given the proper permission by the system administrator, can call upon resources from other computers and networks.


2. Variable Replacement

Variable substitution is a simple and oft-used feature of Interchange templates. Before anything else is done on a template, all variable tokens are replaced by variable values. There are three types of variable tokens:

__VARIABLENAME__ is replaced by the catalog variable called VARIABLENAME.

@@VARIABLENAME@@ is replaced by the global variable called VARIABLENAME.

@_VARIABLENAME_@ is replaced by the catalog variable VARIABLENAME if it exists; otherwise, it is replaced by the global variable VARIABLENAME.

See the icconfig documentation for information on how to use the Variable configuration file directive to set global variables in interchange.cfg and catalog variables in catalog.cfg.


3. Interchange Tags

[accessories]        Access product accessory functions
[area]               Insert a re-written Interchange URL
[banner]             Insert a random or rotating ad banner
[bounce]             Insert header to redirect to a different URL
[calc]               Perform Perl calculations (low overhead)
  [/calc]
[cart]               Set the current shopping cart name
[cgi]                Insert a CGI form value
[checked]            Conditionally check an HTML check/radio box
[comment]            Insert comments in Interchange pages
  [/comment]
[col]                Used with [row] -- rudimentary text tables for order
  [/col]             reports
[condition]          Sets a condition inside [if explicit] and others
  [/condition]
[counter]            Increment, decrement, or read a file-based counter
[currency]           Formats a number like currency for current locale
  [/currency]
[data]               Access a database or user session element
[default]            Insert a variable but with a default response if blank
[description]        Output a product description
[discount]           Set a product discount coupon
  [/discount]
[discount-price]     Show the discounted price (only in [item-list])
[dump]               Dump the session information (for errors and debugging)
[ecml]               Translate to-from Electronic Commerce Modeling Language
                     field
[else]               Defines else region for [if ...], [if-PREFIX-field ..]
  [/else]            and others
[elsif]              Defines elsif region for [if ...] (not available for
  [/elsif]           [if-PREFIX-field]
[error]              Check/display form processing errors
[field]              Access a product database field
[file]               Insert the contents of a file
[flag]               Set a minivend flag
[fly-list]           Show an item "on-the-fly" in an arbitrary page
  [/fly-list]
[goto]               goto an arbitrary page location, skipping the rest
[html_table]         create an HTML table from a query or list
[if]                 Perform any of many conditional tests
  [/if]
[if-PREFIX-data]     Display region only if database element non-empty
  [/if-PREFIX-data]
[if-PREFIX-field]    Display region only if field non-empty
  [/if-PREFIX-field]
[if-PREFIX-param]    Display only if item passed parameter set
  [/if-PREFIX-param]
[include]            Include a file with complete Interchange interpretation
[import]             Import ASCII text into a database
[index]              Create a searchable ASCII index
[input_filter]       Create an input filter
[PREFIX-accessories] Product accessory functions (set select box)
[PREFIX-alternate]   Alternation for table/line build
[/PREFIX-alternate
[PREFIX-change]      Grouping of items in list display
  [/PREFIX-change]
[PREFIX-code]        Insert current item SKU/code/row identifier
[PREFIX-data]        Insert data entry corresponding to current SKU
[PREFIX-description] Insert description corresponding to current SKU
[PREFIX-discount]    Show amount of discount for current SKU
[PREFIX-field]       Insert product database entry corresponding to current SKU
[PREFIX-increment]   Count for list
[PREFIX-last]        Stop displaying if condition is met
  [/PREFIX-last]
[PREFIX-next]        Skip item if condition is met
  [/PREFIX-next]
[PREFIX-list]        Iterate over a shopping cart
  [/PREFIX-list]
[PREFIX-param]       Show element from list.
[PREFIX-pos]         Show positional element from list.
[PREFIX-price]       Display price of item with any discounts/price breaks/
                     adjustments
[PREFIX-quantity]    Show quantity ordered on shopping cart line

[PREFIX-subtotal]    Subtotal for the item (item-quantity * item-price)
[label]              Set a label for goto
[loop]               Iterate over an arbitrary list
  [/loop]
[matches]            Show number of matches from search
[modifier-name]      Place a variable name that corresponds to an attribute
                     (in item-list)
[more]               Show region of search list only if more matches
[more-list]          Display more matches list with links to next series
  [/more-list]
[mvasp]              ASP-style Perl programming area
[no-match]           Define area of region results displayed when no match
  [/no-match]
[nitems]             Show number of items for a shopping cart
[order]              Create HTML link to order an item
[page]               Create A HREF with re-written URL to call Interchange page
[perl]               Embed output of arbitrary Perl in the page
  [/perl]
[price]              Show price of an item
[process]            Create URL for Interchange form processing
[quantity-name]      Place a variable name that corresponds to item quantity
[query]              Perform any of several types of SQL query
  [/query]
[read_cookie]        Read a cookie sent by the user
[record]             Set a database record
[row]                Used with [col] -- rudimentary text tables for order
  [/row]             reports
[salestax]           Show amount of salestax for shopping cart
[scratch]            Access a scratch variable
[search-region]      Define an area of the page as a search list/query
  [/search-region]
[selected]           Conditional selection of drop-down <SELECT ...>
[set]                Set a scratch variable
  [/set]
[set_cookie]         Send a cookie to the user
[setlocale]          Set the locale
[shipping]           Calculate shipping
[shipping-desc]      Show shipping description
[sort]               Set sort order for iterating lists
  [/sort]
[strip]              Strip leading/trailing whitespace
  [/strip]
[subtotal]           Calculate subtotal without tax or shipping
[tag]                Miscellaneous functions
  [/tag]
[then]               Define THEN region for [if ...]
  [/then]
[timed_build]        Build region of page on timed basis
[total-cost]         Calculate order total with tax, handling, and shipping
[userdb]             Access user database functions
[update]             Perform Interchange actions
[value]              Display form value
[value_extended]     Display form array values or do file upload functions

3.1. Tag Syntax

Interchange uses a style similar to HTML, but with [square brackets] replacing <chevrons>. The parameters that can be passed are much the same, where a parameter="parameter value" can be passed.

Summary:

   [tag parameter]             Tag called with positional parameter
   [tag parameter=value]       Tag called with named parameter
   [tag parameter="the value"] Tag called with space in parameter
   [tag 1 2 3]                 Tag called with multiple positional parameters
   [tag foo=1 bar=2 baz=3]     Tag called with multiple named parameters
   [tag foo=`2 + 2`]           Tag called with calculated parameter
   [tag foo="[value bar]"]     Tag called with tag inside parameter
   [tag foo="[value bar]"]
       Container text.         Container tag.
   [/tag]

Most tags can accept some positional parameters. This speeds up parsing and is simpler to write in many cases.

Here is an example tag:

   [value name=city]

This will cause Interchange to look in the user form value array and return the value of the form parameter city, which might have been set with:

   City: <INPUT TYPE=text NAME=city VALUE="[value city]">

Note that the value was pre-set with the previous value of city (if any). It uses the positional style -- name is the first positional parameter for the [value ...] tag. Positional parameters cannot be derived from other Interchange tags; for instance [value [value formfield]] will not work. But if the named parameter syntax is used, the parameters can contain other tags, such as:

   [value name="[value formfield]"]

There is one exception to the above rule when using the [item-list], [loop ...], [sql ...], and other list tags. These will be examined in following sections.

Many Interchange tags are container tags:

   [set Checkout]
       mv_nextpage=ord/checkout
       mv_todo=return
   [/set]

Tags and parameter names are not case sensitive, so [VALUE NAME=something] would work just as well. Interchange convention is to place HTML tags in upper case and Interchange tags in lower case so pages are easier to read, but this sense can easily be reversed.

Single quotes work just as well as double quotes, and can prevent ambiguity.

   [value name=b_city set='[value city]']

Backticks, the other single quote, cause the parameter contents to be evaluated as Perl code via the [calc] tag. (This is in MV3.15 and above.) For example:

   [value name=row_value set=`$row_value += 1`]

is the same as

   [value name=row_value set="[calc]$row_value += 1[/calc]"]

Pipes are also quoting characters, but have the special behavior of stripping leading and trailing whitespace. For example:

       [loop list="code        field    field2  field3
       k1    A1    A2    A3
       k2      B1      B2      B3"]
       [loop-increment][loop-code]
       [/loop]

might be more elegantly expressed as:

    [loop list=|
            k1    A1    A2    A3
            k2    B1    B2    B3"]
    |]
        [loop-increment][loop-code]
    [/loop]

What is done with the results of the tag depends on whether it is a container or standalone tag. A container tag is one which has an end tag, i.e., [tag] stuff [/tag]. A standalone tag has no end tag, as in [area href=somepage]. (Note that [page ...] and [order ..] are not container tags.)

A container tag will have its output re-parsed for more Interchange tags by default. To inhibit this behavior, explicitly set the attribute reparse to 0. Note that the default action is almost always desirable. With some exceptions ([include file] among them), the output of a standalone tag will not be re-interpreted for Interchange tag constructs.

Most container tags will not have their contents interpreted before being passed the container text. Exceptions include [calc] .. [/calc] and [currency] ... [/currency]. All tags accept the INTERPOLATE=1 tag modifier, which causes the interpretation to take place. It is not necessary to interpret the contents of a [set variable] TAGS [/set] pair, as they might contain tags which should only be upon evaluating an order profile, search profile, or mv_click operation. If the evaluation is performed at the time a variable is set, use [set name=variable interpolate=1] TAGS [/set].

3.2. DATA and FIELD

The [data ...] and [field ...] tags access elements of Interchange databases. They are the form used outside of the iterating lists, and can be effectively used to do lookups when the table, column/field or key/row is conditional based on a previous operation.

The following are equivalent for attribute names:

   table ---> base
   col   ---> field --> column
   key   ---> code  --> row

The [field ...] tag is special in that it looks in any of the tables defined as ProductFiles, in that order, for the data, returning the first non-empty value. In most catalogs, where ProductFiles is not defined, i.e., the demo, [field title 00-0011] is equivalent to [data products title 00-0011]. For example, [field col=foo key=bar] will not display something from the table "category" because "category" is not in the directive ProductFiles or there are multiple ProductFiles and an earlier one has an entry for that key.

[data table column key]

            accesses      Accesses within the last 30 seconds
            arg           The argument passed in a [page ...] or [area ...] tag
            browser       The user browser string
            host          Interchange's idea of the host (modified by DomainTail)
            last_error    The last error from the error logging
            last_url      The current Interchange path_info
            logged_in     Whether the user is logged in via UserDB
            pageCount     Number of unique URLs generated
            prev_url      The previous path_info
            referer       HTTP_REFERER string
            ship_message  The last error messages from shipping
            source        Source of original entry to Interchange
            time          Time (seconds since Jan 1, 1970) of last access
            user          The REMOTE_USER string
            username      User name logged in as (UserDB)

[field name code]

3.3. set, seti, scratch and scratchd

Scratch variables are maintained in the user session separate from the form variable values set on HTML forms. Many things can be controlled with scratch variables, particularly search and order processing, the mv_click multiple variable setting facility, and key Interchange conditions session URL display.

There are three tags which are used to set the space, [set name]value[/set], [seti name]value[/seti], [tmp name]value[/tmp], and two variations (or shortcuts).

[set variable]value[/set]

          [set checkout]
          name=required You must give us your name.
          address=required Oops! No address.
          [/set]
          <INPUT TYPE=hidden NAME=mv_order_profile VALUE="checkout">
          [set substring_case]
          mv_substring_match=yes
          mv_case=yes
          [/set]
          <INPUT TYPE=hidden NAME=mv_profile VALUE="substring_case">
            [calc]$Scratch->{foo} = 'bar'; return;[/calc]

[seti variable][value something][/seti]

            [set name=variable interpolate=1][value something][/set]

[tmp name]value[/tmp]

[scratch name]

            [perl]$Scratch->{foo}[/perl]

[scratchd]

[if scratch name op* compare*] yes [else] no [/else] [/if]

3.4. loop

Loop lists can be used to construct arbitrary lists based on the contents of a database field, a search, or other value (like a fixed list). Loop accepts a search parameter which will do one-click searches on a database table (or file).

To iterate over all keys in a table, use the idiom ([loop search="ra=yes/ml=9999"] [/loop]. ra=yes sets mv_return_all, which means "match everything". The ml=9999 limits matches to that many records. Normally this many matches will not be necessary, but it is a reasonable default maximum. If the text file for searching an Interchange DBM database is not used, set st=db (mv_searchtype).

When using st=db, returned keys may be affected by TableRestrict. See catalog.cfg. Both can be sorted with [sort table:field:mod -start +number] modifiers. See Sorting.

[loop item item item] LIST [/loop]

            [loop prefix=size list="Small Medium Large"]
                [loop prefix=color list="Red White Blue"]
                    [color-code]-[size-code]<BR>
                [/loop]
                <P>
            [/loop]
                        Red-Small
                        White-Small
                        Blue-Small
        
                        Red-Medium
                        White-Medium
                        Blue-Medium
        
                        Red-Large
                        White-Large
                        Blue-Large
            [loop search="se=Americana/sf=category"]
                [loop-code] [loop-field title]
            [/loop]

[if-loop-data table field] IF [else] ELSE [/else][/if-loop-field]


Note: This tag does not nest with other [if-loop-data ...] tags.

[if-loop-field field] IF [else] ELSE [/else][/if-loop-field]


Note: This tag does not nest with other [if-loop-field ...] tags.

[loop-alternate N] DIVISIBLE [else] NOT DIVISIBLE [/else][/loop-alternate]

            [loop-alternate 2]EVEN[else]ODD[/else][/loop-alternate]
            [loop-alternate 3]BY 3[else]NOT by 3[/else][/loop-alternate]

[/loop-alternate]

[loop-change marker]

[loop-code]

[loop-data database fieldname]

[loop-description]

[loop-field fieldname]

[loop-increment]

[loop-last]tags[/loop-last]

              [loop-last][calc]
                return -1 if '[loop-field weight]' eq '';
                return 1 if '[loop-field weight]' < 1;
                return 0;
                [/calc][/loop-last]

[loop-next]tags[/loop-next]

              [loop-next][calc][loop-field weight] < 1[/calc][/loop-next]

[loop-price n* noformat*]

[loop-calc]PERL[/loop-calc]


Note: All normal embedded Perl operations can be used, but be careful to pre-open any database tables with a [perl tables="tables you need"][/perl] tag prior to the opening of the [loop].

[loop-exec routine]argument[/loop-exec]

[loop-sub routine]PERL[/loop-sub]

3.5. if

[if type field op* compare*]

[if !type field op* compare*]

Allows conditional building of HTML based on the setting of various Interchange session and database values. The general form is:

        [if type term op compare]
        [then]
                                    If true, this is printed on the document.
                                    The [then] [/then] is optional in most
                                    cases. If ! is prepended to the type
                                    setting, the sense is reversed and
                                    this will be output for a false condition.
        [/then]
        [elsif type term op compare]
                                    Optional, tested when if fails.
        [/elsif]
        [else]
                                    Optional, printed when all above fail.
        [/else]
        [/if]

The [if] tag can also have some variants:

        [if explicit][condition] CODE [/condition]
                    Displayed if valid Perl CODE returns a true value.
        [/if]

Some Perl-style regular expressions can be written, and combine conditions:

        [if value name =~ /^mike/i]
                                    This is the if with Mike.
        [elsif value name =~ /^sally/i]
                                    This is an elsif with Sally.
        [/elsif]
        [elsif value name =~ /^barb/i]
        [or value name =~ /^mary/i]
                                    This is an elsif with Barb or Mary.
        [elsif value name =~ /^pat/i]
        [and value othername =~ /^mike/i]
                                    This is an elsif with Pat and Mike.
        [/elsif]
        [else]
                                    This is the else, no name I know.
        [/else]
        [/if]

While the named parameter tag syntax works for [if ...], it is more convenient to use the positional syntax in most cases. The only exception is when planning on doing a test on the results of another tag sequence:

This will not work:

   [if value name =~ /[value b_name]/]
       Shipping name matches billing name.
   [/if]

This will not work. Do this instead:

   [if type=value term=name op="=~" compare="/[value b_name]/"]
       Shipping name matches billing name.
   [/if]

As an alternative:

   [if type=value term=high_water op="<" compare="[shipping noformat=1]"]
       Shipping cost is too high, charter a truck.
   [/if]

There are many test targets available:

config Directive

            [if config CreditCardAuto]
            Auto credit card validation is enabled.
            [/if]

data database::field::key

            [if data products::size::99-102]
            There is size information.
            [else]
            No size information.
            [/else]
            [/if]
        
            [if data products::size::99-102 =~ /small/i]
            There is a small size available.
            [else]
            No small size available.
            [/else]
            [/if]
            [set code]99-102[/set]
            [if type=data term="products::size::[scratch code]"]
            There is size information.
            [else]
            No size information.
            [/else]
            [/if]

discount

            [if discount 99-102]
            Item is discounted.
            [/if]

explicit

            [if explicit]
            [condition]
                $country = $ values =~{country};
                return 1 if $country =~ /u\.?s\.?a?/i;
                return 0;
            [/condition]
            You have indicated a US address.
            [else]
            You have indicated a non-US address.
            [/else]
            [/if]

file

            [if file /home/user/www/images/[item-code].gif]
            <IMG SRC="[item-code].gif">
            [/if]
        
            or
        
            [if type=file term="/home/user/www/images/[item-code].gif"]
            <IMG SRC="[item-code].gif">
            [/if]

items

          [if items]You have items in your shopping cart.[/if]
        
          [if items layaway]You have items on layaway.[/if]

ordered

          [if ordered 99-102] ... [/if]
            Checks the status of an item on order, true if item
            99-102 is in the main cart.
        
          [if ordered 99-102 layaway] ... [/if]
            Checks the status of an item on order, true if item
            99-102 is in the layaway cart.
        
          [if ordered 99-102 main size] ... [/if]
            Checks the status of an item on order in the main cart,
            true if it has a size attribute.
        
          [if ordered 99-102 main size =~ /large/i] ... [/if]
            Checks the status of an item on order in the main cart,
            true if it has a size attribute containing 'large'.
            THE CART NAME IS REQUIRED IN THE OLD SYNTAX. The new
            syntax for that one would be:
        
            [if type=ordered term="99-102" compare="size =~ /large/i"]
        
            To make sure it is exactly large, you could use:
        
            [if ordered 99-102 main size eq 'large'] ... [/if]
        
          [if ordered 99-102 main lines] ... [/if]
              Special case -- counts the lines that the item code is
              present on. (Only useful, of course, when mv_separate_items
              or SeparateItems is defined.)

scratch

            [if scratch mv_separate_items]
            Ordered items will be placed on a separate line.
            [else]
            Ordered items will be placed on the same line.
            [/else]
            [/if]

session

validcc

value

variable

The field term is the specifier for that area. For example, [if session frames] would return true if the frames session parameter was set.

As an example, consider buttonbars for frame-based setups. It would be nice to display a different buttonbar (with no frame targets) for sessions that are not using frames:

   [if session frames]
       [buttonbar 1]
   [else]
       [buttonbar 2]
   [/else]
   [/if]

Another example might be the when search matches are displayed. If using the string [value mv_match_count] titles found, it will display a plural for only one match. Use:

   [if value mv_match_count != 1]
       [value mv_match_count] matches found.
   [else]
       Only one match was found.
   [/else]
   [/if]

The op term is the compare operation to be used. Compare operations are as in Perl:

   ==  numeric equivalence
   eq  string equivalence
   >   numeric greater-than
   gt  string greater-than
   <   numeric less-than
   lt  string less-than
   !=  numeric non-equivalence
   ne  string equivalence

Any simple Perl test can be used, including some limited regex matching. More complex tests are best done with [if explicit].

[then] text [/then]

[elsif type field op* compare*]

[else] text [/else]

[condition] text [/condition]

[/if]


4. Programming

Interchange has a powerful paradigm for extending and enhancing its functionality. It uses two mechanisms, user-defined tags and user subroutines on two different security levels, global and catalog. In addition, Embedded Perl Code may be used to build functionality into a site's page.

User-defined tags are defined with the UserTag directive in either minivend.cfg or catalog.cfg. The ones in minivend.cfg are global, i.e., they are not constrained by the Safe Perl module as to which opcodes and routines they may use. Normally, the user-defined tags in catalog.cfg are constrained by Safe, but if the AllowGlobal global directive is set for the particular catalog in use, its UserTag and Sub definitions will have global capability.

Many of the internal Interchange routines can be accessed by the savvy programmer who reads the source and finds the entry points. Also, many internal Interchange routines can be overridden:

    GlobalSub <<EOS
    sub just_for_overriding {
        package Vend::Module;
        use MyModule;
        sub to_override {
            &MyModule::do_something_funky($Values->{my_variable});
        }
    }
    EOS

The effect of the above is to override the to_override routine in the module Vend::Module. This is preferable to hacking on the code if the functionality change is expected to last long. Then, the Interchange code can be updated, in most cases, while still keeping your hack.

4.1. Embedded Perl Code

Perl code can be directly embedded in Interchange pages. The code is specified as:

    [perl]
        $name    = $Values->{name};
        $browser = $Session->{browser};
        return "Hi, $name! How do you like your $browser?";
    [/perl]

ASP syntax can be used with:

    [mvasp]
        <%
        $name    = $Values->{name};
        $browser = $Session->{browser};
        %>
        Hi, <%= $name %>!
        <%
            HTML "How do you like your $browser?";
        %>
    [/mvasp]

The two snippets above are essentially equivalent.

4.2. Export

            $Tag->export(
                {
                 table => VALUE,
                }
            )
            $Tag->export($table, $ATTRHASH);
                base ==> table
                database ==> table

4.3. Time

            $Tag->time(
                {
                 locale => VALUE,
                },
                BODY
            )
            $Tag->time($locale, $ATTRHASH, $BODY);

4.4. Import

            $Tag->import(
                {
                 table => VALUE,
                 type => VALUE,
                },
                BODY
            )
            $Tag->import($table, $type, $ATTRHASH, $BODY);
                base ==> table
                database ==> table
            [import table=orders]
            code: [value mv_order_number]
            shipping_mode: [shipping-description]
            status: pending
            [/import]
        
            [import table=orders]
            shipping_mode: [shipping-description]
            status: pending
            code: [value mv_order_number]
            [/import]

4.5. Log

            $Tag->log(
                {
                 file => VALUE,
                },
                BODY
            )
            $Tag->log($file, $ATTRHASH, $BODY);
                arg ==> file

4.6. Header

4.7. price, description, accessories

[price code quantity* database* noformat*]

            [price  code=99-102
                    size=L]              is $10.00
        
            [price  code=99-102
                    size=XL]             is $11.00
        
            [price  code=99-102
                    color=RED
                    size=XL]             is $11.75
        
            [price  code=99-102
                    size=XL
                    quantity=10]         is $10.00
        
            [price  code=99-102
                    size=S]              is $9.50

[description code table*]

[accessories code attribute*, type*, field*, database*, name*, outboard*]

            name=Label Text, name=Label Text*
            [accessories TK112 color]
            <SELECT NAME="mv_order_color">
            <OPTION VALUE="beige">Almond
            <OPTION VALUE="gold">Harvest Gold
            <OPTION SELECTED>White
            <OPTION VALUE="green">Avocado
            </SELECT>

4.8. FILE and INCLUDE

These elements read a file from the disk and insert the contents in the location of the tag. [include ...] will allow insertion of Interchange variables and ITL tags.

[file ...]

[include file]

4.9. Banner/Ad rotation

Interchange has a built-in banner rotation system designed to show ads or other messages according to category and an optional weighting.

The [banner ...] ITL tag is used to implement it.

The weighting system pre-builds banners in the directory 'Banners,' under the temporary directory. It will build one copy of the banner for every one weight. If one banner is weighted 7, one 2, and one 1, then a total of 10 pre-built banners will be made. The first will be displayed 70 percent of the time, the second 20 percent, and the third 10 percent, in random fashion. If all banners need to be equal, give each a weight of 1.

Each category may have separate weighting. If the above is placed in category tech, then it will behave as above when placed in [banner category=tech] in the page. A separate category, say art, would have its own rotation and weighting.

The [banner ...] tag is based on a database table, named banners by default. It expects a total of five (5) fields in the table:

code

category

weight

rotate

            non-zero, non-blank: Rotating ads
            blank:               Ad not displayed
            0:                   Ad is entire contents of banner field

banner

Interchange expects the banner field to contains the banner text. It can contain more than one banner, separated by the string '{or}.' To activate the ad, place any string in the field rotate.

The special key "default" is the banner that is displayed if no banners are found. (Doesn't apply to weighted banners.)

Weighted banners are built the first time they are accessed after catalog reconfiguration. They will not be rebuilt until the catalog is reconfigured, or the file tmp/Banners/total_weight and tmp/Banners/<category>/total_weight is removed.

If the option once is passed (i.e., [banner once=1 weighted=1], then the banners will not be rebuilt until the total_weight file is removed.

The database specification should make the weight field numeric so that the proper query can be made. Here is the example from Interchange's demo:

   Database   banner   banner.txt   TAB
   Database   banner   NUMERIC      weight

Examples:

weighted, categorized

            code    category   weight   rotate   banner
            t1      tech       1                 Click here for a 10% banner
            t2      tech       2                 Click here for a 20% banner
            t3      tech       7                 Click here for a 70% banner
            a1      art        1                 Click here for a 10% banner
            a2      art        2                 Click here for a 20% banner
            a3      art        7                 Click here for a 70% banner
            [banner weighted=1 category="tech"]

weighted

            [banner weighted=1]
            code    category   weight   rotate   banner
            t1      tech       1                 Tech banner 1
            t2      tech       2                 Tech banner 2
            t3      tech       7                 Tech banner 3
            a1      art        1                 Art banner 1
            a2      art        2                 Art banner 2
            a3      art        7                 Art banner 3

categorized, not rotating

            [banner category="tech"]
            [data table=banner col=banner key=tech
            code    category   weight   rotate   banner
            tech               0        0        Tech banner
            [banner category="[value interest]"]

categorized and rotating

            [banner category="tech"]
            code    category   weight   rotate   banner
            tech               0        1        Tech banner 1{or}Tech banner 2
            art                0        1        Art banner 1{or}Art banner 2
            [banner category="[value interest]"]

multi-level categorized

            [banner category="tech:hw"] or [banner category="tech:sw"]
            code    category   weight   rotate   banner
            tech               0        1        Tech banner 1{or}Tech banner 2
            tech:hw            0        1        Hardware banner 1{or}HW banner 2
            tech:sw            0        1        Software banner 1{or}SW banner 2

Advanced

            [banner
                weighted=1*
                category=category*
                once=1*
                separator=sep*
                delimiter=delim*
                table=banner_table*
                a_field=banner_field*
                w_field=weight_field*
                r_field=rotate_field*
            ]
            table       banner    selects table used
            a_field     banner    selects field for banner text
            delimiter   {or}      delimiter for rotating ads
            r_field     rotate    rotate field
            separator   :         separator for multi-level categories
            w_field     weight    rotate field

4.10. Tags for Summarizing Shopping Basket/Cart

The following elements are used to access common items which need to be displayed on baskets and checkout pages.

* marks an optional parameter

[item-list cart*]

[/item-list]

[nitems cart*]

[subtotal]

[salestax cart*]

[shipping-description mode*]

[shipping mode*]

[total-cost cart*]

[currency convert*]

            [currency]4[/currency]
            4.00
            [currency convert=1] [calc] 500.00 + 1000.00 [/calc] [/currency]

[/currency]

[cart name]

[row nn]

[/row]

[col width=nn wrap=yes|no gutter=n align=left|right|input spacing=n]

            width=nn        The column width, including the gutter. Must be
                            supplied, there is no default. A shorthand method
                            is to just supply the number as the first parameter,
                            as in [col 20].
        
            gutter=n        The number of spaces used to separate the column (on
                            the right-hand side) from the next. Default is 2.
        
            spacing=n       The line spacing used for wrapped text. Default is 1,
                            or single-spaced.
        
            wrap=(yes|no)   Determines whether text that is greater in length than
                            the column width will be wrapped to the next line. Default
                            is yes.
        
            align=(L|R|I)   Determines whether text is aligned to the left (the default),
                            the right, or in a way that might display an HTML text
                            input field correctly.

[/col]

4.11. Item Lists

Within any page, the [item-list cart*] element shows a list of all the items ordered by the customer so far. It works by repeating the source between [item-list] and [/item-list] once for each item ordered.


Note: The special tags that reference item within the list are not normal Interchange tags, do not take named attributes, and cannot be contained in an HTML tag (other than to substitute for one of its values or provide a conditional container). They are interpreted only inside their corresponding list container. Normal Interchange tags can be interspersed, though they will be interpreted after all of the list-specific tags.

Between the item_list markers the following elements will return information for the current item:

[if-item-data table column]


Note: This tag does not nest with other [if-item-data ...] tags.

[if-item-data table column]

[/if-item-data]

[if-item-field fieldname]


Note: This tag does not nest with other [if-item-field ...] tags.

[if-item-field fieldname]

[/if-item-field]

[item-accessories attribute*, type*, field*, database*, name*]

[item-alternate N] DIVISIBLE [else] NOT DIVISIBLE [/else][/item-alternate]

            [item-alternate 2]EVEN[else]ODD[/else][/item-alternate]
            [item-alternate 3]BY 3[else]NOT by 3[/else][/item-alternate]

[/item-alternate]

[item-code]

[item-data database fieldname]

[item-description]

[item-field fieldname]

[item-increment]

[item-last]tags[/item-last]

              [item-last][calc]
                return -1 if '[item-field weight]' eq '';
                return 1 if '[item-field weight]' < 1;
                return 0;
                [/calc][/item-last]

[item-modifier attribute]

[item-next]tags[/item_next]

              [item-next][calc][item-field weight] < 1[/calc][/item-next]

[item-price n* noformat*]

[discount-price n* noformat*]

[item-discount]

[item-quantity]

[item-subtotal]

[modifier-name attribute]

[quantity-name]


5. Interchange Page Display

Interchange has several methods for displaying pages:

            <FORM ACTION="[process]">
            <INPUT TYPE=hidden NAME=mv_todo VALUE=return>
            <SELECT NAME=mv_nextpage>
            <OPTION VALUE=index>Main page
            <OPTION VALUE=browse>Product listing
            <OPTION VALUE="ord/basket">Shopping cart
            </SELECT>
            <INPUT TYPE=submit VALUE=Go>
            </FORM>

5.1. On-the-fly Catalog Pages

If an item is displayed on the search list (or order list) and there is a link to a special page keyed on the item, Interchange will attempt to build the page "on the fly." It will look for the special page flypage.html, which is used as a template for building the page. If [item-field fieldname], [item-price], and similar elements are used on the page, complex and information-packed pages can be built. The [if-item-field fieldname] HTML [/if-item-field] pair can be used to insert HTML only if there is a non-blank value in a particular field.

Important note: Because the tags are substituted globally on the page, [item-*] tags cannot be used on the default on-the-fly page. To use a [search-region] or [item-list] tag, change the default with the prefix parameter. Example:

   [item-list prefix=cart]
   [cart-code] -- title=[cart-data products title]
   [/item-list]

To have an on-the-fly page mixed in reliably, use the idiom [fly-list prefix=fly code="[data session arg]"] [/flylist] pair.

[fly-list code="product_code" base="table"] ... [/fly-list]

            prefix=label     Allows [label-code], [label-description]
           [fly-list code="[data session arg]"]
            (contents of flypage.html)
           [/fly-list]
            [page 00-0011] One way to display the Mona Lisa [/page]
            [page flypage2 00-0011] Another way to display the Mona Lisa [/page]

If the directive PageSelectField is set to a valid product database field which contains a valid Interchange page name (relative to the catalog pages directory, without the .html suffix), it will be used to build the on-the-fly page.

Active tags in their order of interpolation:

[if-item-field field]    Tests for a non-empty, non-zero value in field
[if-item-data db field]  Tests for a non-empty, non-zero field in db
[item-code]              Product code of the displayed item
[item-accessories args]  Accessory information (see accessories)
[item-description]       Description field information
[item-price quantity*]   Product price (at quantity)
[item-field field]       Product database field
[item-data db field]     Database db entry for field

5.2. Special Pages

A number of HTML pages are special for Interchange operation. Typically, they are used to transmit error messages, status of search or order operations, and other out of boundary conditions.


Note: The distributed demo does not use all of the default values.

The names of these pages can be set with the SpecialPage directive. The standard pages and their default locations:

canceled (special_pages/canceled.html)

catalog (special_pages/catalog.html)

failed (special_pages/failed.html)

flypage (special_pages/flypage.html)

interact (special_pages/interact.html)

missing (special_pages/missing.html)

            [tag op=header]Status: 404 missing[/tag]

noproduct (special_pages/noproduct.html)

order (ord/backet.htm)

search (results.html)

            SpecialPage   search   results

violation (special pages/violation.html)

5.3. Checking Page HTML

Interchange allows debugging of page HTML with an external page checking program. Because leaving this enabled on a production system is potentially a very bad performance degradation, the program is set in a the global configuration file with the CheckHTML directive. To check a page for validity, set the global directive CheckHTML to the name of the program (don't do any output redirection). A good choice is the freely available program Weblint. It would be set in minivend.cfg with:

   CheckHTML  /usr/local/bin/weblint -s -

Of course, the server must be restarted for it to be recognized. The full path to the program should be used. If having trouble, check it from the command line (as with all external programs called by Interchange).

Insert [flag type=checkhtml][/tag] at the top or bottom of pages to check, and the output of the checker should be appended to the browser output as a comment, visible if the page or frame source are viewed. To do this occasionally, use a Variable setting:

   Variable  CHECK_HTML    [flag type=checkhtml]

and place __CHECK_HTML__ in the pages. Then set the Variable to the empty string to disable it.


6. Forms and Interchange

Interchange uses HTML forms for many of its functions, including ordering, searching, updating account information, and maintaining databases. Order operations possibly include ordering an item, selecting item size or other attributes, and reading user information for payment and shipment. Search operations may also be triggered by a form.

Interchange supports file upload with the multipart/form-data type. The file is placed in memory and discarded if not accessed with the [value-extended name=filevar file_contents=1] tag or written with [value-extended name=filevar outfile=your_file_name]. See Extended Value Access and File Upload.

6.1. Special Form Fields

Interchange treats some form fields specially, to link to the search engine and provide more control over user presentation. It has a number of predefined variables, most of whose names are prefixed with mv_ to prevent name clashes with your variables. It also uses a few variables which are post-fixed with integer digits; those are used to provide control in its iterating lists.

Most of these special fields begin with mv_, and include:

(O = order, S = search, C = control, A = all, X in scratch space)

Name               scan Type  Description

mv_all_chars         ac  S   Turns on punctuation matching
mv_arg[0-9]+             A   Parameters for mv_subroutine (mv_arg0,mv_arg1,...)
mv_base_directory    bd  S   Sets base directory for search file names
mv_begin_string      bs  S   Pattern must match beginning of field
mv_case              cs  S   Turns on case sensitivity
mv_cartname              O   Sets the shopping cart name
mv_cache_params          S   Determines caching of searches
mv_change_frame          A   Any form, changes frame target of form output
mv_check                 A   Any form, sets multiple user variables after update
mv_checkout              O   Sets the checkout page
mv_click                 A   Any form, sets multiple form variables before update
mv_click                 XA  Default mv_click routine, click is mv_click_arg
mv_click <name>          XA  Routine for a click <name>, sends click as arg
mv_click_arg             XA  Argument name in scratch space
mv_coordinate        co  S   Enables field/spec matching coordination
mv_column_op         op  S   Operation for coordinated search
mv_credit_card*          O   Discussed in order security (some are read-only)
mv_delay_page        dp  S   Delay search until after inital page display
mv_dict_end          de  S   Upper bound for binary search
mv_dict_fold         df  S   Non-case sensitive binary search
mv_dict_limit        di  S   Sets upper bound based on character position
mv_dict_look         dl  S   Search specification for binary search
mv_dict_order        do  S   Sets dictionary order mode
mv_doit                  A   Sets default action
mv_email                 O   Reply-to address for orders
mv_exact_match       em  S   Sets word-matching mode
mv_failpage          fp  O,S Sets page to display on failed order check/search
mv_field_file        ff  S   Sets file to find field names for Glimpse
mv_field_names       fn  S   Sets field names for search, starting at 1
mv_first_match       fm  S   Start displaying search at specified match
mv_head_skip         hs  S   Sets skipping of header line(s) in index
mv_index_delim       id  S   Delimiter for search fields (TAB default)
mv_matchlimit        ml  S   Sets match page size
mv_max_matches       mm  S   Sets maximum match return (only for Glimpse)
mv_min_string        ms  S   Sets minimum search spec size
mv_negate            ne  S   Records NOT matching will be found
mv_nextpage          np  A   Sets next page user will go to
mv_numeric           nu  S   Comparison numeric in coordinated search
mv_order_group           O   Allows grouping of master item/sub item
mv_order_item            O   Causes the order of an item
mv_order_number          O   Order number of the last order (read-only)
mv_order_quantity        O   Sets the quantity of an ordered item
mv_order_profile         O   Selects the order check profile
mv_order_receipt         O   Sets the receipt displayed
mv_order_report          O   Sets the order report sent
mv_order_subject         O   Sets the subject line of order email
mv_orsearch          os  S   Selects AND/OR of search words
mv_profile           mp  S   Selects search profile
mv_range_alpha       rg  S   Sets alphanumeric range searching
mv_range_look        rl  S   Sets the field to do a range check on
mv_range_max         rx  S   Upper bound of range check
mv_range_min         rm  S   Lower bound of range check
mv_record_delim      dr  S   Search index record delimiter
mv_return_all        ra  S   Return all lines found (subject to range search)
mv_return_delim      rd  S   Return record delimiter
mv_return_fields     rf  S   Fields to return on a search
mv_return_file_name  rn  S   Set return of file name for searches
mv_return_spec       rs  S   Return the search string as the only result
mv_save_session          C   Set to non-zero to prevent expiration of user session
mv_search_field      sf  S   Sets the fields to be searched
mv_search_file       fi  S   Sets the file(s) to be searched
mv_search_line_return lr S   Each line is a return code (loop search)
mv_search_match_count    S   Returns the number of matches found (read-only)
mv_search_page       sp  S   Sets the page for search display
mv_searchspec        se  S   Search specification
mv_searchtype        st  S   Sets search type (text, glimpse, db or sql)
mv_separate_items        O   Sets separate order lines (one per item ordered)
mv_session_id        id  A   Suggests user session id (overridden by cookie)
mv_shipmode              O   Sets shipping mode for custom shipping
mv_sort_field        tf  S   Field(s) to sort on
mv_sort_option       to  S   Options for sort
mv_spelling_errors   er  S   Number of spelling errors for Glimpse
mv_substring_match   su  S   Turns off word-matching mode
mv_successpage           O   Page to display on successful order check
mv_todo                  A   Common to all forms, sets form action
mv_todo.map              A   Contains form imagemap
mv_todo.checkout.x       O   Causes checkout action on click of image
mv_todo.return.x         O   Causes return action on click of image
mv_todo.submit.x         O   Causes submit action on click of image
mv_todo.x                A   Set by form imagemap
mv_todo.y                A   Set by form imagemap
mv_unique            un  S   Return unique search results only
mv_value             va  S   Sets value on one-click search (va=var=value)

6.2. Form Actions

Interchange form processing is based on an action and a todo. The predefined actions at the first level are:

   process       process a todo
   search        form-based search
   scan          path-based search
   order         order an item
   minimate      get access to a database via MiniMate

Any action can be defined with ActionMap.

The process action has a second todo level called with mv_todo or mv_doit. The mv_todo takes preference over mv_doit, which can be used to set a default if no mv_todo is set.

The action can be specified with any of:

page name

            <FORM ACTION="/cgi-bin/simple/search" METHOD=POST>
            <INPUT NAME=mv_searchspec>
            </FORM>
            <FORM ACTION="[area search]" METHOD=POST>
            <INPUT NAME=mv_searchspec>
            </FORM>
            <FORM ACTION="[process]" METHOD=POST>
            <INPUT TYPE=hidden NAME=mv_todo VALUE=search>
            <INPUT NAME=mv_searchspec>
            </FORM>

mv_action

            <FORM ACTION="[area foo]" METHOD=post>
            <INPUT TYPE=hidden NAME=mv_action VALUE=search>
            <INPUT NAME=mv_searchspec>
            </FORM>

The second level todo for the process action has these defined by default:

   back         Go to mv_nextpage, don't update variables
   search   Trigger a search
   submit   Submit a form for validation (and possibly a final order)
   go       Go to mv_nextpage (same as return)
   return   Go to mv_nextpage, update variables
   set      Update a database table
   refresh  Go to mv_orderpage|mv_nextpage and check for
            ordered items
   cancel   Erase the user session

If a page name is defined as an action with ActionMap or use of Interchange's predefined action process, it will cause form processing. First level is setting the special page name process, or mv_action set to do a form process, the Interchange form can be used for any number of actions. The actions are mapped by the ActionMap directive in the catalog configuration file, and are selected on the form with either the mv_todo or mv_doit variables.

To set a default action for a process form, set the variable mv_doit as a hidden variable:

   <INPUT TYPE=hidden NAME=mv_doit VALUE=refresh>

When the mv_todo value is not found, the refresh action defined in mv_doit will be used instead.

More on the defined actions:

back

cancel

refresh

return

search

submit

6.3. One-click Multiple Variables

Interchange can set multiple variables with a single button or form control. First define the variable set (or profile, as in search and order profiles) inside a scratch variable:

 [set Search by Category]
 mv_search_field=category
 mv_search_file=categories
 mv_todo=search
 [/set]

The special variable mv_click sets variables just as if they were put in on the form. It is controlled by a single button, as in:

   <INPUT TYPE=submit NAME=mv_click VALUE="Search by Category">

When the user clicks the submit button, all three variables will take on the values defined in the "Search by Category" scratch variable. Set the scratch variable on the same form as the button is on. This is recommended for clarity. The mv_click variable will not be carried from form to form, it must be set on the form being submitted.

The special variable mv_check sets variables for the form actions <checkout, control, refresh, return, search,> and <submit>. This function operates after the values are set from the form, including the ones set by mv_click, and can be used to condition input to search routines or orders.

The variable sets can contain and be generated by most Interchange tags. The profile is interpolated for Interchange tags before being used. This may not always operate as expected. For instance, if the following was set:

   [set check]
   [cgi name=mv_todo set=bar hide=1]
   mv_todo=search
   [if cgi mv_todo eq 'search']
   do something
   [/if]
   [/set]

The if condition is guaranteed to be false, because the tag interpretation takes place before the evaluation of the variable setting.

Any setting of variables already containing a value will overwrite the variable. To build sets of fields (as in mv_search_field and mv_return_fields), comma separation if that is supported for the field must be used.

It is very convenient to use mv_click as a trigger for embedded Perl:

   <FORM ...
   <INPUT TYPE=hidden NAME=mv_check VALUE="Invalid Input">
   ...
   </FORM>

   [set Invalid Input]
   [perl]
   my $type        = $CGI->{mv_searchtype};
   my $spell_check = $CGI->{mv_spelling_errors};
   my $out = '';
   if($spell_check and $type eq 'text') {
       $CGI->{mv_todo}     = 'return';
       $CGI->{mv_nextpage} = 'special/cannot_spell_check';
   }
   return;
   [/perl]
   [/set]

6.4. Checks and Selections

A "memory" for drop-down menus, radio buttons, and checkboxes can be provided with the [checked] and [selected] tags.

[checked var_name value]

[selected var_name value]

            <SELECT NAME="color">
            <OPTION [selected name=color value=blue]> Blue
            <OPTION [selected name=color value=green]> Green
            <OPTION [selected name=color value=red]> Red
            </SELECT>
            <SELECT NAME=color>
            [loop list="Blue Green Red" option=color]
            <OPTION> [loop-code]
            [/loop]
            </SELECT>

6.5. Integrated Image Maps

Imagemaps can also be defined on forms, with the special form variable mv_todo.map. A series of map actions can be defined. The action specified in the default entry will be applied if none of the other coordinates match. The image is specified with a standard HTML 2.0 form field of type IMAGE. Here is an example:

<INPUT TYPE=hidden NAME="mv_todo.map" VALUE="rect submit 0,0 100,20">
<INPUT TYPE=hidden NAME="mv_todo.map" VALUE="rect cancel 290,2 342,18">
<INPUT TYPE=hidden NAME="mv_todo.map" VALUE="default refresh">
<INPUT TYPE=image  NAME="mv_todo" SRC="url_of_image">

All of the actions will be combined together into one image map with NCSA-style functionality (see the NCSA imagemap documentation for details), except that Interchange form actions are defined instead of URLs.

6.6. Setting Form Security

You can cause a form to be submitted securely (to the base URL in the SecureURL directive, that is) by specifying your form input to be ACTION="[process secure=1]".

To submit a form to the regular non-secure server, just omit the secure modifier.

6.7. Stacking Variables on the Form

Many Interchange variables can be "stacked," meaning they can have multiple values for the same variable name. As an example, to allow the user to order multiple items with one click, set up a form like this:

<FORM METHOD=POST ACTION="[process-order]">
<input type=checkbox name="mv_order_item" value="M3243"> Item M3243
<input type=checkbox name="mv_order_item" value="M3244"> Item M3244
<input type=checkbox name="mv_order_item" value="M3245"> Item M3245
<input type=hidden name="mv_doit" value="refresh">
<input type=submit name="mv_junk" value="Order Checked Items">
</FORM>

The stackable mv_order_item variable with be decoded with multiple values, causing the order of any items that are checked.

To place a "delete" checkbox on the shopping basket display:

<FORM METHOD=POST ACTION="[process-order]">
[item-list]
  <input type=checkbox name="[quantity-name]" value="0"> Delete
  Part number: [item-code]
  Quantity: <input type=text name="[quantity-name]" value="[item-quantity]">
  Description: [item-description]
[/item-list]
<input type=hidden name="mv_doit" value="refresh">
<input type=submit name="mv_junk" value="Order Checked Items">
</FORM>

In this case, first instance of the variable name set by [quantity-name] will be used as the order quantity, deleting the item from the form.

Of course, not all variables are stackable. Check the documentation for which ones can be stacked or experiment.

6.8. Extended Value Access and File Upload

Interchange has a facility for greater control over the display of form variables; it also can parse multipart/form-data forms for file upload.

File upload is simple. Define a form like:

   <FORM ACTION="[process-target] METHOD=POST ENCTYPE="multipart/form-data">
   <INPUT TYPE=hidden NAME=mv_todo     VALUE=return>
   <INPUT TYPE=hidden NAME=mv_nextpage VALUE=test>
   <INPUT TYPE=file NAME=newfile>
   <INPUT TYPE=submit VALUE="Go!">
   </FORM>

The [value-extended ...] tag performs the fetch and storage of the file. If the following is on the test.html page (as specified with mv_nextpage and used with the above form, it will write the file specified:

   <PRE>
   Uploaded file name: [value-extended name=newfile]
   Is newfile a file? [value-extended name=newfile yes=Yes no=No test=isfile]

   Write the file. [value-extended name=newfile outfile=junk.upload]
   Write again with
    indication: [value-extended name=newfile
                               outfile=junk.upload
                               yes="Written."]
                               no=FAILED]

   And the file contents:
   [value-extended name=newfile file_contents=1]
   </PRE>

The [value-extended] tag also allows access to the array values of stacked variables. Use the following form:

   <FORM ACTION="[process-target] METHOD=POST ENCTYPE="multipart/form-data">
   <INPUT TYPE=hidden NAME=testvar VALUE="value0">
   <INPUT TYPE=hidden NAME=testvar VALUE="value1">
   <INPUT TYPE=hidden NAME=testvar VALUE="value2">
   <INPUT TYPE=submit VALUE="Go!">
   </FORM>

and page:

   testvar element 0: [value-extended name=testvar index=0]
   testvar element 1: [value-extended name=testvar index=1]
   testvar elements:
    joined with a space:   |[value-extended name=testvar]|
    joined with a newline: |[value-extended
                               joiner="\n"
                               name=testvar
                               index="*"]|
    first two only:    |[value-extended
                               name=testvar
                               index="0..1"]|
    first and last:    |[value-extended
                               name=testvar
                               index="0,2"]|

to observe this in action.

The syntax for [value-extended ...] is:

named: [value-extended
           name=formfield
           outfile=filename*
           ascii=1*
           yes="Yes"*
           no="No"*
           joiner="char|string"*
           test="isfile|length|defined"*
           index="N|N..N|*"
           file_contents=1*
           elements=1*]

positional: [value-extended name]

Expands into the current value of the customer/form input field named by field. If there are multiple elements of that variable, it will return the value at index; by default all joined together with a space.

If the variable is a file variable coming from a multipart/form-data file upload, then the contents of that upload can be returned to the page or optionally written to the outfile.

name

joiner

test

index

file_contents

outfile

ascii

yes

no

6.9. Updating Interchange Database Tables with a Form

Any Interchange database can be updated with a form using the following method. The Interchange user interface uses this facility extensively.


Note: All operations are performed on the database, not the ASCII source file. An [export table_name] operation will have to be performed for the ASCII source file to reflect the results of the update. Records in any database may be inserted or updated with the [query] tag, but form-based updates or inserts may also be performed.

In an update form, special Interchange variables are used to select the database parameters:

mv_data_enable (scratch)

            [set update_database]
            [if type=data term="userdb::trusted::[data session username]"]
                [set mv_data_enable]1[/set]
            [else]
                [set mv_data_enable]0[/set]
            [/else]
            [/if]
            [/set]
            <INPUT TYPE=hidden NAME=mv_click VALUE=update_database>

mv_data_table

mv_data_key

mv_data_function

mv_data_verify

mv_data_fields

mv_update_empty

mv_data_filter_(field)

The Interchange action set causes the update. Here are a pair of example forms. One is used to set the key to access the record (careful with the name, this one goes into the user session values). The second actually performs the update. It uses the [loop] tag with only one value to place default/existing values in the form based on the input from the first form:

   <FORM METHOD=POST ACTION="[process]">
    <INPUT TYPE=HIDDEN name="mv_doit" value="return">
    <INPUT TYPE=HIDDEN name="mv_nextpage" value="update_proj">
    Sales Order Number <INPUT TYPE=TEXT SIZE=8
                            NAME="update_code"
                            VALUE="[value update_code]">
    <INPUT TYPE=SUBMIT name="mv_submit"  Value="Select">
    </FORM>
<FORM METHOD=POST ACTION="[process]">
   <INPUT TYPE=HIDDEN NAME="mv_data_table"    VALUE="ship_status">
   <INPUT TYPE=HIDDEN NAME="mv_data_key"      VALUE="code">
   <INPUT TYPE=HIDDEN NAME="mv_data_function" VALUE="update">
   <INPUT TYPE=HIDDEN NAME="mv_nextpage"      VALUE="updated">
   <INPUT TYPE=HIDDEN NAME="mv_data_fields"
               VALUE="code,custid,comments,status">
   <PRE>

   [loop arg="[value update_code]"]
   Sales Order <INPUT TYPE=TEXT NAME="code    SIZE=10 VALUE="[loop-code]">
  Customer No. <INPUT TYPE=TEXT NAME="custid" SIZE=30
                   VALUE="[loop-field custid]">
      Comments <INPUT TYPE=TEXT NAME="comments"
                   SIZE=30 VALUE="[loop-field comments]">
        Status <INPUT TYPE=TEXT NAME="status"
                   SIZE=10 VALUE="[loop-field status]">
   [/loop]
   </PRE>

       <INPUT TYPE=hidden NAME="mv_todo" VALUE="set">
       <INPUT TYPE=submit VALUE="Update table">
   </FORM>

The variables in the form do not update the user's session values, so they can correspond to database field names without fear of corrupting the user session.


7. Frequently Asked Questions

7.1. How do you pass variables from page to page?

No effort needed. Interchange does this automatically. Every user session that is started by Interchange automatically creates a variable set for the user. As long as the user session is maintained, and does not expire, any variables you set on a form will be "remembered" in future sessions.

Don't use the prefix mv_ for your own variables. Interchange treats these specially and they may not behave as you wish. Use the mv_ variables only as they are documented.

Also, because you can set so many variables, Interchange does not unset variables it does not find on the current form. That means you can't expect a checkbox to become unchecked unless you explicitly reset it.

7.2. How can I tell when I need to quote a tag inside a tag?

In general, you don't need to quote the following tags which are interpreted first within a list:

   [item-code] [item-data ...] [item-field ...] etc.
   [loop-code] [loop-data ...] [loop-field ...] etc.
   [foo-code]  [foo-data ...]   [foo-field ...] etc.

This is because they are interpreted as a part of the surrounding [loop], [item-list], [search-list], [sql list], or [tag each table] constructs.

So this will work:

   [item-list]
   [page [item-field url]]detailed info[/page] on [item-description]
   [/item-list]

This will not work:

   [page [value mypage]]

The [value ...] tag is not interpolated before page, and the parser will not know to do so. It needs to be instead:

   [page href="[value mypage]"]

You might wonder why unquoted tags are even allowed. The answer is performance. If you have large lists of tags you can achieve significant speedups by using positional parameters. It requires CPU power to parse and disassemble the named parameters.

7.3. Can I use Interchange with my existing static catalog pages?

Yes, but you probably won't want to in the long run. Interchange is designed to build pages based on templates from a database. If all you want is a shopping cart, you can mix standard static pages with Interchange, but it is not as convenient and doesn't take advantage of the many dynamic features Interchange offers.

That being said, all you usually have to do to place an order link on a page is:

   <A HREF="/cgi-bin/construct/order?mv_order_item=SKU_OF_ITEM">Order!</A>

Replace /cgi-bin/construct with the path to your Interchange link.