The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
NAME
    CGI::Panel - Create sophisticated event-driven web applications from
    simple panel objects

SYNOPSIS
      A very simple application...

        ---------------

      in simpleapp.cgi:

        use SimpleApp;
        my $simple_app = obtain SimpleApp;
        $simple_app->cycle();

        ---------------

      in SimpleApp.pm:

        package SimpleApp;

        use strict;
        use Basket;
        use base qw(CGI::Panel);

        sub init {
            my ($self) = @_;
            $self->add_panel('basket', new Basket); # Add a sub-panel
            $self->{count} = 1;   # Initialise some persistent data
        }

        sub _event_add {    # Respond to the button click event below
            my ($self, $event) = @_;

            $self->{count}++;  # Change the persistent data
        }

        sub display {
            my ($self) = @_;

            return
                'This is a very simple app.<p>' .
                # Display the persistent data...
                "My current count is $self->{count}<p>" .
                # Display the sub-panel...
                $self->panel('basket')->display . '<p>' .
                # Display a button that will generate an event...
                $self->event_button(label => 'Add 1', name => 'add'); 
        }

        1;

        ---------------

      in Basket.pm:

        package Basket;
        use base qw(CGI::Panel);

        sub display {
            'I have the potential to be a shopping basket one day'
        }
        1;

        ---------------

DESCRIPTION
    * Please note that the subclass CGI::Panel::MainPanel has now been
    deprecated to make using the module easier. Please change any code which
    uses the module so that the main panel sub-classes CGI::Panel just like
    the other panels. *

    CGI::Panel allows applications to be built out of simple object-based
    components. It'll handle the state of your data and objects so you can
    write a web application just like a desktop app. You can forget about
    the http requests and responses, whether we're getting or posting, and
    all that stuff because that is all handled for you leaving to you
    interact with a simple API.

    An application is constructed from a set of 'panels', each of which can
    contain other panels. The panels are managed behind the scenes as
    persistent objects. See the sample applications for examples of how
    complex object-based applications can be built from simple encapsulated
    components. To try the demo app, copy the contents of the 'demo'
    directory to a cgi-bin directory.

    CGI::Panel allows you to design the logic of your application in an
    event-driven manner. That is, you set up your application the way you
    want it, with special buttons and links that trigger 'events'. The
    application then sits back and when an event is triggered, the code
    associated with that event is run. The code that responds to an event
    goes in the same class as the code that generates the event button or
    link, making the code more readable and maintainable. If the event code
    changes the state of any of the panels, the panels will then stay in the
    new state, until their state is changed again.

    Each panel is encapsulated not only in terms of the code, but in terms
    of the form data that is passed through. For example a panel class can
    be defined which has a textfield called 'name'. Three instances of this
    panel can then exist simultaneously and each will get the correct value
    of the 'name' parameter when they read their parameters (see the
    'local_params' method).

    Until the software reaches version 1.00 it will be considered beta
    software. You should be able to use it in production code, however I
    strongly recommend that you 'stabilise' your version of the module if
    you release any code that uses it. By this I mean that, once you've
    tested your app thoroughly, you rename CGI::Panel as, for example
    App::CGIPanel and inherit from this, then include this with your other
    panels. This will protect you from any changes in the interface. I'm not
    planning to make many changes, however one thing I'm considering is
    making the events objects instead of hashes.

    Please let me know by email if you're using the module. I'll then inform
    you when there's an update.

USAGE
    See 'SYNOPSIS'

BUGS
SUPPORT
AUTHOR
            Robert J. Symes
            CPAN ID: RSYMES
            rob@robsymes.com

COPYRIGHT
    Copyright (c) 2002 Robert J. Symes. All rights reserved. This program is
    free software; you can redistribute it and/or modify it under the same
    terms as Perl itself.

    The full text of the license can be found in the LICENSE file included
    with this module.

SEE ALSO
    perl(1).

