File Coverage

blib/lib/Mojolicious/Plugin/Surveil.pm
Criterion Covered Total %
statement 27 34 79.4
branch 4 6 66.6
condition 5 7 71.4
subroutine 7 8 87.5
pod 1 1 100.0
total 44 56 78.5


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Surveil;
2 2     2   1145 use Mojo::Base 'Mojolicious::Plugin';
  2         5  
  2         15  
3              
4 2     2   387 use Mojo::JSON qw(encode_json decode_json);
  2         8  
  2         1049  
5              
6             our $VERSION = '0.02';
7              
8             sub register {
9 2     2 1 75 my ($self, $app, $config) = @_;
10              
11 2   50     17 $config->{events} ||= [qw(click touchstart touchcancel touchend)];
12              
13 2         3 push @{$app->renderer->classes}, __PACKAGE__;
  2         15  
14 2         34 $self->_after_render_hook($app, $config);
15 2 50       42 $self->_default_route($app, $config) unless $config->{path};
16             }
17              
18             sub _after_render_hook {
19 2     2   5 my ($self, $app, $config) = @_;
20 2         4 my $enable_param = $config->{enable_param};
21              
22             $app->hook(
23             after_render => sub {
24 3     3   40545 my ($c, $output, $format) = @_;
25 3 50       16 return if $format ne 'html';
26 3 100 100     21 return if $enable_param and !$c->param($enable_param);
27 2         286 my $js = $self->_javascript_code($c, $config);
28 2         7953 $$output =~ s!!$js!;
29             }
30 2         15 );
31             }
32              
33             sub _default_route {
34 2     2   4 my ($self, $app, $config) = @_;
35              
36 2         4 $config->{path} = '/mojolicious/plugin/surveil';
37              
38             $app->routes->websocket($config->{path})->to(
39             cb => sub {
40 0     0   0 my $c = shift;
41 0         0 $c->inactivity_timeout(60);
42             $c->on(
43             message => sub {
44 0         0 my $action = decode_json $_[1];
45 0         0 my ($type, $target) = (delete $action->{type}, delete $action->{target});
46 0         0 $app->log->debug(qq(Event "$type" on "$target" @{[encode_json $action]}));
  0         0  
47             }
48 0         0 );
49             }
50 2         10 );
51             }
52              
53             sub _javascript_code {
54 2     2   6 my ($self, $c, $config) = @_;
55 2   50     9 my $scheme = $c->req->url->to_abs->scheme || 'http';
56              
57 2         401 $scheme =~ s!^http!ws!;
58              
59             $c->render_to_string(
60             template => 'mojolicious/plugin/surveil',
61             events => encode_json($config->{events}),
62 2         17 surveil_url => $c->url_for($config->{path})->to_abs->scheme($scheme),
63             );
64             }
65              
66             1;
67              
68             =encoding utf8
69              
70             =head1 NAME
71              
72             Mojolicious::Plugin::Surveil - Surveil user actions
73              
74             =head1 VERSION
75              
76             0.02
77              
78             =head1 DESCRIPTION
79              
80             L is a plugin which allow you to see every
81             event a user trigger on your web page. It is meant as a debug tool for
82             seeing events, even if the browser does not have a JavaScript console.
83              
84             Note: With great power, comes great responsibility.
85              
86             CAVEAT: The JavaScript that is injected require WebSocket in the browser to
87             run. The surveil events are attached to the "body" element, so any other event
88             that prevent events from bubbling will not emit this to the WebSocket
89             resource.
90              
91             =head1 SYNOPSIS
92              
93             Use default logging:
94              
95             use Mojolicious::Lite;
96             plugin "surveil";
97             app->start;
98              
99             Use custom route:
100              
101             use Mojolicious::Lite;
102              
103             plugin surveil => { path => "/surveil" };
104              
105             websocket "/surveil" => sub {
106             my $c = shift;
107              
108             $c->on(message => sub {
109             my ($c, $action) = @_;
110             warn "User event: $action\n";
111             });
112             };
113              
114             app->start;
115              
116             =head1 CONFIG
117              
118             This plugin can take the following config params:
119              
120             =over 4
121              
122             =item * enable_param = "..."
123              
124             Used to specify a query parameter to be part of the URL to enable surveil.
125              
126             Default is not to require any query parameter.
127              
128             =item * events = [...]
129              
130             The events that should be reported back over the WebSocket.
131              
132             Defaults to click, touchstart, touchcancel and touchend.
133             (The default list is EXPERIMENTAL).
134              
135             =item * path = "...";
136              
137             The path to the WebSocket route.
138              
139             Defaults to C. Emitting the "path" parameter will
140             also add a default WebSocket route which simply log with "debug" the action
141             that was taken. (The format of the logging is EXPERIMENTAL)
142              
143             =back
144              
145             =head1 METHODS
146              
147             =head2 register
148              
149             $self->register($app, $config);
150              
151             Used to add an "after_render" hook into the application which adds a
152             JavaScript to every HTML document.
153              
154             =head1 COPYRIGHT AND LICENSE
155              
156             Copyright (C) 2014, Jan Henning Thorsen
157              
158             This program is free software, you can redistribute it and/or modify it under
159             the terms of the Artistic License version 2.0.
160              
161             =head1 AUTHOR
162              
163             Jan Henning Thorsen - C
164              
165             =cut
166              
167             __DATA__