Major update of "democode"

master
Hauke D 7 years ago
parent 310bb92b2c
commit 2f4eff19a1

@ -4,14 +4,58 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebPerl Code Demo</title> <title>WebPerl Code Demo</title>
<iframe name="perlrunner" sandbox="allow-scripts" <!-- ##### WebPerl - http://webperl.zero-g.net #####
src="perlrunner.html" style="display: none;"></iframe>
Copyright (c) 2018 Hauke Daempfling (haukex@zero-g.net)
at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (IGB),
Berlin, Germany, http://www.igb-berlin.de
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl 5 itself: either the GNU General Public
License as published by the Free Software Foundation (either version 1,
or, at your option, any later version), or the "Artistic License" which
comes with Perl 5.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the licenses for details.
<iframe sandbox="allow-scripts" src="perleditor.html#i1f=Foo%0ABar%0AQuz&i1n=in1.txt&script=use warnings;%0Ause strict;%0A%0Awhile (<>) {%0A s/[aeiou]/_/gi;%0A}&cmdline=perl script.pl in1.txt" You should have received a copy of the licenses along with this program.
style="border:1px solid black;width:100%;height:20em;"></iframe> If not, see http://perldoc.perl.org/index-licence.html
##### -->
<!-- TODO: Document
Notes:
- "perl -CSD" is recommended because files are currently always UTF-8
- STDIN is currently not supported, workaround is to supply files on command line
-->
<iframe name="perlrunner" sandbox="allow-scripts"
src="perlrunner.html" style="display:none;"></iframe>
<iframe sandbox="allow-scripts" src="perleditor.html" <iframe id="perl1" sandbox="allow-scripts"
style="border:1px solid black;width:100%;height:20em;"></iframe> style="border:1px solid black;width:100%;height:8em;"></iframe>
<iframe id="perl2" sandbox="allow-scripts"
style="border:1px solid black;width:100%;height:40em;"></iframe>
<script>
document.getElementById('perl1').src =
"perleditor.html#" + encodeURIComponent(JSON.stringify( {
cmdline: "perl -e 'print \"Hello, World!\"'",
} ));
document.getElementById('perl2').src =
"perleditor.html#" + encodeURIComponent(JSON.stringify( {
cmdline: "perl devoweler.pl mytext.txt other.txt",
script: "use warnings;\nuse strict;\n\nopen my $vfh, '>', 'vowels.txt' or die $!;\n"
+"while (<>) {\n\tprint $vfh $1 while s/([aeiou])/_/i;\n\tprint;\n}\nclose $vfh;",
script_fn: "devoweler.pl",
inputs: [
{ fn: "mytext.txt", text: "Foo\nBar\nQuz\n" },
{ fn: "other.txt", text: "Hello, World!" },
],
outputs : [ "vowels.txt" ],
} ));
</script>
</head> </head>
<body> <body>

@ -0,0 +1,33 @@
body {
margin: 0.4em;
}
.text {
font-family: Calibri, Ubuntu, "Droid Sans", Tahoma, Arial, Helvetica, sans-serif;
}
pre,textarea,code,.code,.filename,.CodeMirror {
font-family: Consolas, "Ubuntu Mono", "Droid Sans Mono", "Lucida Console", "Courier New", Courier, monospace;
}
pre {
margin: 0;
}
.CodeMirror {
border: 1px solid lightgrey;
height: auto;
}
.CodeMirror-scroll {
max-height: 12em;
}
#runnerstate {
margin-top: 0.1em;
margin-bottom: 0.3em;
font-size: 0.8em;
}
#runnererrors {
background-color: rgba(255,200,200,255);
margin-top: 0.3em;
margin-bottom: 0.3em;
padding: 0.1em 0.2em;
}

