#!/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/ htmltbledit.pl
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="https://code.jquery.com/jquery-3.3.1.min.js"
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.