Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Re: Running local Perl from HTML

by haukex (Bishop)
on Mar 10, 2019 at 19:26 UTC ( #1231096=note: print w/replies, xml ) Need Help??

in reply to Running local Perl from HTML

you can't edit the table directly in the browser

Sure you can, JavaScript makes that possible. <plug type="shameless"> It's even possible to run Perl instead of JS in the browser with WebPerl. </plug>

I also agree with what choroba said about running a webserver locally. You can bind the webserver to your localhost IP, and if you wanted to play it extra safe (like on a multi-user machine), you could use HTTPS and pass an access token.

The following uses Mojolicious to serve up a HTML file, injecting some JavaScript in the process. This JavaScript reacts to clicks on <td> and <th> elements, allowing you to edit their text, and then it immediately POSTs the modified HTML back to the server, which then rewrites the HTML file with what the browser sent. This is admittedly not the most elegant way to go about it, but it should work. Note it only supports one client at a time: although the JS makes sure to only send one request at a time, if two browser windows were to be open and submit requests at the same time, one of the changes would get lost.

#!/usr/bin/env perl use Mojolicious::Lite; use Mojo::Util qw/md5_sum/; use Mojo::DOM; use File::Replace 'replace3'; # Start me with: morbo -l https://localhost:3000/ my $HTMLFILE = '/tmp/test.html'; # ##### For Demo only: Write a default HTML file ##### if (!-e $HTMLFILE) { open my $fh, '>:raw:encoding(UTF-8)', $HTMLFILE or die $!; print $fh <<'END_HTML'; <!DOCTYPE html> <html lang="en"> <head> <title>Hello, World!</title> <style> table { border-collapse: collapse; } table, th, td { border: 1px solid black; } th, td { padding: 0.1em 0.4em; } </style> </head> <body> <table border="1"><tbody> <tr> <th>Foo</th> <th>Bar</th> <th>Quz</th> </tr> <tr> <td>Hello</td> <td>Perl</td> <td>World</td> </tr> <tr> <td>123</td> <td>456</td> <td>789</td> </tr> </tbody></table> </body> </html> END_HTML close $fh; } # ##### Authentication Stuff (optional) ##### my $TOKEN = md5_sum(rand(1e15).time); hook before_server_start => sub { my ($server, $app) = @_; print "URL with Token: ", $_->query(token=>$TOKEN), "\n" for map {Mojo::URL->new($_)} @{$server->listen}; }; under sub { my $c = shift; return 1 if ($c->param('token')//'') eq $TOKEN; $c->render(text => 'Bad token!', status => 403); return undef; }; # ##### JS Code ##### # note: the jQuery JS could also be saved locally my $JSCODE = <<'END_JSCODE'; <script src="" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> <script> $(function() { var requestInProgress = false; $('th, td').click(function() { if (requestInProgress) return; var newtxt = prompt("Foo", $(this).text() ); if ( newtxt==null ) return; $(this).text( newtxt ); requestInProgress = true; $.ajax({ method: 'POST', url: 'save?token=<<<TOKEN>>>', contentType: 'text/plain', data: document.body.innerHTML, dataType: 'text', }) .done(function(data) { console.log(data) }) .fail(function(jqXHR, textStatus, errorThrown) { alert("Error when saving: "+textStatus+"\n"+errorThrown); }) .always(function() { requestInProgress = false; }); }); }); </script> END_JSCODE $JSCODE=~s/<<<TOKEN>>>/$TOKEN/g; # ##### Request Handling Stuff ##### get '/' => sub { # read the file and inject our JavaScript my $c = shift; open my $fh, '<:raw:encoding(UTF-8)', $HTMLFILE or die $!; my $dom = Mojo::DOM->new(do { local $/; <$fh> }); close $fh; $dom->at('head')->append_content($JSCODE); $c->render(text => $dom); }; # NOTE this does not handle multiple requests at once. The JS tries to # prevent this, but it can still happen if there are multiple clients. post '/save' => sub { # rewrite the HTML file my $c = shift; my ($ifh,$ofh,$rpl) = replace3($HTMLFILE, ':raw:encoding(UTF-8)'); my $dom = Mojo::DOM->new(do { local $/; <$ifh> }); # Firefox apparently inserts blank lines here?? Remove them... ( my $newbody = $c->req->body ) =~ s/\n\K\n+\z//; $dom->at('body')->content($newbody); print $ofh $dom->to_string; $rpl->finish; $c->render(text=>'saved successfully'); }; app->start;

Update: Disclaimer: File::Replace is one of my modules too.

Replies are listed 'Best First'.
Re^2: Running local Perl from HTML
by Corion (Pope) on Mar 11, 2019 at 08:38 UTC

    To add some more body parts to this Frankenstein-thing, you can take the content-reloading parts of App::Mojo::AssetReloader to broadcast any change to all connected clients. That way, multiple sessions can edit the content at the same time, with hilarious results. Ideally, you then transfer any change immediately (or as soon as it is somewhat valid HTML) to reduce the amount of edit conflicts.

    Converting this to a real multiplayer editor which shows the multiple insertion points is left as another exercise.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1231096]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (2)
As of 2021-08-04 20:03 GMT
Find Nodes?
    Voting Booth?
    My primary motivation for participating at PerlMonks is: (Choices in context)

    Results (43 votes). Check out past polls.