@ -23,31 +23,11 @@ See the licenses for details.
You should have received a copy of the licenses along with this program. You should have received a copy of the licenses along with this program.
If not, see http://perldoc.perl.org/index-licence.html If not, see http://perldoc.perl.org/index-licence.html
--> ##### -->
<!--cacheable--><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css" integrity="sha256-oSrCnRYXvHG31SBifqP2PM1uje7SJUyX0nTwO2RJV54=" crossorigin="anonymous" /> <!--cacheable--><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css" integrity="sha256-oSrCnRYXvHG31SBifqP2PM1uje7SJUyX0nTwO2RJV54=" crossorigin="anonymous" />
<!--cacheable--><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/codemirror.min.css" integrity="sha256-I8NyGs4wjbMuBSUE40o55W6k6P7tu/7G28/JGUUYCIs=" crossorigin="anonymous" /> <!--cacheable--><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/codemirror.min.css" integrity="sha256-I8NyGs4wjbMuBSUE40o55W6k6P7tu/7G28/JGUUYCIs=" crossorigin="anonymous" />
<style> <link rel="stylesheet" href="perleditor.css" />
body {
margin: 0.4em;
}
.text {
font-family: Calibri, Ubuntu, "Droid Sans", Tahoma, Arial, Helvetica, sans-serif;
}
pre,textarea,code,.code,.filename,.CodeMirror {
font-family: Consolas, "Ubuntu Mono", "Droid Sans Mono", "Lucida Console", "Courier New", Courier, monospace;
}
pre {
margin: 0;
}
.CodeMirror {
border: 1px solid grey;
height: auto;
}
.CodeMirror-scroll {
max-height: 10em;
}
</style>
<!--cacheable--><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/codemirror.min.js" integrity="sha256-uRIJ6Wfou5cTtmcCvQNA9lvsYl8sUbZXxnfG+P79ssY=" crossorigin="anonymous"></script> <!--cacheable--><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/codemirror.min.js" integrity="sha256-uRIJ6Wfou5cTtmcCvQNA9lvsYl8sUbZXxnfG+P79ssY=" crossorigin="anonymous"></script>
<!--cacheable--><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/mode/perl/perl.min.js" integrity="sha256-Uu9QBfi8gU6J/MzQunal8ewmY+i/BbCkBrcAXA5bcCM=" crossorigin="anonymous"></script> <!--cacheable--><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/mode/perl/perl.min.js" integrity="sha256-Uu9QBfi8gU6J/MzQunal8ewmY+i/BbCkBrcAXA5bcCM=" crossorigin="anonymous"></script>
@ -55,6 +35,11 @@ pre {
<script> <script>
"use strict"; "use strict";
var mergeStdOutErr = 0; //TODO Later: make an options hash instead of individual variable(s)?
var perlRunner; // the Perl runner iframe found by findPerlRunner()
var buttonBlockers = {}; // for updateButtonState()
var lastExitStatus; // for runnerState()
function makeCM (textarea,plain,ro) { function makeCM (textarea,plain,ro) {
return CodeMirror.fromTextArea( textarea[0], { return CodeMirror.fromTextArea( textarea[0], {
viewportMargin: Infinity, // so browser's search works, not good for long documents though viewportMargin: Infinity, // so browser's search works, not good for long documents though
@ -65,67 +50,94 @@ function makeCM (textarea,plain,ro) {
} ); } );
} }
var mergeStdOutErr = 0; function runnerState (text) {
$('#runnerstate').text( text
+ (lastExitStatus ? ' (last exit status was '+lastExitStatus+')'
: '') );
}
var cm_std = { 1:null, 2:null }; // 1=stdout, 2=stderr function updateButtonState () {
function stdOutput (which, data) { // 1=stdout, 2=stderr $('#runperl').prop("disabled",
Object.keys(buttonBlockers).length>0 );
}
function stdOutput (which, data) { // which: 1=stdout, 2=stderr
if (mergeStdOutErr) which = 1; if (mergeStdOutErr) which = 1;
if (!cm_std[which]) {
var div = $(which==1?'#stdout':'#stderr'); var div = $(which==1?'#stdout':'#stderr');
div.show(); div.show();
cm_std[which] = makeCM($('textarea',div),1,1); var cm = div.data('CodeMirrorInstance');
div.data('CodeMirrorInstance', cm_std[which]); if (!cm) {
cm = makeCM($('textarea',div),1,1);
div.data('CodeMirrorInstance', cm);
} }
if (data && data.length) if (data && data.length)
cm_std[which].setValue( cm_std[which].getValue() + data ); cm.setValue( cm.getValue() + data );
} }
function clearStdOutput () { function clearStdOutput () {
if (cm_std["1"]) cm_std["1"].setValue(""); $('#stdout,#stderr').each(function (i) {
if (cm_std["2"]) cm_std["2"].setValue(""); var div = $(this);
var cm = div.data('CodeMirrorInstance');
if (cm) cm.setValue('');
div.hide();
});
} }
var perlRunner; function findPerlRunner () {
// assume calling this function means the runner isn't available
buttonBlockers.runnerState = 1;
updateButtonState();
// poll for perlRunner, which gets set by the message listener
var pollUntil = Date.now() + 10*1000; // milliseconds
var pollId;
pollId = window.setInterval( function () {
if (perlRunner)
window.clearInterval(pollId);
else if ( Date.now()>pollUntil ) {
if (window.confirm("Perl does not appear to have loaded yet, keep waiting?\n"
+"(If you are on a slow connection, click OK to keep waiting.)"))
pollUntil = Date.now() + 10*1000;
else
window.clearInterval(pollId);
}
else
if (window.parent && window.parent.frames["perlrunner"])
window.parent.frames["perlrunner"].postMessage(
{perlRunnerDiscovery:1}, '*');
}, 100);
}
window.addEventListener('message', function (event) { window.addEventListener('message', function (event) {
var data = event.data; var data = event.data;
//console.log("editor got message", data); //DB
if (data["perlRunnerState"]) { if (data["perlRunnerState"]) {
var disableBtn = true;
if ( data.perlRunnerState=="Ready" ) { if ( data.perlRunnerState=="Ready" ) {
perlRunner = event.source; perlRunner = event.source;
disableBtn = false; delete buttonBlockers.runnerState;
updateButtonState();
} }
else if ( data.perlRunnerState=="Ended" ) { else if ( data.perlRunnerState=="Ended" ) {
if ('exitStatus' in data)
lastExitStatus = ''+data.exitStatus;
// we know the runner will reload itself now
perlRunner = null; perlRunner = null;
findPerlRunner(); findPerlRunner();
} }
$('#runperl').prop("disabled",disableBtn); runnerState("Perl is "+data.perlRunnerState);
} }
else if (data["perlOutput"]) { else if (data["perlOutput"])
stdOutput(data.perlOutput.chan, data.perlOutput.data); stdOutput(data.perlOutput.chan, data.perlOutput.data);
else if (data["perlOutputFiles"]) {
data.perlOutputFiles.forEach(function (outp) {
setupOutputFile(outp.fn, outp.text);
});
}
else if (data["perlRunnerError"]) {
$('#runnererrors').show();
$('#runnererrors>pre').append(data.perlRunnerError+"\n");
} }
else console.warn("Perl Editor ignoring unknown message:",data); else console.warn("Perl Editor ignoring unknown message:",data);
}); });
function findPerlRunner () { function parseCmdLine(str) { //TODO: there's a better way to do this
var pollId;
var pollUntil = Date.now() + 10*1000; // milliseconds
pollId = window.setInterval( function () {
if (perlRunner) {
window.clearInterval(pollId);
}
else if ( Date.now()>pollUntil ) {
window.clearInterval(pollId);
console.error("Perl Editor could not contact Perl Runner"); //TODO: report error to user via UI (same for other console.error calls in this script)
}
else
if (window.parent && window.parent.frames["perlrunner"])
window.parent.frames["perlrunner"].postMessage(
{perlRunnerRegisterClient:1}, '*');
}, 100);
}
function parseCmdLine(str) {
var re = /"((?:\\"|\\\\|[^"])*)"|'((?:\\'|\\\\|[^'])*)'|(\S+)/g; var re = /"((?:\\"|\\\\|[^"])*)"|'((?:\\'|\\\\|[^'])*)'|(\S+)/g;
var argv = []; var argv = [];
var match; var match;
@ -137,57 +149,83 @@ function parseCmdLine(str) {
return argv; return argv;
} }
function parseParams(str) { // Thanks to https://stackoverflow.com/a/26849194 function fetchUrl(url,cm) { // fetch the contents of a URL into a CodeMirror instance
if (!str || !str.length) return {}; cm.setValue("Fetching URL\n"+url+"\nPlease wait...");
return str.split('&').reduce(function (params, param) { buttonBlockers["fetchUrls"]++;
var paramSplit = param.split('=').map(function (value) { updateButtonState();
return decodeURIComponent(value.replace(/\+/g, ' ')); $.get(url, function (data) {
cm.setValue(data);
},'text').fail(function (jqXHR,textStatus,errorThrown) {
cm.setValue("Fetching URL\n"+url+"\nFailed!\n"+textStatus+"\n"+errorThrown);
}).always(function () {
buttonBlockers.fetchUrls--;
if (!buttonBlockers.fetchUrls)
delete buttonBlockers.fetchUrls;
updateButtonState();
}); });
params[paramSplit[0]] = paramSplit[1];
return params;
}, {});
} }
function initialize (hash) { function setupOutputFile (fn, text) {
console.log("hash", hash); //DB var found = $('div.outputs>.filename')
.filter(function(){ return $(this).text() == fn });
var cm;
if (found.length) {
var div = found.parent();
cm = div.data('CodeMirrorInstance');
}
else {
var div = $('<div/>',{class:"codewithfn outputs"});
div.append( $('<div/>',{class:"filename",text:fn}) );
var ta = $('<textarea/>').appendTo(div);
$('#outputhere').before(div);
cm = makeCM(ta,1,1);
div.data('CodeMirrorInstance', cm);
}
cm.setValue( text ? text : '' );
}
$(function () {
var hashdata = window.location.hash.substr(1);
var hash = hashdata.length>0 ? JSON.parse(decodeURIComponent(hashdata)) : {};
// script // script
if (hash["script"] || hash["scripturl"]) { var scriptdiv = $('#script');
var script = $('#script'); if ( hash["script"] || hash["script_url"] ) {
script.show(); scriptdiv.show();
var cm = makeCM($('#perlcode')); var cm = makeCM($('#perlcode'),0,0);
script.data('CodeMirrorInstance', cm); scriptdiv.data('CodeMirrorInstance', cm);
if (hash["script"]) if (hash["script"])
cm.setValue(hash.script); cm.setValue(hash.script);
else if (hash["scripturl"]) { else if (hash["script_url"])
//TODO: fetch URL fetchUrl(hash.script_url,cm);
}
else throw "internal error: this shouldn't happen"; else throw "internal error: this shouldn't happen";
if (hash["scriptfn"]) if (hash["script_fn"])
$('.filename',script).text(hash.scriptfn); $('>.filename',scriptdiv).text(hash.script_fn);
} }
if (hash["cmdline"]) {
// command line
if (hash["cmdline"])
$('#argv').val(hash.cmdline); $('#argv').val(hash.cmdline);
}
// input files // input files
$('.inputs').remove(); $('.inputs').remove();
for (var i=1;;i++) { if ( hash["inputs"] ) hash.inputs.forEach(function(inp,i) {
if (!( hash["i"+i+"f"] || hash["i"+i+"u"] )) break; var fn = inp["fn"] || "input"+(i+1)+".txt";
var fn = hash["i"+i+"n"] || "input"+i+".txt";
var div = $('<div/>',{class:"codewithfn inputs"}); var div = $('<div/>',{class:"codewithfn inputs"});
div.append( $('<div/>',{class:"filename",text:fn}) ); div.append( $('<div/>',{class:"filename",text:fn}) );
var ta = $('<textarea/>').appendTo(div); var ta = $('<textarea/>').appendTo(div);
$('#inputhere').before(div); $('#inputhere').before(div);
var cm = makeCM(ta,1,0); var cm = makeCM(ta,1,0);
div.data('CodeMirrorInstance', cm); div.data('CodeMirrorInstance', cm);
if (hash["i"+i+"f"]) { if (inp["text"])
cm.setValue(hash["i"+i+"f"]); cm.setValue(inp.text);
} else if (inp["url"])
else if (hash["i"+i+"u"]) { fetchUrl(inp.url,cm);
//TODO: fetch URLs });
}
}
// stdout/stderr // stdout/stderr
if (hash["mergestdouterr"]) { if (hash["mergeStdOutErr"]) {
mergeStdOutErr = 1; mergeStdOutErr = 1;
$('#stdout>.filename').text("STDOUT+STDERR"); $('#stdout>.filename').text("STDOUT+STDERR");
} }
@ -196,44 +234,53 @@ function initialize (hash) {
$('#stdout>.filename').text("STDOUT"); $('#stdout>.filename').text("STDOUT");
} }
clearStdOutput(); clearStdOutput();
// output files
for (var i=1;;i++) {
if (hash["o"+i+"n"]) {
var div = $('<div/>',{class:"codewithfn outputs"});
div.append( $('<div/>',{class:"filename",text:hash["o"+i+"n"]}) );
var ta = $('<textarea/>').appendTo(div);
$('#outputhere').before(div);
var cm = makeCM(ta,1,1);
div.data('CodeMirrorInstance', cm);
}
else break;
}
}
$(function () { // output files
$('.outputs').remove();
initialize(parseParams(window.location.hash.substr(1))); if ( hash["outputs"] ) hash.outputs.forEach(function(outp) {
setupOutputFile(outp);
});
var btn_runperl = $('#runperl'); $('#runperl').click( function () {
btn_runperl.click( function () {
clearStdOutput(); clearStdOutput();
var rp_data = {};
// command-line args
var argv = parseCmdLine($('#argv').val()); var argv = parseCmdLine($('#argv').val());
if (argv.length<1 || argv[0]!="perl") { if (argv.length<1 || argv[0]!="perl") {
console.error("invalid command line"); $('#runnererrors>pre').text('Invalid command line, command must be "perl"');
return } $('#runnererrors').show();
else argv.shift(); return;
} // else
var runperl = { argv.shift();
//TODO: input files rp_data.argv = argv;
argv: argv, $('#runnererrors>pre').text('');
//TODO: script: perl_cm.getValue(), $('#runnererrors').hide();
}; // script
if (scriptdiv.is(':visible')) {
btn_runperl.prop("disabled",true); rp_data.script = scriptdiv.data('CodeMirrorInstance').getValue();
perlRunner.postMessage({ runPerl: runperl },'*'); rp_data.script_fn = scriptdiv.find('>.filename').text();
}
// inputs
$('.inputs').each(function () {
var div = $(this);
var fn = $('>.filename',div).text();
var text = div.data('CodeMirrorInstance').getValue();
if (!rp_data["inputs"]) rp_data.inputs = [];
rp_data.inputs.push([fn, text]);
});
// outputs
$('.outputs').each(function () {
var fn = $(this).find('>.filename').text();
if (!rp_data["outputs"]) rp_data.outputs = [];
rp_data.outputs.push(fn);
});
// send message to runner
buttonBlockers.runnerState = 1;
updateButtonState();
lastExitStatus = null;
runnerState("Requesting Perl Run...");
perlRunner.postMessage({ runPerl: rp_data }, '*');
}); });
btn_runperl.prop("disabled",true);
findPerlRunner(); findPerlRunner();
}); });
@ -255,6 +302,14 @@ $(function () {
<input type="text" id="argv" class="code" size="60" value='perl' /> <input type="text" id="argv" class="code" size="60" value='perl' />
</div> </div>
<div id="runnerstate" class="text">
Loading...
</div>
<div id="runnererrors" style="display:none;">
<pre></pre>
</div>
<div id="stdout" class="codewithfn" style="display:none;"> <div id="stdout" class="codewithfn" style="display:none;">
<div class="filename">STDOUT</div> <div class="filename">STDOUT</div>
<textarea></textarea> <textarea></textarea>

@ -23,7 +23,7 @@ See the licenses for details.
You should have received a copy of the licenses along with this program. You should have received a copy of the licenses along with this program.
If not, see http://perldoc.perl.org/index-licence.html If not, see http://perldoc.perl.org/index-licence.html
--> ##### -->
<!-- Possible To-Do for Later: This whole thing could probably also be <!-- Possible To-Do for Later: This whole thing could probably also be
accomplished with a Web Worker, but that would probably require a accomplished with a Web Worker, but that would probably require a
@ -44,83 +44,124 @@ Perl.endAfterMain=true; // act like command-line perl
var knownClients = []; var knownClients = [];
var currentClient; // which client we're running Perl for, also keeps state var currentClient; // which client we're running Perl for, also keeps state
var curOutputFiles;
var stdbuf = [null,'',''];
function reportErr (err) {
if (currentClient)
currentClient.postMessage({ perlRunnerError: err },'*');
else
console.error(err);
}
Perl.addStateChangeListener(function (from,to) { Perl.addStateChangeListener(function (from,to) {
if (from==to) return; // won't be needed as of v0.09-beta if (from==to) return; // won't be needed as of v0.09-beta
if (to=="Ended" && currentClient) {
for (var chan=1;chan<=2;chan++) // flush buffers
if (stdbuf[chan].length) {
currentClient.postMessage({ perlOutput: { chan:chan, data:stdbuf[chan] } },'*');
stdbuf[chan] = '';
}
currentClient.postMessage({ perlRunnerState: Perl.state,
exitStatus: Perl.exitStatus },'*');
for(var i=0; i<knownClients.length; i++) for(var i=0; i<knownClients.length; i++)
if (knownClients[i]!=currentClient)
knownClients[i].postMessage({ perlRunnerState: Perl.state },'*'); knownClients[i].postMessage({ perlRunnerState: Perl.state },'*');
if (to=="Ended") { if (curOutputFiles) {
if (currentClient) { var ofs = curOutputFiles.map(function (file) {
for (var c=1;c<=2;c++) // flush buffers //TODO Later: Support binary files as well?
if (stdbuf[c].length) // {encoding:"binary"} => readFile returns Uint8Array
currentClient.postMessage({ perlOutput: { chan:c, data:stdbuf[c] } },'*'); // Should then also provide the same support on FS.writeFile() as well
//TODO: how to handle nonzero exit codes and communicate them back to the client var of = { fn: file };
//TODO: post output files try {
of.text = FS.readFile(file, {encoding:"utf8"});
}
catch (e) {
reportErr("couldn't read "+file+" because "+e);
}
return of;
});
currentClient.postMessage({ perlOutputFiles: ofs },'*');
} }
else console.error("state change to Ended with no current client?"); }
else {
for(var i=0; i<knownClients.length; i++)
knownClients[i].postMessage({ perlRunnerState: Perl.state },'*');
}
if (to=="Ended") {
if (!currentClient)
console.error("Internal Error: Perl state change to Ended with no client");
window.location.reload(false); window.location.reload(false);
} }
}); });
var stdbuf = [null,'',''];
Perl.output = function (str,chan) { Perl.output = function (str,chan) {
stdbuf[chan] += str; stdbuf[chan] += str;
var pos = stdbuf[chan].lastIndexOf("\n"); var pos = stdbuf[chan].lastIndexOf("\n");
if (pos>-1) { if (pos<0) return;
var line = stdbuf[chan].slice(0,pos); var lines = stdbuf[chan].slice(0,pos+1);
if (currentClient) if (currentClient)
currentClient.postMessage({ perlOutput: { chan:chan, data:line+"\n" } },'*'); currentClient.postMessage({ perlOutput: { chan:chan, data:lines } },'*');
else else
console.warn("output on",chan==1?"STDOUT":"STDERR", console.error("Internal Error: Output on",chan==1?"STDOUT":"STDERR","with no client:",lines);
"with no client?",line);
stdbuf[chan] = stdbuf[chan].slice(pos+1); stdbuf[chan] = stdbuf[chan].slice(pos+1);
}
}; };
Perl.init(function () { function saveFile (fn, data) {
FS.currentPath = ENV.HOME; // NOTE: https://github.com/kripken/emscripten/issues/5873 if (fn.substring(0,1)!='/') // if relative, make absolute
window.addEventListener('message', function (event) { fn = FS.joinPath([FS.cwd(), fn]);
var data = event.data; try {
var result; FS.writeFile(fn, data);
if (data["perlRunnerRegisterClient"]) { }
result = { perlRunnerState: Perl.state }; catch (e) {
reportErr("couldn't write "+file+" because "+e);
}
}
window.addEventListener('message', function (event) {
if (event.data["perlRunnerDiscovery"]) {
if (!knownClients.includes(event.source)) if (!knownClients.includes(event.source))
knownClients.push(event.source); knownClients.push(event.source);
event.source.postMessage({ perlRunnerState: Perl.state },'*');
} }
else if (data["runPerl"]) { else if (event.data["runPerl"]) {
if (!knownClients.includes(event.source)) if (!knownClients.includes(event.source))
knownClients.push(event.source); knownClients.push(event.source);
if (currentClient) { // check state
//TODO Later: a way to communicate these errors back to client? if (currentClient && currentClient !== event.source) {
console.error("Attempt to run Perl from",event.source, console.error("Attempt to run Perl from",event.source,
"but am already running Perl for",currentClient); "but am already running Perl for",currentClient);
reportErr("Attempt to run Perl (from "+event.origin
+") but am already running Perl for someone else (see JavaScript console)");
return; return;
} } // else
currentClient = event.source;
if (Perl.state!="Ready") { if (Perl.state!="Ready") {
console.error("Attempt to run Perl in state",Perl.state, reportErr("Attempt to run Perl in state "+Perl.state);
"from",event.source);
return; return;
} // else
// set up files and run perl
var rp = event.data.runPerl;
if (rp["script"]) {
var script_fn = 'script.pl';
if (rp["script_fn"])
script_fn = rp.script_fn;
saveFile(script_fn, rp.script);
} }
//TODO Later: can we support STDIN? (probably need to look at webperl.js)
currentClient = event.source; if (rp["inputs"])
rp.inputs.forEach(function (inp) {
var scriptFn = data.runPerl["scriptName"] saveFile(inp[0], inp[1]);
? data.runPerl.scriptName : 'script.pl';
Module['thisProgram'] = './'+scriptFn;
FS.writeFile( FS.joinPath([FS.cwd(), scriptFn]),
data.runPerl.script );
//TODO: input files
var argv = data.runPerl["argv"] ? data.runPerl.argv : [scriptFn];
Perl.start(argv);
}
else console.warn("Perl Runner ignoring unknown message:", data);
//console.log("runner got message", data, "result", result); //DB
if (result)
event.source.postMessage(result,
event.origin==null || event.origin=="null" ? '*' : event.origin);
}); });
curOutputFiles = rp["outputs"];
Perl.start( rp["argv"] ? rp.argv : [] );
}
else console.warn("Perl Runner ignoring unknown message:", event.data);
});
Perl.init(function () {
Module['thisProgram'] = 'perl';
FS.currentPath = ENV.HOME; // NOTE: https://github.com/kripken/emscripten/issues/5873
}); });
</script> </script>

Loading…
Cancel
Save