NAME

POE::XUL::Node - XUL element

SYNOPSIS

use POE::XUL::Node;

# Flexible way of creating an element
my $box = POE::XUL::Node->new( tag => 'HBox', 
                               Description( "Something" ),
                               class => 'css-class',
                               style => $css,
                               Click => $poe_event  
                             );

# DWIM way
$window = Window(                            # window with a header,
   HTML_H1(textNode => 'a heading'),         # a label, and a button
   $label = Label(FILL, value => 'a label'),
   Button(label => 'a button'),
);

# attributes
$window->width( 800 );
$window->height( 600 );

$label->value('a value');
$label->style('color:red');
print $label->flex;

# compositing
print $window->child_count;                  # prints 2
$window->Label(value => 'another label');    # add a label to window
$window->appendChild(Label);                 # same but takes child as param
$button = $window->get_child(1);             # navigate the widget tree
$window->add_child(Label, 0);                # add a child at an index

# events
$window->Button(Click => sub { $label->value('clicked!') });
$window->MenuList(
   MenuPopup(map { MenuItem( label => "item #$_", ) } 1..10 ),
   Select => sub { $label->value( $_[0]->selectedIndex ) },
);

# disposing
$window->removeChild($button);                # remove child widget
$window->remove_child(1);                     # remove child by index

DESCRIPTION

POE::XUL::Node is a DOM-like object that encapsulates a XUL element. It uses POE::XUL::ChangeManager to make sure all changes are mirrored in the browser's DOM.

Elements

To create a UI, an application must create a Window with some elements in it. Elements are created by calling a function or method named after their tag:

$button = Button;                           # orphan button with no label
$box->Button;                               # another, but added to a box
$widget = POE::XUL::Node->new(tag => $tag); # using dynamic tag

After creating a widget, you must add it to a parent. The widget will show when there is a containment path between it and a window. There are multiple ways to set an elements parent:

$parent->appendChild($button);              # DOM-like
$parent->replaceChild( $old, $new );        # DOM-like
$parent->add_child($button);                # left over from XUL-Node
$parent->add_child($button, 1);             # at an index
$parent->Button(label => 'hi!');            # create and add in one shot
$parent = Box(style => 'color:red', $label);# add in parent constructor

Elements can be removed from the document by removing them from their parent:

$parent->removeChild($button);           # DOM-like
$parent->remove_child(0);                 # index
$parent->replaceChild( $old, $new );        # DOM-like

Elements have attributes. These can be set in the constructor, or via a method of the same name:

my $button = Button( value => 'one button' );
$button->value('a button');
print $button->value;                       # prints 'a button'

You can configure all attributes, event handlers, and children of a element, in the constructor. There are also constants for commonly used attributes. This allows for some nice code:

Window( SIZE_TO_CONTENT,
   Grid( FLEX,
      Columns( Column(FLEX), Column(FLEX) ),
      Rows(
         Row(
            Button( label => "cell 1", Click => $poe_event ),
            Button( label => "cell 2", Click => $poe_event ),
         ),
         Row(
            Button( label => "cell 3", Click => $poe_event ),
            Button( label => "cell 4", Click => $poe_event ),
         ),
      ),
   ),
);

