NAME
    "CGI::Explorer" - A class to manage displaying a hash tree of data, for
    use in CGI scripts

    The format of the hash is discussed in the FAQ section.

Synopsis
    Install /css/xtree.css, /js/xtree.js, and /images/*, as per the
    installation instructions, below.

    Then run the demos example/bootstrap-hobbit.pl, which creates a database
    table using "DBIx::Hash2Table", and then example/hobbit.cgi, which reads
    a database table using "DBIx::Table2Hash".

    Or, run example/hobbit-hash.cgi which has the same hash directly in the
    source code.

Description
    "CGI::Explorer" is a pure Perl module.

    It is a support module for CGI scripts. It manages a hash, a tree of
    data, so that the script can display the tree, and the user can
    single-click on the [+] or [-] of a node, or double-click on the icon of
    a node, to open or close that node's sub-tree.

    Opening a node reveals all children of that node, and restores their
    open/closed state.

    Closing a node hides all children of that node.

    When you click on the text of a node, the node's id is submitted to the
    CGI script via the path info of the URL attached to that node. This path
    info mechanism can be overridden.

    The id is assigned to the node when you call the method "hash2tree()",
    which is where the module converts your hash into JavaScript.

    Neither the module CGI.pm, nor any of that kidney, are used by this
    module.

Installation
    The makefile will install /perl/site/lib/CGI/Explorer.pm.

    You must manually install <Document Root>/css/xtree.css, <Document
    Root>/js/xtree.js, and <Document Root>/images/*.

    If you choose to put the CSS elsewhere, you'll need to call new(css =>
    '/new/path/xtree.css').

    If you choose to put the JavaScript elsewhere, you'll need to call
    new(js => '/new/path/xtree.js').

    These last 2 options can be used together, and can be passed into
    "hash2tree()" or "set()" rather than "new()".

    If you choose to put the images elsewhere, you'll need to edit lines 62
    .. 74 of xtree.js V 1.15.

Warning: V 1 'v' V 2
    The API for "CGI::Explorer" version 2 is not compatible with the API for
    version 1.

    This is because version 2 includes CSS and JavaScript to handle
    expanding and contracting sub-trees purely within the client. No longer
    do client mouse clicks cause a round trip to the server/CGI script and
    back.

Constructor and initialization
    new(...) returns a "CGI::Explorer" object.

    This is the class's contructor.

    Almost every option is demonstrated by the program example/hobbit.cgi.

    Note: All methods (except "get()") use named parameters.

    Options:

    *   behavior

        Usage: CGI::Explorer -> new(behavior => 'classic').

        This option takes one of two values:

        *   classic

            This is the default.

            classic means the leaf nodes on the tree have a document icon.

        *   explorer

            explorer means the leaf nodes have a folder icon, ie they look
            like those in MS Windows Explorer, even though they can't be
            opened.

        Note: I have adopted the non-Australian spelling of behavior, as
        used by Emil A Eklund in the JavaScript shipped with
        "CGI::Explorer".

    *   css

        Usage: CGI::Explorer -> new(css => '/css/xtree.css').

        This points to a file of CSS used to display the tree.

        The default is '/css/xtree.css'.

        Emil A Eklund is the author of xtree.css.

        The make file does not install this CSS file automatically. You must
        install it manually under the web server's document root.

    *   current_icon

        Usage: CGI::Explorer -> new(current_icon => '/path/to/image for
        current icon').

        This option takes one of two values:

        *   '' (the empty string)

            This is the default.

            This stops the currently selected node from being given a
            special icon.

        *   '/path/to/image for current icon'

            Eg: the file '/images/current.png' is shipped with this module.

            This gives the currently selected node the icon defined by the
            value of the string.

    *   current_id

        Usage: CGI::Explorer -> hash2tree(current_id => $id, ...).

        This is the value retrieved by you from the URL's path info, and
        passed into one of the methods.

        The default value is ''.

    *   current_key

        Usage: $key = $explorer -> id2key() or $key = $explorer ->
        get('current_key').

        This is the value of the string of keys, joined by $;, which lead
        from the root of the tree to the node whose id is the value of
        current_id.

        The default value is ''.

    *   form_name

        Usage: CGI::Explorer -> new(form_name => 'explorer_form').

        This is simply a convenient place to store a default form name.
        Ignore this parameter if you wish.

        The default is 'explorer_form'.

        Warning: Under MS Internet Explorer, some words are reserved, and
        can not be used as form names. I think you'll find 'explorer', and
        perhaps 'form', are reserved in such circumstances.

    *   hashref

        Usage: CGI::Explorer -> new(hashref => {...}).

        This is a reference to a tree-structured hash which contains the
        data to be displayed.

        From example/hobbit.cgi it will be clear that some CPAN modules'
        methods, eg my DBIx::Table2Hash -> select_tree(), can return a hash
        suitable for passing directly into "new()" or "hash2tree()".

        The default is {}.

    *   header_type

        Usage: CGI::Explorer -> new(header_type =>
        'text/html;charset=ISO-8859-1').

        This is simply a convenient place to store a default HTTP header
        type. Ignore this parameter if you wish.

        The default is 'text/html;charset=ISO-8859-1'.

    *   js

        Usage: CGI::Explorer -> new(js => '/js/xtree.js').

        This points to a file of JavaScript used to manipulate the tree.

        The default is '/js/xtree.js'.

        Emil A Eklund is the author of xtree.js.

        The make file does not install this JavaScript file automatically.
        You must install it manually under the web server's document root.

        Note: I've made one systematic change to xtree.js V 1.15. I've
        changed lines 62 .. 74 to add a '/' prefix to the paths of the
        images. This means you should install the images/ directory under
        your web server's document root.

    *   jscript

        Usage: CGI::Explorer -> new(jscript => '...').

        This is any JavaScript you wish, and which becomes the prefix of the
        JavaScript generated to populate the tree from the given hash.

        The default is ''.

        Warning: Be clear about the differences between the 2 parameters
        'js' and 'jscript'.

    *   left_style

        Usage: CGI::Explorer -> new(left_style => '<Some CSS>').

        This is a string of CSS used to format the HTML div of the left-hand
        pane, ie the one in which the tree is displayed.

        The default is 'position: absolute; width: 20em; top: 7em; left:
        0.25em; padding: 0.25em; overflow: auto; border: 2px solid
        #e0e0e0;'.

    *   node_id

        Usage: CGI::Explorer -> new(node_id => 'js_rm_00').

        The default is 'rm00000', where rm stands for run mode.

        See the FAQ for a discussion of the role of this parameter.

        Note especially the warnings mentioned in the FAQ regarding the
        syntax of values for this option.

    *   right_style

        Usage: CGI::Explorer -> new(right_style => '<Some CSS>').

        This is a string of CSS used to format the HTML div of the
        right-hand pane, ie the one in which the CGI script's output is
        displayed.

        The default is 'position: absolute; left: 20.25em; top: 7em;
        padding: 0.25em; border: 2px solid #e0e0e0;'.

    *   target

        Usage: CGI::Explorer -> new(target => '<name of a frame>').

        Recall the operating environment: A CGI script uses this module, and
        that script has been run, so the user is looking at a tree which
        contains clickable node names. That tree could be in one frame, and
        you want clicks on node names to re-run the CGI script, and to have
        the script's output go to a different frame than the frame
        containing the tree itself.

        This option, then, allows you to have your script output to a named
        frame, and specifically a frame different than the one which
        received the user's click on the node's name.

        Note: After you use this option, clicks on nodes all output to the
        same frame. You cannot use this option to direct clicks on node A to
        one frame and clicks on node B to a different frame. In other words,
        this option is currently tree-wide, and cannot be changed on a
        node-by-node basis.

        If you are using CGI.pm, call header() thus:

                print $q -> header({type => 'text/html', target => 'right'});

        Lincoln Stein's book on CGI.pm contains a mis-print on page 222
        which says frame => 'responses'. Do not use 'frame'.

        As you can see, I pass an anonymous hash into every one of CGI.pm's
        methods. This always works, whereas using '-type' etc sometimes
        fails silently :-(.

        If you are using raw HTML, specify target thus:

                <a href = 'http://some.domain.net.au/cgi-bin/x.cgi' target = 'right'>Log in</a>

    *   tree

        Usage: $tree = $explorer -> get('tree').

        This is the tree of JavaScript returned by "hash2tree()".

    *   url

        Usage: CGI::Explorer -> new(url => $q -> url() ).

        This is a string for the URL to be submitted when the node's text is
        clicked.

        The default is ''.

        If you use "CGI.pm"'s "url()" method to obtain the default URL, you
        get something like 'http://127.0.0.1/perl/hobbit.cgi'. You're
        advised to shorten this to '/perl/hobbit.cgi' before passing it into
        "new()" or "hash2tree()", since a copy of this string is attached to
        each node, and the shorter version saves you around 20 bytes per
        node.

        Each node will, by default, be given the same URL, with only the
        path info varying from node to node. The URL has the node's id
        appended as path info, when the node is copied from your hash and
        inserted into the tree. Hence the node's URL will then be of the
        form "$url/$id".

        See the FAQ for a discussion of how ids are generated.

        It is this final URL, "$url/$id", which is passed back to your CGI
        script when a node's text is clicked.

        It is up to you, as author of the CGI script, to know what to do, ie
        what code to execute, for a given id.

        You can think of your CGI script as a callback, being triggered by
        events in the client. Then, this id is what your callback uses to
        determine what action to take for each client request.

        If you wish to override this system, use the reserved hash key
        '_url', as described in the FAQ.

FAQ
    Q: What is the format of this thing you call a 'hash tree'?

    A: It is simply a hash, with these characteristics:

    *   It has a single root.

        So, if your hash looks like this:

                my($h) = {Key => {...} };

        then you can pass $h into method "hash2tree()".

        But, if you hash has multiple roots like this:

                my($h) = {Key_1 => {...}, Key_2 => {...} };

        you must call "hash2tree()" like this:

                $explorer -> hash2tree(hashref => {Mother_Of_All_Roots => $h});

        so as to ensure hashref points to a hash with a single root.

    *   Hash keys are displayed in sorted order

        This uses Perl's default sorting mechanism.

    *   Keys and sub-keys

        Keys either point to a string, eg undef, '' or 'Data', or keys point
        to hashrefs, which is what makes the hash a tree. Eg:

                my($h)={Root=>{Key_1=>undef,Key_2=>{Key_3=>{...},Data=>''},Key_4=>{}};

        Note: See how Key_4 can point to an empty hash.

        See example/hobbit-hash.cgi for a CGI script with a hash embedded in
        the source.

        See example/bootstrap-hobbit.pl for a command line script with the
        same hash embedded in the source, and which writes the hash to a
        database table. See example/hobbit.cgi for a CGI script which reads
        and displays that database table.

        Note: Some of the URLs in the demo hash point to non-existant CGI
        scripts. It's a demo, after all.

    *   All hash keys matching /^_/ are treated specially

        That is, they are ignored when building the visible part of the
        tree.

        This is slightly unusual, so read slowly :-).

        *   Hash keys matching /^_node_id$/ are used to override the default
            id appended to a node's URL

            See the discussion of _url 2 items down for details.

        *   Hash keys matching /^_(open|shut)_icon$/ are special

            These apply to each node, and hence could be different for every
            node.

            These options allow you to specify an image for when a specific
            node is in the open and/or closed state.

            Note: The _current_icon parameter to new() applies to the tree
            as a whole.

        *   Hash keys matching /^_url$/ are used to override the default URL
            of a node

            Given a hash key like:

            Mega_key => {Nested_key_if_any => {} }

            then the default URL attached to the node labelled Mega_key is
            overridden thus:

            Mega_key => {_url => 'Special URL', Nested_key_if_any => {} }

            See how _url is a sub-key (child) of the key who actually owns
            this URL.

            Clearly, this overriding mechanism operates on a node-by-node
            basis, so any node can be given any node id and/or URL.

            Even when this option is used, the node's id is still appended
            to this special URL as path info.

    *   The tree must be constant

        The hash used to build the tree must be constant from one execute of
        the CGI script to the next, or the id generated for a node on the
        first execute and hence returned by the client may not match the id
        generated for the same node on the second execute.

    *   Bugs in Apache/mod_perl/Perl/CGI.pm

        In this environment: Win2K, Apache 1.3.26, mod_perl 1.27_01-dev,
        Perl 5.6.1, CGI.pm 2.89, the CGI method path_info(), when given a
        URL without any path info, returns the path info from the previous
        submit, but only if the CGI script is running as an Apache::Registry
        script. When the CGI script is run as a simple cgi-bin script, this
        bug is not manifest.

        This is very like the behavior of my()-scoped variables in nested
        subroutines, documented here:

        http://perl.apache.org/docs/general/perl_reference/perl_reference.ht
        ml

        Click on: 'my() Scoped Variable in Nested Subroutines' for details.

        You have been warned.

    Q: Why use em rather than px in left_style and right_style?

    A: The designers of CSS2, Hakon Lie and Bert Bos, recommend using
    relative sizes, and specifically em.

    Q: Why does my tree display 'funny'?

    A: Because browsers vary in how well they render CSS.

    Under Win2K, IE 6.00.2600, the style 'overflow: auto' in left_style
    renders as it should.

    Under Win2K, IE 5.00.3502, 'overflow: auto' renders as though you had
    specified 'overflow: visible'.

    Q: How do I configure Apache V 2 to use /perl/ the way you recommend in
    the next Q?

    A: Add these options to httpd.conf and restart the server:

            Alias /perl/ "/apache2/perl/"
            <Location /perl>
                    SetHandler perl-script
                    PerlResponseHandler ModPerl::Registry
                    Options +ExecCGI
                    PerlOptions +ParseHeaders
                    Order deny,allow
                    Deny from all
                    Allow from 127.0.0.1
            </Location>

    Q: How do I run the demo?

    A: Install example/hobbit.cgi as /apache2/perl/hobbit.cgi and run it via
    your browser, by typing

            http://127.0.0.1/perl/hobbit.cgi

    into your browser. Study the screen.

    Now, click on the [+] signs to open the tree until you can see 'Evil
    Grey Gnome', noting the spelling of Grey.

    Now click on the text 'Evil Grey Gnome'.

    Lastly, click on 'Prettiest grand gnome' in the breadcrumb trail. Neat,
    huh?

    Note: The update button in example/hobbit.cgi does not actually do
    anything.

    Q: How are node ids generated?

    A: Well, by rolling your mouse over the nodes' texts, you can see in the
    browser's status line URLs like:

            http://127.0.0.1/perl/hobbit.cgi/rm00006

    (for Evil Grey Gnome)

    These ids are generated sequentially, starting with 'rm00000'. So, the
    second id will be 'rm00001', and so on.

    The initial value is the default value for the node_id parameter to
    "new()" or "hash2tree()".

    Hence you can control the values of the ids by initializing the node_id
    parameter, subject to the warnings which follow.

    Values for node_id are generated for all nodes in the hash tree for
    which you have not supplied a node-specific value for node_id.

    Warning:

    *   The node_id string has a trailing integer

        The code "$$self{'_node_id'}++;" is used to increment ids. This
        means that if you wish to override the default value for node_id,
        you absolutely must supply an initial value for node_id which has a
        nice set of trailing zeros (just like the cheque you're thinking of
        sending me for releasing such a great module :-).

        Hence the default value 'rm00000'.

        Warning: You can't use a value like '_00' because Perl discards the
        '_' when incrementing such a string.

    *   All values of the node_id string are the names of JavaScript
        variables

        This means that if you wish to override the default value for
        node_id, you absolutely must supply a value for node_id which is a
        valid JavaScript variable name.

        Hence the default value 'rm00000'.

        Hence, also, the values in the _node_id column of the hobbit table
        generated by the program example/bootstrap-hobbit.cgi.

    Q: How is the breadcrumb trail in example/hobbit.cgi generated?

    A: See the source.

    Q: How do I know when to pass a given parameter in to a method? Eg: Do I
    call "new()" or "hash2tree()" to set a value for node_id or
    current_icon?

    A: You can pass in any parameter to any method (except "get()") at any
    time before that parameter is actually needed.

    All methods (except "get()") take a list of named parameters, and store
    the values of the parameters internally within the object.

    So, when you see this code in example/hobbit.cgi:

            my($tree)       =$explorer->hash2tree(current_id=>$current_id,hashref=>$hash);
            my($current_key)=$explorer->id2key();

    you know the call to "id2key()" must be using the value of current_id
    passed in in the call to "hash2tree()".

    You could have used this code:

            my($tree)       =$explorer->hash2tree(hashref=>$hash);
            my($current_key)=$explorer->id2key(current_id=>$current_id);

    but that would mean the value of current_id was not available during the
    call to "hash2tree()", so the current node in the tree could not have
    had the special icon designated by the value of the parameter
    current_icon (if you passed in a value for current_icon in the call to
    "new()" or "hash2tree()" of course.), because at the time of calling
    "hash2tree()", the code in that module would not know the value of
    current_id.

    Even worse, if current_id somehow had a value from a previous call to a
    method, the wrong node would be flagged as the current node.

    Q: I'm running on a Pentium II at 266MHz. I'm finding that as I get up
    to many hundreds of nodes, it takes a long time to update the screen.

    A: Yes.

    Emil has kindly offered to work on speeding things up. I have one idea,
    but have not tried implementing it yet.

Method: hash2tree(current_id => $current_id, hashref => $hash)
    Returns the JavaScript which populates the tree.

    You can also retrieve this JavaScript by calling:

            $explorer -> hash2tree(hashref => $hashref);
            my($tree) = $explorer -> get('jscript') . $explorer -> get('tree');

    Note: $explorer -> get('js') returns the name of the file of JavaScript
    written by Emil, ie '/js/xtree.js', by default. Try not to get the 2
    options 'js' and 'jscript' confused. It'll make you look silly :-).

    The 2 parameters listed here are those you would normally pass into
    "hash2tree()", but you are not limited to these parameters.

Method: get('Name of object attribute')
    Returns the value of the named attribute. These attributes are discussed
    above, in the section called 'Constructor and initialization'.

    The demo example/hobbit.cgi calls this method a number of times.

Method: get_node([current_id => $id])
    Returns a hash ref.

    The [] refer to an optional parameter, not to an array ref.

    This method uses the value of current_id to find and return the node
    corresponding to current_id.

    If current_id is '', the get_node returns the value you previously
    passed in for the hashref option.

Method: id2key([current_id => $id])
    Returns a string.

    The [] refer to an optional parameter, not to an array ref.

    This method converts a node id, eg retrieved from the path info, into a
    string which contains, in order, all hash keys required to find the node
    within the tree.

    The hash keys are separated by $;, aka $SUBSCRIPT_SEPARATOR.

    The demo example/hobbit.cgi has an example which uses this method.

Method: key2id([current_key => $key])
    Returns a string.

    The [] refer to an optional parameter, not to an array ref.

    This method converts a string of hash keys, concatenated with $;, into
    the corresponding node id.

    By default, this method uses the value of current_key generated by a
    previous call to "id2key()".

Method: key2url([current_key => $key])
    Returns a string.

    The [] refer to an optional parameter, not to an array ref.

    This method converts a string of hash keys, concatenated with $;, into
    the corresponding node URL.

    By default, this method uses the value of current_key generated by a
    previous call to "id2key()".

Method: new(...)
    Returns a object of type "CGI::Explorer".

    See above, in the section called 'Constructor and initialization'.

Method: set(%arg)
    Returns nothing.

    This allows you to set any option after calling the constructor.

    Eg: $explorer -> set(css => '/css/even_better.css');

Icons for Nodes
    "CGI::Explorer" ships with an images/ directory containing 1 or 2
    (open/closed) PNGs for each icon.

    Most of these icons are those shipped by Emil A Eklund in his xtree
    package.

    I have added 3 icons to the set, all from this web site:

    http://www.geocities.com/windowsicons/

    *   open.png

        Collection: Replacements for Win95/98 system-icons.

        Original icon file: foldrs02.ico.

    *   shut.png

        Collection: Replacements for Win95/98 system-icons.

        Original icon file: foldrs01.ico.

    *   current.png

        Collection: Pointers, arrows and hands.

        Original icon file: 'arrow #3.ico'.

    The make file does not install this images/ directory automatically. You
    must install it manually under the web server's document root.

Required Modules
    None, not even CGI.pm. Well OK, one - Exporter.

    In particular, the fine module Tree::Nary, used in V 1 of
    "CGI::Explorer", is no longer needed.

Changes
    See Changes.txt.

Credits
    "CGI::Explorer" V 2 depends heavily on the superb package xtree, written
    by Emil A Eklund, and in fact my module is no more than a Perl wrapper
    around xtree.

    Please visit the web site http://www.eae.net (from his initials) where
    more goodies by Emil and his colleague Erik Arvidsson are on display.

Unused Namespace - DBIx::CSS::TreeMenu
    In the POD for 2 recent modules, I intimated I was going to release a
    module called DBIx::CSS::TreeMenu, which of course was to be based on
    xtree.

    However, I've since decided to incorporate these ideas into
    "CGI::Explorer" V 2.

    There is clearly no need for the current module to be linked into the
    DBIx:: namespace. Further, CSS is a mechanism used, and while it could
    be in the namespace, I no longer think that is appropriate. Otherwise,
    any module using CSS would have CSS:: in it's name, and taken to the
    illogical extreme, all modules would be in the Perl:: namespace!

    So, I'm abandoning all plans to issue a module called
    DBIx::CSS::TreeMenu.

    However, I still have my eye on another package, by Erik Arvidsson,
    called tabpane. I am intending to put a Perl wrapper around tabpane, but
    have not yet decided on a Perl module name.

Author
    "CGI::Explorer" was written by Ron Savage *<ron@savage.net.au>* in 2001.

    Home page: http://savage.net.au/index.html

Copyright
    Australian copyright (c) 2001, Ron Savage. All rights reserved.

            All Programs of mine are 'OSI Certified Open Source Software';
            you can redistribute them and/or modify them under the terms of
            The Artistic License, a copy of which is available at:
            http://www.opensource.org/licenses/index.html

