Reworked file add/rename/delete handling

Also a few minor fixes in perlrunner
master
Hauke D 7 years ago
parent 2ef4af02cb
commit 93b73c04db

@ -5,6 +5,9 @@ body {
.text,.fakelink { .text,.fakelink {
font-family: Calibri, Ubuntu, "Droid Sans", Tahoma, Arial, Helvetica, sans-serif; font-family: Calibri, Ubuntu, "Droid Sans", Tahoma, Arial, Helvetica, sans-serif;
} }
.small {
font-size: 0.8em;
}
pre,textarea,code,.code,.filename,.CodeMirror { pre,textarea,code,.code,.filename,.CodeMirror {
font-family: Consolas, "Ubuntu Mono", "Droid Sans Mono", "Lucida Console", "Courier New", Courier, monospace; font-family: Consolas, "Ubuntu Mono", "Droid Sans Mono", "Lucida Console", "Courier New", Courier, monospace;
} }
@ -20,12 +23,36 @@ pre {
max-height: 12em; max-height: 12em;
} }
.codewithfn {
margin-top: 0.1em;
}
.fnfuncs {
cursor: default;
}
.filename {
display: inline-block;
border: 0;
padding: 1px;
min-width: 1em;
cursor: auto;
}
.filefuncs {
display: none;
margin-left: 1em;
}
.fnfuncs:hover .filefuncs {
display: inline-block;
}
.fakelink { .fakelink {
color: darkblue; color: darkblue;
cursor: pointer; cursor: pointer;
font-size: 0.9em; font-size: 0.9em;
} }
.badfilename {
background-color: rgba(255,200,200,255);
/* also has a placeholder text */
min-width: 10em;
}
#runnerstate { #runnerstate {
margin-top: 0.1em; margin-top: 0.1em;
margin-bottom: 0.3em; margin-bottom: 0.3em;
@ -37,3 +64,8 @@ pre {
margin-bottom: 0.3em; margin-bottom: 0.3em;
padding: 0.1em 0.2em; padding: 0.1em 0.2em;
} }
#inputhere, #outputhere {
text-align: right;
}

