}{'' . $self->_insert}ei;
$chunk;
}
}
} );
}
# Return the js script updating the time and adding config params
sub _insert {
my ($self) = @_;
my %var = (
wait => $self->wait * 1000,
url => $URL,
uid => $self->_uid,
now => time,
);
( my $script = $self->{_script} ) =~ s/{{([^}]*)}}/$var{$1}/eg;
return $script;
}
sub _uid {
my $self = shift;
return ++$self->{_uid};
}
# AFN saw a change, respond to each blocked client
sub _change_handler {
my $self = shift;
my $now = $self->{last_change} = time;
for my $uid ( keys %{ $self->{condvars} } ) {
my $condvar = delete $self->{condvars}->{$uid};
$condvar->send( $self->_respond( { changed => $now } ) );
}
return 1;
}
# Generate the plack response and encode any arguments as json
sub _respond {
my ( $self, $resp ) = @_;
## TODO: check that resp is a hash ref
return [
200,
[ 'Content-Type' => 'application/json' ],
[ JSON::Any->new->encode($resp) ] ];
}
# Return the js script from ShareDir unless we are developing/testing PMA.
# This is a bit hack-ish
sub _get_script {
my $self = shift;
my $script =
File::Spec->catfile( dirname( $INC{'Plack/Middleware/AutoRefresh.pm'} ),
qw( .. .. .. share ), $JS_DEV );
$script = dist_file( 'Plack-Middleware-AutoRefresh', $JS )
unless -r $script;
return '';
}
1;
__END__
=head1 NAME
Plack::Middleware::AutoRefresh - Reload pages in browsers when files are modified
=head1 SYNOPSIS
# in app.psgi
use Plack::Builder;
builder {
enable 'Plack::Middleware::AutoRefresh',
dirs => [ qw/html/ ], filter => qr/\.(swp|bak)/;
$app;
}
=head1 DESCRIPTION
Plack::Middleware::AutoRefresh is a middleware component that will
reload you web pages in your browser when changes are detected in the
source files. It should work with any modern browser that supports
JavaScript and multiple browsers simultaneously.
At this time, this middleware will only work with backend servers that
set psgi.nonblocking to true. Servers that are known to work include
L and L. You can force
a server with the C or C flag to C.
=head1 CONFIGURATION
dirs => [ '.' ] # default
dirs => [ qw/root share html/ ]
Specifies the directories to watch for changes. Will watch all files
and subdirectories of the specified directories for file modifications,
new files, deleted files, new directories and deleted directories.
filter => qr/\.(swp|bak)$/ # default
filter => qr/\.(svn|git)$/
filter => sub { shift =~ /\.html$/ }
Will apply the specified filter to the changed path name. This can be
a regular expression or a code ref. Any paths that match the regular
expression will be ignored. A code ref will be passed the path as the
only argument. Any false return values will be filtered out.
wait => 5 # default
Wait indicated the maximum number of seconds that the client should
block for while waiting for notifications of changes. Setting this to
a lower value will I improve response times.
=head1 ACKNOWLEDGMENTS
This component was inspired by NodeJuice (L).
NodeJuice provides very similar browser refresh functionality by
running a standalone proxy between your client and the web
application. It is a bit more robust than
Plack::Middleware::AutoRefresh as it can handle critical errors in
your app (ie, compile errors). Plack::Middleware::AutoRefresh is
simpler to setup and is limited to L based applications. Some
of the original JavaScript was taken from nodeJuice project as well,
although it was mostly rewritten prior to release. Thank you to
Stephen Blum the author of nodeJuice.
A huge thank you to the man behind L, Tatsuhiko Miyagawa, who
help me brainstorm the implementation, explained the inners of the
Plack servers, and re-wrote my broken code.
=head1 IMPLEMENTATION
Plack::Middleware::AutoRefresh accomplishes the browser refresh by
inserting a bit (1.2K to be precise) of JavaScript into the (x)html
pages your Plack application on the fly. The JavaScript tries to have
minimal impact: only one anonymous function and one global flag
(window['-plackAutoRefresh-']) are added. The JavaScript will open an
Ajax connection back to your Plack server which will block waiting to
be notified of changes. When a change notification arrives, the
JavaScript will trigger a page reload.
=head1 SEE ALSO
NodeJuice at L.
Modules used to implement this module L.
And of course, L.
=head1 BUGS
Please report any bugs or suggestions at L
=head1 AUTHOR
Mark Grimes, Emgrimes@cpan.orgE
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2010 by Mark Grimes
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.2 or,
at your option, any later version of Perl 5 you may have available.
=cut