Windows and Dialogs
A running SiteFusion application always has at least one window open. This root window is an object of the class XULWindow and is opened automatically and made available through the
Application::$window property. To influence the characteristics of this root window, you can set some properties in the Application class definition:
- Application::$alwaysLowered - boolean indicating whether the window should always be under the other windows. Defaults to FALSE.
- Application::$alwaysRaised - boolean indicating whether the window should always be on top of the other windows. Defaults to FALSE.
- Application::$centerscreen - set to TRUE to have the window open in the center of the screen. Defaults to FALSE.
- Application::$resizable - whether the user should be able to resize the window. Defaults to TRUE.
- Application::$width - default width of the window (integer). Defaults to NULL, which makes the window autosize to its contents. Note that both width and height need to be set to force a size.
- Application::$height - default height of the window (integer). Defaults to NULL, which makes the window autosize to its contents. Note
that both width and height need to be set to force a size.
The properties
Application::$alwaysLowered and
Application::$alwaysRaised might not always result in the desired behavior, this seems to be dependent on the platform specific implementation of XULRunner.
In an empty application, the root window is the only registered node. Any nodes added as its children will appear inside it, as demonstrated in earlier tutorials. Windows in XUL and SiteFusion are just another kind of nodes. In the case of windows, being registered (e.g. becoming a child of another node) makes them open and initialize. Likewise, when windows are closed, either by the user or by the server process, the node is unregistered and removed from its parent childset. Window classes, like the Application class, have an
init() function that is called when the window has been created on the client side. The default class provides a simple init function, but when writing extending classes, this is the function to override and use to construct the inner content of the window.
Other windows
SiteFusion distinguishes between two additional types of windows:
XULChildWindow and
XULDialog. They both behave largely the same way, but may be rendered differently depending on the platform. XULDialog extends XULChildWindow, so all options available to XULChildWindow also apply to XULDialog. Additionally, a dialog will display a set of buttons on the bottom (accept and cancel buttons by default), which are bound to specific events enabling you to react to those buttons appropriately. A dialog is mostly used to gather information from the user when requested by another part of the application, while a child window often represents a more independent part of an application. Dialogs and child windows can be constructed inline, or extended by a new class implementing the specific desired functionality of that window. Like the root window, the childwindow and thereby its extending class supports several options that can be set on the object or class definition:
- XULChildWindow::$alwaysLowered - boolean indicating whether the window/dialog should always be under the other windows. Defaults to FALSE.
- XULChildWindow::$alwaysRaised - boolean indicating whether the window/dialog should always be on top of the other windows. Defaults to FALSE.
- XULChildWindow::$centerscreen - set to TRUE to have the window/dialog open in the center of the screen, or FALSE to have it open on a position relative to its parent window. Defaults to TRUE.
- XULChildWindow::$dependent - set to TRUE to make the window/dialog dependent on its parent window. That means that if the parent window moves, the child moves with it. Defaults to TRUE.
- XULChildWindow::$dialog - determines whether the look of the window should match a native dialog. Defaults to FALSE for child windows and to TRUE for dialogs.
- XULChildWindow::$modal - a modal window/dialog prevents interaction with other windows until it is closed. This is useful if the application needs a certain task cleared or an answer supplied before it can continue. Defaults to FALSE.
- XULChildWindow::$resizable - set to TRUE to enable resizing of the window/dialog. Defaults to TRUE for child windows and to FALSE for dialogs.
- XULChildWindow::$title - set the title of the window/dialog (string)
The size of these windows can be set through the
XULBasicWindow::size() method.
Inline construction
When constructing a dialog or child window inline, behavior is much like any other node:
<?php
function authorizeLogin( $args, $user, $pass ) {
return TRUE;
}
function getApplication( $args ) {
return 'SFDialogDemo';
}
class SFDialogDemo extends Application
{
public function init( $event ) {
$this->window->addChild(
$btDialog = new XULButton( 'Open Dialog' ),
$btChildWindow = new XULButton( 'Open Window' )
);
$btDialog->setEventHandler( 'command', $this, 'openDialog' );
$btChildWindow->setEventHandler( 'command', $this,
'openChildWindow' );
}
public function openDialog( $event ) {
$this->window->addChild(
$dialog = new XULDialog( 'Nice Dialog',
new XULLabel( 'This is a nice dialog indeed' )
)
);
}
public function openChildWindow( $event ) {
$this->window->addChild(
$cwin = new XULChildWindow( 'Some Window',
new XULLabel( 'Hi there' )
)
);
}
}
This method of construction is most suitable for small, relatively unimportant dialogs and windows. It allows you to put together the contents of the window on the fly.
Note: Unlike other nodes, child
nodes added to a dialog or childwindow node right after or during their
construction, as in the above example, are not registered until the next
event cycle. This is because windows need to send an 'initialized'
event before their childnodes can be registered. Childnode methods that
require a node to be registered (like Node::setAttribute() or
Node::setEvent()) can be called from an event handler for this event.
<?php
function authorizeLogin( $args, $user, $pass ) {
return TRUE;
}
function getApplication( $args ) {
return 'SFDialogEventExample';
}
class SFDialogEventExample extends Application
{
public function init( $event ) {
$this->window->addChild(
$dialog = new XULDialog( 'My Dialog',
$checkbox = new XULCheckBox( 'Check me' )
)
);
$dialog->checkbox = $checkbox;
$dialog->setEventHandler( 'initialized',
$this, 'initDialog' );
}
public function initDialog( $e ) {
$e->sourceObject->checkbox->setEvent( 'command', MSG_SEND,
$this, 'handleCheckbox', $e->sourceObject->checkbox );
}
public function handleCheckbox( $e ) {
$this->window->alert(
$e->sourceObject->checked ?
"It's on!" : "It's off..."
);
}
}
Writing an extending class
If you require a little more functionality, you'll want to
write a separate class for the window or dialog. This allows you to have
a self-contained piece of code, governing both the layout and the event
handling and other functionality of the window or dialog. This also allows you to keep the rest of the application clean and keep all code directly concerning the dialog within the dialog class:
<?php
function authorizeLogin( $args, $user, $pass ) {
return TRUE;
}
function getApplication( $args ) {
return 'SFDialogClassExample';
}
class SFDialogClassExample extends Application
{
public function init( $event ) {
$this->window->addChild(
$this->textbox = new XULTextBox,
$button = new XULButton( 'Do something' )
);
$button->setEvent( 'command', MSG_SEND, $this,
'openDialog', $this->textbox );
}
public function openDialog( $event ) {
$this->window->addChild(
new DemoDialog( $this->textbox->value )
);
}
}
class DemoDialog extends XULDialog
{
public function __construct( $text ) {
$this->originalText = $text;
$this->title = 'Sure?';
}
public function init() {
$this->addChild(
new XULLabel( 'Want to edit this?' ),
$this->textbox = new XULTextBox
);
$this->textbox->value( $this->originalText );
$this->setEvent( 'accept', MSG_SEND, $this,
'onAccept', $this->textbox );
}
public function onAccept( $event ) {
$newText = $this->textbox->value();
$this->rootApplication->textbox->value( $newText );
}
}
Dialog events
Windows and dialogs fire several events which can be used to bind functionality to. Both fire the 'initialized' event, which is handled internally leading to the default init() function being called. Both also fire the 'close' event when the close button the titlebar is clicked. You can use this event to do some cleanup for example, or to prevent the window from actually closing if it is not supposed to. This is done by calling the
XULBasicWindow::preventClose() method. Dialogs fire several other events that relate to the specific system buttons that this class provides. By default, a dialog will have the OK and Cancel buttons, usually localized to the system language. These buttons fire the 'accept' and 'cancel' events respectively. The full set of buttons a XUL dialog can display and their correspondingly named events are:
- accept - the OK button
- cancel - the Cancel button
- help - a button to provide help in an operating system consistent way
- disclosure - a button to show more information. Visual representation may differ across systems
- extra1 - a generic extra button
- extra2 - a second generic extra button
Setting the buttons to be displayed is done by setting the
XULDialog::$buttons property to a comma-separated string containing any of the above button names. For example, setting $dialog->buttons = 'accept,cancel,disclosure'; will show the accept, cancel and disclosure buttons. All buttons except the extra1 and extra2 buttons have default labels, determined by the localization settings of XULRunner. These can be changed however, through the following set of methods:
Window references
All registered nodes hold references to their root and host windows. The root window is contained in the
Node::$rootWindow property. The property
Node::$hostWindow points to the window that contains the node.
<?php
function authorizeLogin( $args, $user, $pass ) {
return TRUE;
}
function getApplication( $args ) {
return 'SFWindowReferenceExample';
}
class SFWindowReferenceExample extends Application
{
public $width = 400;
public $height = 300;
public function init( $event ) {
$this->window->addChild(
new AllknowingLabel,
new DemoDialog
);
}
}
class DemoDialog extends XULDialog
{
public function init() {
$this->addChild( new AllknowingLabel );
}
}
class AllknowingLabel extends XULLabel
{
public function __construct( $label = NULL, $style = NULL ) {
parent::__construct( $label, $style );
$this->setEventHandler( 'onAfterAttach', $this, 'setLabel' );
}
public function setLabel( $event ) {
if( $this->hostWindow === $this->rootWindow )
$this->value( "I'm in the root window" );
else
$this->value( "I'm in another window" );
}
}
Although not required, it is good practice to always have windows be the parents of others windows. Adding a window node to a non-window node's child collection will work, but if the node is removed, the window is closed. When it comes to dependent windows (usually dialogs), you'll usually want them to close when their parent window closes. Independent child windows can be added to the root window to keep them open as long as the application runs.