# This example shows how to create events, with a bit of # DOM calesthenics thrown in. # Refer also to the Minilla, Signals, and Elements examples. # # $CVSHeader: Mozilla-DOM/examples/Events.pm,v 1.5 2007-06-06 21:46:56 slanning Exp $ package Events; use strict; use warnings; use Cwd 'getcwd'; use Glib qw(TRUE FALSE); use Gtk2; use Gtk2::MozEmbed '0.04'; use Mozilla::DOM '0.17'; # for exporting :phases #use Mozilla::DOM::Event qw(:phases); # XXX: need to add examples #use Mozilla::DOM::KeyEvent qw(:keycodes); #use Mozilla::DOM::MutationEvent qw(:changes); use Glib::Object::Subclass Gtk2::Window::; sub INIT_INSTANCE { my $self = shift; my $embed = Gtk2::MozEmbed->new(); $self->add($embed); $embed->signal_connect(net_stop => \&net_stop_cb); $embed->signal_connect(dom_mouse_click => \&click_cb); $embed->signal_connect(dom_key_press => \&press_cb); # XXX: there's got to be a way to refer to a file # relative to the cwd using a file:// URI, isn't there? my $cwd = getcwd(); $embed->load_url("file://$cwd/index.html"); $self->{_embed} = $embed; $self->{_lock} = {}; } sub net_stop_cb { my $embed = shift; my $click = _create_event($embed, 'MouseEvent', 'click'); my $button = _get_input($embed, 'button'); _do_event($click, $button); } sub click_cb { my ($embed, $event) = @_; # Prevent infinite recursion, since we dispatch click # events from within the click handler return FALSE if _locked($embed, $event); # Click the radio buttons # XXX: this only displays the last one clicked; # and sleeping between events just makes it wait to display. # Also, clicking on the buttons manually doesn't refresh the # selected one. Can you refresh the Gtk2::Window? # Duhrr, wait a minute.. If I click on a button, # then click_cb gets called.. so... # I should be doing this stuff in the press_cb. my $click = _create_event($embed, 'MouseEvent', 'click'); foreach my $i (0 .. 2) { my $radio = _get_input($embed, 'radio', $i); _do_event($click, $radio); } # Type a random character into the text field my $charcode = int(rand(26)) + ord('a'); my $press = _create_event($embed, 'KeyEvent', 'keypress', $charcode); my $textbox = _get_input($embed, 'text'); _do_event($press, $textbox); # See the documentation for Mozilla::DOM::Event InitEvent # for more events you can create. _unlocked($embed, $event); return FALSE; # I'm not sure this actually does anything... } sub press_cb { my ($embed, $event) = @_; # Prevent infinite recursion if we dispatch keypress # events from within the keypress handler return FALSE if _locked($embed, $event); # Click the 1st option in the select menu # (XXX: doesn't seem to work.. Maybe you have to just # change the 'selected' attributes? # "Select boxes are more difficult. A click event on select boxes # or options turns out not to work in all browsers, so I opted for # the traditional change event on the select box itself." # Is this relevant? # change # A control loses the input focus and its value has been modified # since gaining focus. This event can occur either via a user interface # manipulation or the focus() methods and the attributes defined in # [DOM Level 2 HTML]. This event is valid for INPUT, SELECT, and # TEXTAREA element.) my $click = _create_event($embed, 'MouseEvent', 'click'); my $out = _create_event($embed, 'MouseEvent', 'mouseout'); my $over = _create_event($embed, 'MouseEvent', 'mouseover'); my ($select, $option1) = _get_select_option($embed, 'list', 0); (undef, my $option2) = _get_select_option($embed, 'list', 1); # _do_event($click, $option2); # initially selected item # _do_event($out, $option2); # _do_event($over, $option1); _do_event($click, $select); _do_event($click, $option1); _unlocked($embed, $event); return FALSE; # I'm not sure this actually does anything... } # Private functions - probably'd want to subclass Gtk2::MozEmbed, etc., # in a real app sub _create_event { my ($embed, $class, $type, $charcode) = @_; my $doc = _get_document($embed); # You can see if the DOM implementation supports # a particular interface, though I don't trust what it says # my $impl = $doc->GetImplementation; # foreach my $feature (qw(Views MouseEvents KeyEvents UIEvents Events)) { # print "Does", # ($impl->HasFeature($feature, '2.0') ? '' : ' not'), # " support $feature\n"; # } # Create an event # First call the GetIID class method to get an ID. # Then extract the DocumentEvent interface from the Document # by passing the ID to QueryInterface. Finally, create a # generic event from it. my $iid = Mozilla::DOM::DocumentEvent->GetIID(); my $docevent = $doc->QueryInterface($iid); my $event = $docevent->CreateEvent($class . 's'); if ($class eq 'MouseEvent') { # Initialize the MouseEvent ('click') $event->InitEvent($type, 1, 1); return $event; } elsif ($class eq 'KeyEvent') { # 'keypress' events are more complicated because # you have to give a character to press. So we have to switch # its interface to KeyEvent to call its InitKeyEvent method # rather than just initializing it as a generic Event. my $kiid = Mozilla::DOM::KeyEvent->GetIID(); my $keyevent = $event->QueryInterface($kiid); $keyevent->InitKeyEvent($type, 1, 1, 0, 0, 0, 0, 0, $charcode); return $keyevent; } else { die "Unknown event class '$class'\n"; } } # If we wanted the 3rd button (), # $type eq 'button' and $num == 2. # Returns the input element node. sub _get_input { my ($embed, $type, $num) = @_; $num = 0 unless defined $num; my @nodes = (); # Get all elements my $doc = _get_document($embed); my $docelem = $doc->GetDocumentElement; my $inputs = $docelem->GetElementsByTagName('input'); # Find inputs whose 'type' attribute eq $type # and put them in @nodes INPUT: foreach my $i (0 .. $inputs->GetLength - 1) { my $input = $inputs->Item($i); my $attrs = $input->GetAttributes; ATTR: foreach my $a (0 .. $attrs->GetLength - 1) { my $attr = $attrs->Item($a); next ATTR unless $attr->GetNodeName =~ /^type$/i; if ($attr->GetNodeValue =~ /^$type$/i) { push @nodes, $input; next INPUT; } } } # This could easily be made to return multiple inputs, instead if (@nodes) { if (exists $nodes[$num]) { return $nodes[$num]; } else { die "not enough $type inputs!\n"; } } else { die "no inputs of type=$type\n"; } } # If we wanted the 3rd option of a elements my $doc = _get_document($embed); my $docelem = $doc->GetDocumentElement; my $selects = $docelem->GetElementsByTagName('select'); # Find select whose name attribute matches $name my $select = undef; SELECT: foreach my $i (0 .. $selects->GetLength - 1) { my $input = $selects->Item($i); my $attrs = $input->GetAttributes; ATTR: foreach my $a (0 .. $attrs->GetLength - 1) { my $attr = $attrs->Item($a); next ATTR unless $attr->GetNodeName =~ /^name$/i; if ($attr->GetNodeValue =~ /^$name$/i) { $select = $input; last SELECT; } } } die "select with name=$name not found\n" unless defined $select; # Find option number $num my $kids = $select->GetChildNodes; my $option = 0; foreach my $k (0 .. $kids->GetLength - 1) { my $kid = $kids->Item($k); # Children could be text nodes, etc., so make sure it's an