Check out the XUL references (http://developer.mozilla.org/en/docs/XUL) for an explanation of available elements and their attributes.

Events are removed with the "detach" method:

$button->detach( 'Click' );

Events

Elements receive events from their client halves, and pass them on to attached listeners in the application. You attach a listener to a widget so:

# listening to existing widget
$textbox->attach( Change => sub { print 'clicked!' } );

# listening to widget in constructor
TextBox( Change => $poe_event );

You attach events by providing an event name and a listener. Possible event names are Click, Change, Select, and Pick. Different widgets fire different events. These are listed in POE::XUL::Event.

Listener are either the name of a POE event, or a callbacks that receives a single argument: the event object (POE::XUL::Event). POE events are called on the application session, NOT the current session when an event is defined. If you want to post to another session, use "callback" in POE::Session.

You can query the Event object for information about the event: name, source, and depending on the event type: checked, value, color, and selectedIndex.

Here is an example of listening to the Select event of a list box:

Window(
   VBox(FILL,
      $label = Label(value => 'select item from list'),
      ListBox(FILL, selectedIndex => 2,
         (map { ListItem(label => "item #$_") } 1..10),
         Select => sub {
            $label->value
               ("selected item #${\( shift->selectedIndex + 1 )}");
         },
      ),
   ),
);

Events are removed with the "detach" method:

$button->detach( 'Click' );

XUL-Node API vs. the Javascript XUL API

The XUL-Node API is different in the following ways:

  • Booleans are Perl booleans.

  • All nodes must have an id attribute. If you do not specify one, it will be automatically generated by POE::XUL::Node.

  • There is little difference between attributes, properties, and methods. They are all attributes on the POE::XUL::Node object. However, the javascript client library handles them differently.

    This means that to call a method or a property, you have to specify at least one parameter:

    $node->blur( 0 );           # Equiv to node.blur() in JS
  • While all attribute and properties are mirrored from the Perl object to the DOM object, only a select few are mirrored back (value, selected, selectedIndex).

  • There exist constants for common attribute key/value pairs. See POE::XUL::Node.

ELEMENT CONSTRUCTORS

To make life funner, a bunch of constructor functions have been defined for the most commonly used elements. These functions are exported into any package that uses POE::XUL::Node.

XUL Elements

ArrowScrollBox, Box, Button, Caption, CheckBox, ColorPicker, Column, Columns, Deck, Description, Grid, Grippy, GroupBox, HBox, Image, Label, ListBox, ListCell, ListCol, ListCols, ListHead, ListHeader, ListItem, Menu, MenuBar, MenuItem, MenuList, MenuPopup, MenuSeparator, ProgressMeter, Radio, RadioGroup, Row, Rows, Seperator, Spacer, Splitter, Stack, StatusBar, StatusBarPanel, Tab, TabBox, TabPanel, TabPanels, Tabs, TextBox, ToolBar, ToolBarButton, ToolBarSeperator, ToolBox, VBox, Window.

It is of course possible to create any other XUL element with:

POE::XUL::Node->new( tag => $tag );

HTML Elements

HTML_Pre, HTML_H1, HTML_H2, HTML_H3, HTML_H4, HTML_A, HTML_Div, HTML_Br, HTML_Span.

It is of course possible to create any other HTML element with:

POE::XUL::Node->new( tag => "html:$tag" );

SPECIAL ELEMENTS

There are 4 special elements:

Script

Script( $JS );

Creates a script element, with type="text/javascript", and a single POE::XUL::CDATA child. The client library will eval() the script.

Boot

Boot( $text );

Sends the boot command to the client library. Currently, the client library calls $status.title( $text );, if the $status object exists. Your application must create $status.

RawCmd

RawCmd( \@cmd );

Allows you to send a raw command to the Javascript client library. Use at your own risk.

pxInstructions

pxInstructions( @instructions );

Send instructions to the ChangeManager. This is a slightly higher-level form of "RawCmd". Its presence indicates the immaturity of POE::XUL as a whole. These instructions are subject to change/removal in the future.

@instructions is an array instructions for the ChangeManager. See "instrction" in POE::XUL::ChangeManager for details.

METHODS

createTextNode =head2 textNode

children =head2 child_count =head2 hasChildNodes

add_child

$parent->add_child( $node, $index );

appendChild

$parent->appendChild( $node );

firstChild / first_child

my $node = $parent->firstChild;

get_child

my $node = $parent->get_child( $index );

getItemAtIndex / get_item

my $node = $menu->getItemAtIndex( $index );

Like "get_child", but works for menulist and menupopup.

lastChild / last_child

my $node = $parent->lastChild;

removeChild / remove_child

$parent->removeChild( $node );
$parent->removeChild( $index );

replaceChild

$parent->replaceChild( $old, $new );

attributes

my %hash = $node->attributes;
my $hashref = $node->attributes;

Note even if you manipulate $hashref directly, changes will not be mirrored in the DOM node.

getAttribute / get_attribute

my $value = $node->getAttribute( $name );

setAttribute / set_attribute

$node->setAttribute( $name => $value );

removeAttribute / remove_attribute

$node->removeAttribute( $name );

hide

$node->hide;

Syntatic sugar that adds display: none to the style attribute.

show

$node->show;

Syntatic sugar that removes display: none from the style attribute.

close

Close a sub-window. Obviously may only be called on a Window element.

attach

$node->attach( $Event => $poe_event );

detach

$node->detach( $Event );

event

my $listener = $node->event( $Event );

dispose / distroy

Calls dispose on all the child nodes, and drops all events.

as_xml

Returns this element and all its child elements as an unindented XML string. Useful for debuging.

LIMITATIONS

  • Some elements are not supported yet: tree, popup.

  • Some DOM features are not supported yet:

    * multiple selections
    * node disposal
    * color picker will not fire events if type is set to button
    * equalsize attribute will not work
    * menus with no popups may not show

SEE ALSO

POE::XUL. POE::XUL::Event presents the list of all possible events.

http://developer.mozilla.org/en/docs/XUL has a good XUL reference.

AUTHOR

Philip Gwyn <gwyn-at-cpan.org>

CREDITS

Based on work by Ran Eilam.

COPYRIGHT AND LICENSE

Copyright 2007 by Philip Gwyn. All rights reserved;

Copyright 2003-2004 Ran Eilam. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.