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.
The id attribute
POE::XUL requires each node to have a unique identifier. If you do not set the id
attribute of an node, it will assigned one. A node's id
attribute must be globally to the application, including across windows in the same application. This is contrary to how the DOM works, where elements in different windows may share an id, may even not have one.
Use <POE::XUL::Window/getElementById> to find a node by its id
.
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' );
Style
An element's style property is implemented by a POE::XUL::Style object, which allows DOM-like manipulation of the element's style declaration.
my $button = Button( style=>'color: red' );
$button->style->color( 'puce' );
XUL-Node API vs. the XUL DOM
The XUL-Node API is different in the following ways:
Booleans are Perl booleans, not
true
andfalse
.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
).You currently can not move nodes around in the DOM.
my $node = $parent->getChild( 3 ); my $new_node = Description( content => $node ); $parent->removeChild( 3 ); $parent->appendChild( $new_node ); # FAIL!
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
Creates and populates a POE::XUL::TextNode. Returns the new node.
my $tn = window->createTextNode( 'Some text' );
textNode
Sets or changes the text of a node, such as description. If the node has multiple children (aka <i>mixed-mode</i>) then it will replace the first textNode it finds. If there are none, it will append a new text node. See POE::XUL::TextNode.
my $d = Description( textNode => 'Hello world!' );
$d->textNode( 'This is different' );
children
Find a given node's child nodes. Returns array in array context, an array reference in scalar context. Modifying the arrayref will NOT modify the node's list of children.
foreach my $node ( $box->children ) {
# ...
}
child_count
Returns the number of child nodes of an node.
hasChildNodes
Returns true if a node has child nodes.
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 );
Use <POE::XUL::Window/getElementById> to find a node by its id
.
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 that even if you manipulate $hashref
directly, changes will not be mirrored in the 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 does the following:
$node->style->display( 'none' );
show
$node->show;
Syntatic sugar that does the following:
$node->style->display( '' );
attach
$node->attach( $Event => $listener );
$node->attach( $Event => $coderef );
$node->attach( $Event );
Attaches an event listener to a node. When $Event
happens (normaly in response to a DOM event) the $poe_event
is posted to the application session. Alternatively, the $coderef
is called. In both cases, an POE::XUL::Event object is passed as the first parameter. $poe_event
defaults to $Event
.
attach()
will auto-create handlers for POE::XUL::Application
.
detach
$node->detach( $Event );
Removes the event listener for $Event
. Auto-created handlers are currently not removed.
event
my $listener = $node->event( $Event );
Gets the node's event listener for $Event
. A listener is either a coderef, or the name of a POE event handler in the application's session. Application code will rarely need to call this method.
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
Some XUL properties are implemented with XBL. The front-end attempts to wait for the XBL to be created before setting the property. If the object takes too long, the attribute is set instead.
What this means is that you can't reliably set the properties of freshly created nodes.
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-2009 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.