@ -93,6 +93,7 @@ function findPerlRunner () {
if (perlRunner) if (perlRunner)
window.clearInterval(pollId); window.clearInterval(pollId);
else if ( Date.now()>pollUntil ) { else if ( Date.now()>pollUntil ) {
//TODO: alternative to confirm() if modals are not allowed
if (window.confirm("Perl does not appear to have loaded yet, keep waiting?\n" 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.)")) +"(If you are on a slow connection, click OK to keep waiting.)"))
pollUntil = Date.now() + 10*1000; pollUntil = Date.now() + 10*1000;
@ -167,36 +168,84 @@ function fetchUrl(url,cm) { // fetch the contents of a URL into a CodeMirror ins
function makeCodeWithFn (fn,targ,ro,nodel) { function makeCodeWithFn (fn,targ,ro,nodel) {
var div = $('<div/>',{class:"codewithfn"}); var div = $('<div/>',{class:"codewithfn"});
//TODO: the "delete" and "rename" functions should probably be styled better
var fnfuncs = $('<div/>',{class:"fnfuncs"}).appendTo(div);
var filename = $('<input/>',{class:"filename code",type:"text",
placeholder:"Enter a filename!"})
.appendTo(fnfuncs);
filename.val(fn);
// autosize the filename text box via a hidden span
var fn_width = $('<span/>',
{class:"code",style:"display:none;white-space:pre;"}
).insertAfter(filename);
filename.on('input', function () {
var newfn = filename.val();
fn_width.text( newfn );
filename.width( fn_width.width()+10 );
if (newfn.length)
filename.removeClass("badfilename");
else
filename.addClass("badfilename");
});
/* we need to trigger this handler once when the input
* field is added to the document, we do this below */
var filefuncs = $('<div/>',{class:"filefuncs"}).appendTo(fnfuncs);
if (!nodel) { if (!nodel) {
$('<div/>',{class:"fakelink",style:"float:right;",text:"delete"}) var conf = $('<span/>', {class:"text small"})
.appendTo(div).click(function () { .append(
if (confirm("Are you sure you want to remove this file?")) "&ensp;",
div.remove() }); "Are you sure?",
"&ensp;",
$('<span/>',{class:"fakelink",text:"Yes"})
.click(function () { div.remove(); }),
"&ensp;",
$('<span/>',{class:"fakelink",text:"Cancel"})
.click(function () { conf.hide(); }),
);
$('<span/>',{class:"fakelink",text:"delete"})
.appendTo(filefuncs).click(function () {
conf.show();
});
conf.hide();
conf.appendTo(filefuncs);
} }
$('<div/>',{class:"filename",text:fn})
.appendTo(div).click(function () {
var filename = $(this);
var newname = prompt("Please choose a new filename:", filename.text());
if (newname) filename.text(newname);
});
div.append( $('<div/>',{style:"clear:both;"}) );
var ta = $('<textarea/>').appendTo(div); var ta = $('<textarea/>').appendTo(div);
targ.before(div); targ.before(div);
filename.trigger('input'); // see above
var cm = makeCM(ta, !fn.match(/\.pl$/i), ro); var cm = makeCM(ta, !fn.match(/\.pl$/i), ro);
div.data('CodeMirrorInstance', cm); div.data('CodeMirrorInstance', cm);
return {div:div,ta:ta,cm:cm}; return {div:div,ta:ta,cm:cm};
} }
function pickNewFilename (inNotOut) {
var x = inNotOut ? 'input' : 'output';
for (var i=1; i<1000; i++) {
var fn = x+i+".txt";
var found = $('div.'+x+'s .filename')
.filter(function(){ return $(this).val() == fn });
if (!found.length)
return fn;
}
$('#runnererrors>pre').text('Too many '+x+' files');
$('#runnererrors').show();
throw 'Too many '+x+' files';
}
function setupOutputFile (fn, text) { function setupOutputFile (fn, text) {
var found = $('div.outputs>.filename')
.filter(function(){ return $(this).text() == fn });
var cm; var cm;
if (found.length) { if (fn) {
var div = found.parent(); var founddiv = $('div.outputs')
cm = div.data('CodeMirrorInstance'); .filter(function(){ return $('.filename',this).val() == fn });
if (founddiv.length)
cm = founddiv.data('CodeMirrorInstance');
} }
else { else
fn = pickNewFilename(false);
if (!cm) {
var cfn = makeCodeWithFn(fn, $('#outputhere'), 1); var cfn = makeCodeWithFn(fn, $('#outputhere'), 1);
cfn.div.addClass("outputs"); cfn.div.addClass("outputs");
cm = cfn.cm; cm = cfn.cm;
@ -205,23 +254,7 @@ function setupOutputFile (fn, text) {
} }
function setupInputFile (inp) { function setupInputFile (inp) {
var fn; var fn = inp["fn"] ? inp.fn : pickNewFilename(true);
if (inp["fn"]) fn = inp.fn;
else { // autogenerate a filename
for (var i=1; i<1000; i++) {
var testfn = "input"+i+".txt";
var found = $('div.inputs>.filename')
.filter(function(){ return $(this).text() == testfn });
if (!found.length) {
fn = testfn;
break }
}
if (!fn) {
$('#runnererrors>pre').text('Too many input files');
$('#runnererrors').show();
throw 'Too many input files';
}
}
var cfn = makeCodeWithFn(fn, $('#inputhere'), 0); var cfn = makeCodeWithFn(fn, $('#inputhere'), 0);
cfn.div.addClass("inputs"); cfn.div.addClass("inputs");
if (inp["text"]) if (inp["text"])
@ -237,19 +270,19 @@ function getFileData () {
var scriptdiv = $('#script'); var scriptdiv = $('#script');
if (scriptdiv.is(':visible')) { if (scriptdiv.is(':visible')) {
filedata.script = scriptdiv.data('CodeMirrorInstance').getValue(); filedata.script = scriptdiv.data('CodeMirrorInstance').getValue();
filedata.script_fn = scriptdiv.find('>.filename').text(); filedata.script_fn = scriptdiv.find('.filename').val();
} }
// inputs // inputs
$('.inputs').each(function () { $('.inputs').each(function () {
var div = $(this); var div = $(this);
var fn = $('>.filename',div).text(); var fn = $('.filename',div).val();
var text = div.data('CodeMirrorInstance').getValue(); var text = div.data('CodeMirrorInstance').getValue();
if (!filedata["inputs"]) filedata.inputs = []; if (!filedata["inputs"]) filedata.inputs = [];
filedata.inputs.push( { fn:fn, text:text } ); filedata.inputs.push( { fn:fn, text:text } );
}); });
// outputs // outputs
$('.outputs').each(function () { $('.outputs').each(function () {
var fn = $(this).find('>.filename').text(); var fn = $(this).find('.filename').val();
if (!filedata["outputs"]) filedata.outputs = []; if (!filedata["outputs"]) filedata.outputs = [];
filedata.outputs.push(fn); filedata.outputs.push(fn);
}); });
@ -262,12 +295,19 @@ $(function () {
var hash = hashdata.length>0 ? JSON.parse(decodeURIComponent(hashdata)) : {}; var hash = hashdata.length>0 ? JSON.parse(decodeURIComponent(hashdata)) : {};
$('#addinput').click(function () { $('#addinput').click(function () {
var fn = prompt("Please choose a filename for the new input file:"); setupInputFile( {} );
if (fn) setupInputFile( {fn:fn} );
}); });
$('#addoutput').click(function () { $('#addoutput').click(function () {
var fn = prompt("Please choose a filename for the new output file:"); setupOutputFile();
if (fn) setupOutputFile( fn ); });
var argv_inp = $('#argv');
var argv_autosize = $('<span/>',
{class:"code",style:"display:none;white-space:pre;"}
).insertAfter(argv_inp);
argv_inp.on('input', function () {
argv_autosize.text( argv_inp.val() );
argv_inp.width( argv_autosize.width()+10 );
}); });
// script // script
@ -283,7 +323,8 @@ $(function () {
// command line // command line
if (hash["cmdline"]) if (hash["cmdline"])
$('#argv').val(hash.cmdline); argv_inp.val(hash.cmdline);
argv_inp.trigger('input');
// input files // input files
$('.inputs').remove(); $('.inputs').remove();
@ -294,11 +335,11 @@ $(function () {
// stdout/stderr // stdout/stderr
if (hash["mergeStdOutErr"]) { if (hash["mergeStdOutErr"]) {
mergeStdOutErr = 1; mergeStdOutErr = 1;
$('#stdout>.filename').text("STDOUT+STDERR"); $('#stdout .filename').val("STDOUT+STDERR");
} }
else { else {
mergeStdOutErr = 0; mergeStdOutErr = 0;
$('#stdout>.filename').text("STDOUT"); $('#stdout .filename').val("STDOUT");
} }
clearStdOutput(); clearStdOutput();
@ -311,7 +352,7 @@ $(function () {
$('#runperl').click( function () { $('#runperl').click( function () {
clearStdOutput(); clearStdOutput();
// command-line args // command-line args
var argv = parseCmdLine($('#argv').val()); var argv = parseCmdLine(argv_inp.val());
if (argv.length<1 || argv[0]!="perl") { if (argv.length<1 || argv[0]!="perl") {
$('#runnererrors>pre').text('Invalid command line, command must be "perl"'); $('#runnererrors>pre').text('Invalid command line, command must be "perl"');
$('#runnererrors').show(); $('#runnererrors').show();
@ -338,13 +379,13 @@ $(function () {
</head> </head>
<body> <body>
<div id="inputhere" style="text-align:right;"> <div id="inputhere">
<span id="addinput" class="fakelink">Add Input File</span> <span id="addinput" class="fakelink">Add Input File</span>
</div> </div>
<div id="perlctrl"> <div id="perlctrl">
<button id="runperl"><code>perl</code> &#x25BA;</button> <button id="runperl"><code>perl</code> &#x25BA;</button>
<input type="text" id="argv" class="code" size="60" value='perl' /> <input type="text" id="argv" class="code" value='perl' />
</div> </div>
<div id="runnerstate" class="text"> <div id="runnerstate" class="text">
@ -356,16 +397,16 @@ $(function () {
</div> </div>
<div id="stdout" class="codewithfn" style="display:none;"> <div id="stdout" class="codewithfn" style="display:none;">
<div class="filename">STDOUT</div> <input type="text" class="filename code" readonly="readonly" value="STDOUT" size="7" />
<textarea></textarea> <textarea></textarea>
</div> </div>
<div id="stderr" class="codewithfn" style="display:none;"> <div id="stderr" class="codewithfn" style="display:none;">
<div class="filename">STDERR</div> <input type="text" class="filename code" readonly="readonly" value="STDERR" size="7" />
<textarea></textarea> <textarea></textarea>
</div> </div>
<div id="outputhere" style="text-align:right;"> <div id="outputhere">
<span id="addoutput" class="fakelink">Add Output File</span> <span id="addoutput" class="fakelink">Add Output File</span>
</div> </div>

@ -73,6 +73,7 @@ Perl.addStateChangeListener(function (from,to) {
// {encoding:"binary"} => readFile returns Uint8Array // {encoding:"binary"} => readFile returns Uint8Array
// Should then also provide the same support on FS.writeFile() as well // Should then also provide the same support on FS.writeFile() as well
var of = { fn: file }; var of = { fn: file };
if (!file) return of;
try { try {
of.text = FS.readFile(file, {encoding:"utf8"}); of.text = FS.readFile(file, {encoding:"utf8"});
} }
@ -114,7 +115,7 @@ function saveFile (fn, data) {
FS.writeFile(fn, data); FS.writeFile(fn, data);
} }
catch (e) { catch (e) {
reportErr("couldn't write "+file+" because "+e); reportErr("couldn't write "+fn+" because "+e);
} }
} }
@ -146,15 +147,12 @@ window.addEventListener('message', function (event) {
// one solution would be to just have the script be an input file (code mirror syntax highlighting based on filename?) // one solution would be to just have the script be an input file (code mirror syntax highlighting based on filename?)
// note overlaps of output filenames with input files is ok // note overlaps of output filenames with input files is ok
// we also don't check for duplicate filenames // we also don't check for duplicate filenames
if (rp["script"]) { if (rp["script"])
var script_fn = 'script.pl'; saveFile(rp["script_fn"] ? rp.script_fn : 'script.pl', rp.script);
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) //TODO Later: can we support STDIN? (probably need to look at webperl.js)
if (rp["inputs"]) if (rp["inputs"])
rp.inputs.forEach(function (inp) { rp.inputs.forEach(function (inp) {
if (!inp.fn) return;
saveFile(inp.fn, inp.text); saveFile(inp.fn, inp.text);
}); });
curOutputFiles = rp["outputs"]; curOutputFiles = rp["outputs"];

Loading…
Cancel
Save