| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package WWW::Scripter::Plugin::JavaScript; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 5 |  |  | 5 |  | 227797 | use strict;   # :-( | 
|  | 5 |  |  |  |  | 12 |  | 
|  | 5 |  |  |  |  | 185 |  | 
| 4 | 5 |  |  | 5 |  | 27 | use warnings; # :-( | 
|  | 5 |  |  |  |  | 9 |  | 
|  | 5 |  |  |  |  | 173 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 5 |  |  | 5 |  | 904 | use Encode 'decode_utf8'; | 
|  | 5 |  |  |  |  | 11454 |  | 
|  | 5 |  |  |  |  | 395 |  | 
| 7 | 5 |  |  | 5 |  | 997 | use LWP'UserAgent 5.815; | 
|  | 5 |  |  |  |  | 58299 |  | 
|  | 5 |  |  |  |  | 161 |  | 
| 8 | 5 |  |  | 5 |  | 36 | use Scalar::Util qw'weaken'; | 
|  | 5 |  |  |  |  | 11 |  | 
|  | 5 |  |  |  |  | 340 |  | 
| 9 | 5 |  |  | 5 |  | 34 | use URI::Escape 'uri_unescape'; | 
|  | 5 |  |  |  |  | 9 |  | 
|  | 5 |  |  |  |  | 246 |  | 
| 10 | 5 |  |  | 5 |  | 5238 | use Hash::Util::FieldHash::Compat 'fieldhash'; | 
|  | 5 |  |  |  |  | 5036 |  | 
|  | 5 |  |  |  |  | 41 |  | 
| 11 | 5 |  |  | 5 |  | 1719 | use WWW::Scripter 0.022; # screen | 
|  | 5 |  |  |  |  | 311635 |  | 
|  | 5 |  |  |  |  | 1043 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | our $VERSION = '0.008'; | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | # Attribute constants (array indices) | 
| 16 |  |  |  |  |  |  | sub mech() { 0 } | 
| 17 |  |  |  |  |  |  | sub jsbe() { 1 } # JavaScript back-end (field hash of objects, keyed | 
| 18 |  |  |  |  |  |  | sub benm() { 2 } # Back-end name  # by document) | 
| 19 |  |  |  |  |  |  | sub init_cb() { 3 } # callback routine that's called whenever a new js | 
| 20 |  |  |  |  |  |  | # environment is created | 
| 21 |  |  |  |  |  |  | sub alert()   { 4 } | 
| 22 |  |  |  |  |  |  | sub confirm() { 5 } | 
| 23 |  |  |  |  |  |  | sub prompt()  { 6 } | 
| 24 |  |  |  |  |  |  | sub cb() { 7 } # class bindings | 
| 25 |  |  |  |  |  |  | sub tmout() { 8 } # timeouts | 
| 26 |  |  |  |  |  |  | sub f()       { 9 } # functions | 
| 27 |  |  |  |  |  |  | sub g()        { 10 } # guard objects for back ends, to destroy | 
| 28 |  |  |  |  |  |  | # them forcibly | 
| 29 |  |  |  |  |  |  |  | 
| 30 | 5 |  |  | 5 |  | 30 | {no warnings; no strict; | 
|  | 5 |  |  | 5 |  | 8 |  | 
|  | 5 |  |  |  |  | 180 |  | 
|  | 5 |  |  |  |  | 23 |  | 
|  | 5 |  |  |  |  | 8 |  | 
|  | 5 |  |  |  |  | 7749 |  | 
| 31 |  |  |  |  |  |  | undef *$_ for qw/mech jsbe benm init_cb g cb | 
| 32 |  |  |  |  |  |  | f alert confirm prompt tmout/} # These are PRIVATE constants! | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub init { | 
| 35 |  |  |  |  |  |  |  | 
| 36 | 10 |  |  | 10 | 1 | 51413 | my ($package, $mech) = @_; | 
| 37 |  |  |  |  |  |  |  | 
| 38 | 10 |  |  |  |  | 51 | my $self = bless [$mech], $package; | 
| 39 | 10 |  |  |  |  | 70 | weaken $self->[mech]; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 10 |  |  |  |  | 58 | $mech->script_handler( default => $self ); | 
| 42 | 10 |  |  |  |  | 200 | $mech->script_handler( | 
| 43 |  |  |  |  |  |  | qr/(?:^|\/)(?:x-)?(?:ecma|j(?:ava)?)script[\d.]*\z/i => $self | 
| 44 |  |  |  |  |  |  | ); | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | $mech->set_my_handler(request_preprepare => sub { | 
| 47 | 2 |  |  | 2 |  | 15012 | my($request,$mech) = @_; | 
| 48 | 2 |  |  |  |  | 10 | $self->eval( | 
| 49 | 2 |  |  |  |  | 7 | $mech, decode_utf8 uri_unescape opaque {uri $request} | 
| 50 |  |  |  |  |  |  | ); | 
| 51 | 2 | 50 |  |  |  | 222 | $@ and $mech->warn($@); | 
| 52 | 2 |  |  |  |  | 30 | WWW'Scripter'abort; | 
| 53 | 10 |  |  |  |  | 264 | }, m_scheme => 'javascript'); | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # stop closures from preventing destruction | 
| 56 | 10 |  |  |  |  | 937 | weaken $mech; | 
| 57 | 10 |  |  |  |  | 18 | my $life_raft = $self; | 
| 58 | 10 |  |  |  |  | 30 | weaken $self; | 
| 59 |  |  |  |  |  |  |  | 
| 60 | 10 |  |  |  |  | 42 | $self; | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | sub options { | 
| 64 | 6 |  |  | 6 | 0 | 38 | my $self = shift; | 
| 65 | 6 |  |  |  |  | 24 | my %opts = @_; | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 6 |  |  |  |  | 14 | my $w; | 
| 68 | 6 |  |  |  |  | 23 | for(keys %opts) { | 
| 69 | 6 | 100 |  |  |  | 30 | if($_ eq 'engine') { | 
|  |  | 50 |  |  |  |  |  | 
| 70 | 4 | 50 | 33 |  |  | 41 | if($self->[jsbe] && | 
| 71 |  |  |  |  |  |  | $self->[benm] ne $opts{$_} | 
| 72 |  |  |  |  |  |  | ) { | 
| 73 | 0 |  |  |  |  | 0 | $self->[mech]->die( | 
| 74 |  |  |  |  |  |  | "Can't set JavaScript engine to " . | 
| 75 |  |  |  |  |  |  | "'$opts{$_}' since $self->[benm] is " . | 
| 76 |  |  |  |  |  |  | "already loaded.");; | 
| 77 |  |  |  |  |  |  | } | 
| 78 | 4 |  |  |  |  | 24 | $self->[benm] = $opts{$_};; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  | elsif($_ eq 'init') { | 
| 81 | 2 |  |  |  |  | 13 | $self->[init_cb] = $opts{$_}; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  | else { | 
| 84 | 0 |  |  |  |  | 0 | $self->[mech]->die( | 
| 85 |  |  |  |  |  |  | "JavaScript plugin: Unrecognized option '$_'" | 
| 86 |  |  |  |  |  |  | ); | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  | } | 
| 89 |  |  |  |  |  |  | } | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | sub eval { | 
| 92 | 70 |  |  | 70 | 1 | 491207 | my($plugin,$mech,$code,$url,$line,$inline) = @_; | 
| 93 |  |  |  |  |  |  |  | 
| 94 | 70 | 100 |  |  |  | 435 | if( | 
| 95 |  |  |  |  |  |  | $code =~ s/^(\s*)\s*\z//; | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 70 |  |  |  |  | 289 | my $be = $plugin->back_end($mech); | 
| 103 |  |  |  |  |  |  |  | 
| 104 | 70 |  |  |  |  | 670 | $be->eval($code, $url, $line); | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | sub event2sub { | 
| 108 | 6 |  |  | 6 | 1 | 107381 | my($self,$mech,$elem,undef,$code,$url,$line) = @_; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 6 |  |  |  |  | 35 | $self-> | 
| 111 |  |  |  |  |  |  | back_end($mech)->event2sub($code,$elem,$url,$line); | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | # We have to associate each JS environment with a response object. While | 
| 115 |  |  |  |  |  |  | # writing this logic, I initially tried to use the document, but not all | 
| 116 |  |  |  |  |  |  | # URLs have documents (e.g., plain text files). | 
| 117 |  |  |  |  |  |  | sub back_end { | 
| 118 | 111 |  |  | 111 | 1 | 986 | my $self = shift; | 
| 119 | 111 | 50 |  |  |  | 471 | ref $_[0] or require Carp, Carp'cluck(); | 
| 120 | 111 |  |  |  |  | 977 | my $res = (my $w = shift)->res; | 
| 121 | 111 | 100 | 66 |  |  | 1665 | return $self->[jsbe]{$res} | 
| 122 |  |  |  |  |  |  | if ($self->[jsbe] ||= &fieldhash({}))->{$res}; | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 26 | 100 |  |  |  | 384 | if(!$self->[benm]) { | 
| 125 |  |  |  |  |  |  | # When wspjssm is stable enough, these lines can be uncommented: | 
| 126 |  |  |  |  |  |  | #	    # try this one first, since it's faster: | 
| 127 |  |  |  |  |  |  | #	    eval{require WWW::Scripter::Plugin::JavaScript::SpiderMonkey}; | 
| 128 |  |  |  |  |  |  | #	    if($@) { | 
| 129 |  |  |  |  |  |  | require | 
| 130 | 6 |  |  |  |  | 1017 | WWW::Scripter::Plugin::JavaScript::JE; | 
| 131 | 6 |  |  |  |  | 23 | $self->[benm] = 'JE' | 
| 132 |  |  |  |  |  |  | #            } | 
| 133 |  |  |  |  |  |  | #	    else { $self->[benm] = 'SpiderMonkey' }; | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  | else { | 
| 136 | 20 |  |  |  |  | 2980 | require "WWW/Scripter/Plugin/JavaScript/" . | 
| 137 |  |  |  |  |  |  | "$$self[benm].pm"; | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 | 26 |  | 66 |  |  | 311 | ($self->[g] ||= &fieldhash({}))->{$res} | 
| 141 |  |  |  |  |  |  | = new WWW'Scripter'Plugin'JavaScript'Guard | 
| 142 |  |  |  |  |  |  | my $back_end = $self->[jsbe]{$res} | 
| 143 |  |  |  |  |  |  | = "WWW::Scripter::Plugin::JavaScript::$$self[benm]" -> new( $w ); | 
| 144 | 26 |  |  |  |  | 523 | require HTML::DOM::Interface; | 
| 145 | 26 |  |  |  |  | 156 | require CSS::DOM::Interface; | 
| 146 | 26 |  |  |  |  | 87 | for ($back_end) { | 
| 147 | 26 |  |  |  |  | 227 | for my $class_info( $self->[mech]->class_info ) { | 
| 148 | 104 |  |  |  |  | 998 | $_->bind_classes($class_info) ; | 
| 149 |  |  |  |  |  |  | } | 
| 150 | 26 | 100 |  |  |  | 124 | for my $__(@{$self->[cb]||[]}){ | 
|  | 26 |  |  |  |  | 12425 |  | 
| 151 | 17 |  |  |  |  | 89 | $_->bind_classes($__) | 
| 152 |  |  |  |  |  |  | } | 
| 153 | 26 | 100 |  |  |  | 75 | for my $__(@{$self->[f]||[]}){ | 
|  | 26 |  |  |  |  | 195 |  | 
| 154 | 51 |  |  |  |  | 861 | $_->new_function(@$__) | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | } # for $back_end; | 
| 157 | 26 |  | 100 |  |  | 293 | { ($self->[init_cb]||next)->($w); } | 
|  | 26 |  |  |  |  | 125 |  | 
| 158 | 26 |  |  |  |  | 1916 | weaken $self; # closures | 
| 159 | 26 |  |  |  |  | 163 | return $back_end; | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | sub bind_classes { | 
| 163 | 5 |  |  | 5 | 1 | 37626 | my $plugin = shift; | 
| 164 | 5 |  |  |  |  | 19 | push @{$plugin->[cb]}, $_[0]; | 
|  | 5 |  |  |  |  | 21 |  | 
| 165 | 5 | 100 |  |  |  | 63 | if($plugin->[jsbe]) { | 
| 166 | 3 |  |  |  |  | 47 | $_ && $_->bind_classes($_[0]) | 
| 167 | 3 |  | 33 |  |  | 7 | for values %{ $plugin->[jsbe] }; | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  |  | 
| 171 | 4 |  |  | 4 | 1 | 2722 | sub set { shift->back_end( shift )->set(@_) } | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | sub new_function { | 
| 174 | 8 |  |  | 8 | 1 | 176142 | my $plugin = shift; | 
| 175 | 8 |  |  |  |  | 25 | push @{$plugin->[f]}, \@_; | 
|  | 8 |  |  |  |  | 36 |  | 
| 176 | 8 | 100 |  |  |  | 57 | if($plugin->[jsbe]) { | 
| 177 | 2 |  |  |  |  | 46 | $_ && $_->new_function(@_) | 
| 178 | 2 |  | 33 |  |  | 7 | for values %{ $plugin->[jsbe] }; | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | # ~~~ This is experimental. The purposed for this is that code that relies | 
| 184 |  |  |  |  |  |  | #     on a particular version of a JS back end can check to see which back | 
| 185 |  |  |  |  |  |  | #     end is being used before doing Foo->VERSION($bar). The problem with | 
| 186 |  |  |  |  |  |  | #     it is that it returns nothing unless the JS environment has already | 
| 187 |  |  |  |  |  |  | #     been loaded. If we have it start the JS engine, we may load it and | 
| 188 |  |  |  |  |  |  | #     then not use it. | 
| 189 | 0 |  |  | 0 | 1 | 0 | sub engine { shift->[benm] } | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | package WWW::Scripter::Plugin::JavaScript::Guard; | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 26 |  |  | 26 |  | 305 | sub new { bless \(my $object = pop) } | 
| 195 | 13 |  |  | 13 |  | 192982 | DESTROY { eval { ${$_[0]}->destroy } } | 
|  | 13 |  |  |  |  | 352 |  | 
|  | 13 |  |  |  |  | 129 |  | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | # ------------------ DOCS --------------------# | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | 1; | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | =head1 NAME | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | WWW::Scripter::Plugin::JavaScript - JavaScript plugin for WWW::Scripter | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | =head1 VERSION | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | Version 0.008 (alpha) | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | use WWW::Scripter; | 
| 214 |  |  |  |  |  |  | $w = new WWW::Scripter; | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | $w->use_plugin('JavaScript'); | 
| 217 |  |  |  |  |  |  | $w->get('http://www.cpan.org/'); | 
| 218 |  |  |  |  |  |  | $w->get('javascript:alert("Hello!")'); # prints Hello! | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | $w->use_plugin(JavaScript => | 
| 221 |  |  |  |  |  |  | engine  => 'SpiderMonkey', | 
| 222 |  |  |  |  |  |  | init    => \&init, # initialisation function | 
| 223 |  |  |  |  |  |  | );                         # for the JS environment | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | This module is a plugin for L that provides JavaScript | 
| 228 |  |  |  |  |  |  | capabilities (who would have guessed?). | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | To load the plugin, just use L's C method: | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | $w = new WWW::Scripter; | 
| 233 |  |  |  |  |  |  | $w->use_plugin('JavaScript'); | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | You can pass options to the plugin via the C method. It takes | 
| 236 |  |  |  |  |  |  | hash-style arguments and they are as follows: | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | =over 4 | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | =item engine | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | Which JavaScript back end to use. Currently, the only two back ends | 
| 243 |  |  |  |  |  |  | available are L, a pure-Perl JavaScript interpreter, and | 
| 244 |  |  |  |  |  |  | L (that back end is bundled | 
| 245 |  |  |  |  |  |  | separately). The SpiderMonkey back end is just a proof-of-concept as of | 
| 246 |  |  |  |  |  |  | July, 2010, but may become the default in a future version. JE is now the | 
| 247 |  |  |  |  |  |  | default. | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | If this option is | 
| 250 |  |  |  |  |  |  | not specified, either JE or SpiderMonkey will be used, whichever is | 
| 251 |  |  |  |  |  |  | available. It is possible to | 
| 252 |  |  |  |  |  |  | write one's own bindings for a particular JavaScript engine. See below, | 
| 253 |  |  |  |  |  |  | under L. | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | =item init | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | Pass to this option a reference to a subroutine and it will be run every | 
| 258 |  |  |  |  |  |  | time a new JavaScript environment is initialised. This happens after the | 
| 259 |  |  |  |  |  |  | functions above have been created. The first argument will | 
| 260 |  |  |  |  |  |  | be the WWW::Scripter object. You can use this, for instance, | 
| 261 |  |  |  |  |  |  | to make your | 
| 262 |  |  |  |  |  |  | own functions available to JavaScript. | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | =back | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | =head1 METHODS | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | L's C method will return a plugin object. The | 
| 269 |  |  |  |  |  |  | same object can be retrieved via C<< $w->plugin('JavaScript') >> after the | 
| 270 |  |  |  |  |  |  | plugin is loaded. The same plugin object is used for every page and frame, | 
| 271 |  |  |  |  |  |  | and for every new window derived from the WWW::Scripter object. The | 
| 272 |  |  |  |  |  |  | following methods can be called on that object: | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | =over 4 | 
| 275 |  |  |  |  |  |  |  | 
| 276 |  |  |  |  |  |  | =item eval | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | This evaluates the JavaScript code passed to it. The WWW::Scripter object | 
| 279 |  |  |  |  |  |  | is the first argument; the string of code the second. You can optionally | 
| 280 |  |  |  |  |  |  | pass | 
| 281 |  |  |  |  |  |  | two more arguments: the file name or URL, and the first line number. | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | This method sets C<$@> and returns C if there is an error. | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | =item set | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | Sets the named variable to the value given. The first argument is the | 
| 288 |  |  |  |  |  |  | WWW::Scripter object. The last argument is the value. The intervening | 
| 289 |  |  |  |  |  |  | arguments are the names of properties, so if you want to assign to a | 
| 290 |  |  |  |  |  |  | property of a property ... of a global property, you can pass each property | 
| 291 |  |  |  |  |  |  | name separately like this: | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | $w->plugin('JavaScript')->set( | 
| 294 |  |  |  |  |  |  | $w, 'document', 'location', 'href' => 'http://www.perl.org/' | 
| 295 |  |  |  |  |  |  | ); | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | =item new_function | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | This creates a new global JavaScript function out of a coderef. This | 
| 300 |  |  |  |  |  |  | function is added to every JavaScript environment the plugin has access to. Pass the WWW::Scripter object as the first argument, the | 
| 301 |  |  |  |  |  |  | name as | 
| 302 |  |  |  |  |  |  | the second and the code ref as the third. | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | =item bind_classes | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | Instead of using this method, you might consider L's | 
| 307 |  |  |  |  |  |  | C method, which is more general-purpose (it applies also to | 
| 308 |  |  |  |  |  |  | whatever other scripting languages might be available). | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | With this you can bind Perl classes to JavaScript, so that JavaScript can | 
| 311 |  |  |  |  |  |  | handle objects of those classes. These class bindings will persist from one | 
| 312 |  |  |  |  |  |  | page to the next. | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | You should pass a hash ref that has the | 
| 315 |  |  |  |  |  |  | structure described in L, except that this method | 
| 316 |  |  |  |  |  |  | also accepts a C<< _constructor >> hash element, which should be set to the | 
| 317 |  |  |  |  |  |  | name of the method to be called when the constructor function is called | 
| 318 |  |  |  |  |  |  | within JavaScript; e.g., C<< _constructor => 'new' >>. | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | =item back_end | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | This returns the back end corresponding to the WWW::Scripter object passed | 
| 323 |  |  |  |  |  |  | to it, creating it if necessary. This is intended mostly for back ends | 
| 324 |  |  |  |  |  |  | themselves to use, for accessing frames, etc. | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | =back | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | =head1 FEATURES AVAILABLE TO JAVASCRIPT | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | The members of the HTML DOM that are available depend on the versions of | 
| 331 |  |  |  |  |  |  | L and L installed. See L and | 
| 332 |  |  |  |  |  |  | L. | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | For a list of the properties of the window object, see | 
| 335 |  |  |  |  |  |  | L. | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | =head1 BACK ENDS | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | A back end has to be in the WWW::Scripter::Plugin::JavaScript:: name | 
| 340 |  |  |  |  |  |  | space. It will be Cd by this plugin implicitly when its name is | 
| 341 |  |  |  |  |  |  | passed to the C option. | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | The following methods must be implemented: | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | =head2 Class methods | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | =over 4 | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | =item new | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | This method is passed a window (L) | 
| 352 |  |  |  |  |  |  | object. | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | It has to create a JavaScript environment, in which the global object | 
| 355 |  |  |  |  |  |  | delegates to the window object for the members listed in | 
| 356 |  |  |  |  |  |  | L| WWW::Scripter::WindowInterface/THE C<%WindowInterface> HASH>. | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | When the window object or its frames collection (WWW::Scripter::Frames | 
| 359 |  |  |  |  |  |  | object) is passed to the JavaScript | 
| 360 |  |  |  |  |  |  | environment, the global | 
| 361 |  |  |  |  |  |  | object must be returned instead. | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | This method can optionally create C, C and C | 
| 364 |  |  |  |  |  |  | properties | 
| 365 |  |  |  |  |  |  | that refer to the global object, but this is not necessary. It might make | 
| 366 |  |  |  |  |  |  | things a little more efficient. | 
| 367 |  |  |  |  |  |  |  | 
| 368 |  |  |  |  |  |  | Finally, it has to return an object that implements the interface below. | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | The back end has to do some magic to make sure that, when the global object | 
| 371 |  |  |  |  |  |  | is passed to another JS environment, references to it automatically point | 
| 372 |  |  |  |  |  |  | to a new global object when the user (or calling code) browses to another | 
| 373 |  |  |  |  |  |  | page. | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | For instance, it could wrap up the global object in a proxy object | 
| 376 |  |  |  |  |  |  | that delegates to whichever global object corresponds to the document. | 
| 377 |  |  |  |  |  |  |  | 
| 378 |  |  |  |  |  |  | =back | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | =head2 Object Methods | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | =over 4 | 
| 383 |  |  |  |  |  |  |  | 
| 384 |  |  |  |  |  |  | =item eval | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | This should accept up to three arguments: a string of code, the file name | 
| 387 |  |  |  |  |  |  | or URL, and the first line number. | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | It must set C<$@> and return C if there is an error. | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | =item new_function | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | =item set | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | =item bind_classes | 
| 396 |  |  |  |  |  |  |  | 
| 397 |  |  |  |  |  |  | These correspond to those | 
| 398 |  |  |  |  |  |  | listed above for | 
| 399 |  |  |  |  |  |  | the plugin object. Unlike the above, though, this C is not passed a | 
| 400 |  |  |  |  |  |  | window as its first argument. Also, C and C are | 
| 401 |  |  |  |  |  |  | only expected to act on a single JavaScript environment. The plugin's own | 
| 402 |  |  |  |  |  |  | methods of the same names make sure every JavaScript environment's methods | 
| 403 |  |  |  |  |  |  | are called. | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | C must also accept a third argument, indicating the return | 
| 406 |  |  |  |  |  |  | type. This (when specified) will be the name of a JavaScript function that | 
| 407 |  |  |  |  |  |  | does the type conversion. Only 'Number' is used right now. | 
| 408 |  |  |  |  |  |  | This requirement may be removed before version 1. | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | =item event2sub ($code, $elem, $url, $first_line) | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | This method needs to turn the | 
| 413 |  |  |  |  |  |  | event handler code in C<$code> into an object with a C method | 
| 414 |  |  |  |  |  |  | and then return it. That object's C | 
| 415 |  |  |  |  |  |  | method will be | 
| 416 |  |  |  |  |  |  | called with the event target and the event | 
| 417 |  |  |  |  |  |  | object as its two arguments. Its return | 
| 418 |  |  |  |  |  |  | value, if | 
| 419 |  |  |  |  |  |  | defined, will be used to determine whether the event's C | 
| 420 |  |  |  |  |  |  | method is called. | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | The function's scope must contain the following objects: the global object, | 
| 423 |  |  |  |  |  |  | the document, the element's form (if there is one) and the element itself. | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | If the C<$code> could not be compiled, this method must set C<$@> and | 
| 426 |  |  |  |  |  |  | return C, just like C. | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | =item define_setter | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | This will be called | 
| 431 |  |  |  |  |  |  | with a list of property names representing the 'path' to the property. The | 
| 432 |  |  |  |  |  |  | last argument will be a coderef that must be called with the value assigned | 
| 433 |  |  |  |  |  |  | to the property. | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | B This is actually not used right now. The requirement for this may | 
| 436 |  |  |  |  |  |  | be removed some time before version 1. | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | =head1 PREREQUISITES | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | perl 5.8.4 or higher | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | HTML::DOM 0.032 or higher | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | JE 0.056 or later (when the SpiderMonkey binding is stable enough it will | 
| 445 |  |  |  |  |  |  | become optional) | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | CSS::DOM | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | WWW::Scripter 0.022 or higher | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | URI | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | Hash::Util::FieldHash::Compat | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | LWP 5.815 or higher | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | =head1 BUGS | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | =for comment | 
| 460 |  |  |  |  |  |  | (See also L.) | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | There is currently no system in place for preventing pages from different | 
| 463 |  |  |  |  |  |  | sites from communicating with each other. | 
| 464 |  |  |  |  |  |  |  | 
| 465 |  |  |  |  |  |  | To report bugs, please e-mail the author. | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  | =head1 AUTHOR & COPYRIGHT | 
| 468 |  |  |  |  |  |  |  | 
| 469 |  |  |  |  |  |  | Copyright (C) 2009-11 Father Chrysostomos | 
| 470 |  |  |  |  |  |  | join '.', reverse org => 'cpan' >>E | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | This program is free software; you may redistribute it and/or modify | 
| 473 |  |  |  |  |  |  | it under the same terms as perl. | 
| 474 |  |  |  |  |  |  |  | 
| 475 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | =over 4 | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | =item - | 
| 480 |  |  |  |  |  |  |  | 
| 481 |  |  |  |  |  |  | L | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  | =item - | 
| 484 |  |  |  |  |  |  |  | 
| 485 |  |  |  |  |  |  | L | 
| 486 |  |  |  |  |  |  |  | 
| 487 |  |  |  |  |  |  | =item - | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | L | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | =item - | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | L | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | =item - | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | L | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | =item - | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | L | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | =item - | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | L (the original version of this module) | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | =back |