PUBLIC METHODS
    Each public function/method is described here. These are how you should
    interact with this module.

  new

    Creates a new panel object

    Use:

        my $panel = new Panel;

  init

    Initialises a panel object. This should be used to add panels to the
    current panel. We provide a default method here which can be overridden.

    Example:

        sub init {
            my ($self) = @_;

            $self->add_panel('first_panel',  App::Panel::First);
            $self->add_panel('second_panel', App::Panel::Second);
        }

  parent

    Get or set the parent of the panel object.

    Examples: my $parent = $self->parent; $self->parent($other_panel);

  state

    This method is provided for convenience. Get or set the state. (Simple
    accessor for $self->{_state})

    Examples: my $state = $self->state; $self->state('STATE1');

  get_session_id

    Gets the session id for the application

    Note: It's essential that all panels are added using the proper
    add_panel routine for this routine to work correctly.

    Example:

        my $id = $self->get_session_id;

  panel

    Retrieves a sub-panel by name

    Example:

        my $first_panel = $self->panel('first_panel');

  get_panels

    Retrieves the set of panels as a hash

    Example:

        my %panels = $self->get_panels;

  get_id

    Gets the id of the panel If one is not currently stored, we generate a
    new one with help from the main panel. This method can be overridden if
    you want to give a unique name to a panel.

    Examples:

        sub get_id { 'unique_name' }
    or
        my $id = $self->get_id;

    and later...

        $self->get_panel_by_id('unique_name');
    or
        $self->get_panel_by_id($id);

    See documentation of get_panel_by_id for more details. (Of course, you
    can also just use this get_id to get the auto-generated id and use that
    later in get_panel_by_id.)

  main_panel

    Get the main panel (by recursing up the panel tree) Eventually this will
    reach a panel without a parent, which we will assume to be the main
    panel.

    Example:

        my $main_panel = $self->main_panel;

  add_panel

    Adds a panel to the current panel in a way that maintains referential
    integrity, ie the child panel's parent value will be set to the current
    panel. All panels should be added to their parents using this routine to
    keep referential integrity and allow certain other mechanisms to work.
    Specify the name to refer to the panel by and the panel object.

    Example:

        $self->add_panel('first_panel', new App::Panel::First);

  remove_panels

    Remove all the panels from the current panel.

    Example:

        $self->remove_panels;

  local_params

    Get the parameter list for the current panel. This fetches the parameter
    list and returns the parameters that are relevant to the current panel.
    This allows each panel to be written in isolation. Two panels may have
    input controls (textboxes etc) with the same name and they can each
    retrieve the value of that input from their %local_params hash.

    eg

        my %local_params = $self->local_params
        my $name = $local_params{name};

  event_button

    Display a button which when pressed re-cycles the application and
    generates an event to be handled by the next incarnation of the
    application. The name of the routine that will be called will have
    _event_ prepended. This is partly for aesthesic reasons but mainly for
    security, to stop a wily hacker from calling any routine by changing
    what is passed through the browser. We'll probably be encrypting what is
    passed through in a later version.

      Input:
        label:       Caption to display on button
        name:        Name of the event
        routine:     Name of the event routine to call
                     (defaults to name value if not specified)
                     ('_event_' is prepended to the routine name)
        other_tags:  Other tags for the html item
      eg:
        $shop->event_button(label      => 'Add Item',
                            name       => 'add',
                            routine    => 'add',
                            other_tags => {
                                class => 'myclass'
                            });

  event_link

    Display a link (which can be an image link) which when pressed re-cycles
    the application and generates an event to be handled by the next
    incarnation of the application.

      Input:
        label:       Caption to display on link
         * OR *
        img:         Image to display as link

        name:        Name of the event
        routine:     Name of the event routine to call
                     (defaults to name value if not specified)
                     ('_event_' is prepended to the routine name)
        other_tags:  Other tags for the html item
        img_tags:    Other tags for the image (if the link is an image)

      eg:
        $shop->event_link(label => 'Add Item',
                          name  => 'add',
                          other_tags => {
                              width => 20
                          })

  CGI input functions

    The CGI input functions are available here with local_ prepended so the
    name can be made panel-specific, and they can be called as a method. The
    same effect can be achieved by using the get_localised_name function for
    the name of the parameter.

    Example:

        $self->local_textfield({name => 'testinput', size => 40})

    is equivalent to:

        my $cgi = new CGI;
        $cgi->textfield({name => $self->get_localised_name('testinput'), size => 40})

    Using these methods means that the panel will have exclusive access to
    the named input parameter. So to obtain the value of the input parameter
    above, we would write the following:

        my %local_params = $self->local_params;
        my $test_input_value = $local_params{'testinput'};

    Note that with this techique, several parameters could have input
    controls with the same name and they will each receive the correct
    value. This is especially useful for sets of panels of the same class.

  get_localised_name

    Return a name that has the panel id encoded into it. This is used by the
    local_... functions and can be used to build a custom html input control
    that will deliver its value when the panel's local_params method is
    called.

    Example:

        $output .= $cgi->textfield({name => $self->get_localised_name('sometext')});

    The equivalent could be done by calling:

        $output .= $self->local_textfield({name => 'sometext'});

  local_textfield

    Generate a localised textfield

    Example:

        $output .= $self->local_textfield({name => 'sometext'});

  MAIN PANEL METHODS

    These methods provide extra functionality useful for the main panel of
    an application. Apache::Session is used to handle session information.
    An application built using the CGI::Panel framework should typically
    have one main panel and a hierarchy of other panels, all of which
    inherit from CGI::Panel.

  obtain

    Obtains the master panel object

    This will either restore the current master panel session or create a
    new one

    Use:

        my $shop = obtain Shop;

  cycle

    Performs a complete cycle of the application

    Takes all the actions that are required for a complete cycle of the
    application, including processing events and form data and displaying
    the updated screen. Also manages persistence for the panel hierarchy.

    Use:

        $shop->cycle();

  save

    Saves an object to persistent storage indexed by session id

    Use:

        $self->save;

  get_panel_by_id

    Look up the panel in our list and return it. Note that this is different
    to the 'panel' routine in CGI::Panel, which gets a sub-panel of the
    current panel by name. All the panels in an application will be
    registered with the main panel which stores them in a special hash with
    an automatically generated key. This routine gets any panel in the
    application based on the key supplied.

    Use:

        my $panel_id = $main_panel->get_panel_by_id(3);

OTHER METHODS
    The following methods are used behind the scenes, usually from the
    'cycle' method above. They will generally be sufficient as they are but
    can be overridden if necessary for greater flexibility.

  register_panel

    Accept a panel object and 'register' it - ie store a reference to it in
    a special list. Return the id (hash key) to the caller.

    Use:

        my $id = $main_panel->register($panel);

  screen_main

    Display main screen for the master panel. This is called automatically
    by the 'cycle' routine. Other screen methods can be defined if
    necessary, however judicious use of panels should avoid the need for
    this.

  handle_event

    Handle a button event by passing the event information to the
    appropriate event routine of the correct panel. Currently this is always
    the panel that generates the event.

  handle_link_event

    Handle a link event by passing the event information to the appropriate
    event routine of the correct panel. Currently this is always the panel
    that generates the event.

  interpret_messages

    Read the request information using the CGI module and present this data
    in a more structured way. In particular this detects events and decodes
    the information associated with them.

  session_directory

    This method returns the name of the directory that is used to store the
    session files. It's currently set to '/tmp'. Override this method to
    return a different directory if desired.

  lock_directory

    This method returns the name of the directory that is used to store the
    lock files. It's currently set to '/tmp'. Override this method to return
    a different directory if desired.