diff --git a/web/democode/perleditor.css b/web/democode/perleditor.css index 6e770e7..dcf9137 100644 --- a/web/democode/perleditor.css +++ b/web/democode/perleditor.css @@ -5,6 +5,9 @@ body { .text,.fakelink { font-family: Calibri, Ubuntu, "Droid Sans", Tahoma, Arial, Helvetica, sans-serif; } +.small { + font-size: 0.8em; +} pre,textarea,code,.code,.filename,.CodeMirror { font-family: Consolas, "Ubuntu Mono", "Droid Sans Mono", "Lucida Console", "Courier New", Courier, monospace; } @@ -20,12 +23,36 @@ pre { 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 { color: darkblue; cursor: pointer; font-size: 0.9em; } - +.badfilename { + background-color: rgba(255,200,200,255); + /* also has a placeholder text */ + min-width: 10em; +} #runnerstate { margin-top: 0.1em; margin-bottom: 0.3em; @@ -37,3 +64,8 @@ pre { margin-bottom: 0.3em; padding: 0.1em 0.2em; } + +#inputhere, #outputhere { + text-align: right; +} + diff --git a/web/democode/perleditor.html b/web/democode/perleditor.html index dfd86f8..f8ddf78 100644 --- a/web/democode/perleditor.html +++ b/web/democode/perleditor.html @@ -93,6 +93,7 @@ function findPerlRunner () { if (perlRunner) window.clearInterval(pollId); 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 you are on a slow connection, click OK to keep waiting.)")) 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) { var div = $('
',{class:"codewithfn"}); - //TODO: the "delete" and "rename" functions should probably be styled better + + var fnfuncs = $('',{class:"fnfuncs"}).appendTo(div); + + var filename = $('',{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 = $('', + {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 = $('',{class:"filefuncs"}).appendTo(fnfuncs); + if (!nodel) { - $('',{class:"fakelink",style:"float:right;",text:"delete"}) - .appendTo(div).click(function () { - if (confirm("Are you sure you want to remove this file?")) - div.remove() }); + var conf = $('', {class:"text small"}) + .append( + " ", + "Are you sure?", + " ", + $('',{class:"fakelink",text:"Yes"}) + .click(function () { div.remove(); }), + " ", + $('',{class:"fakelink",text:"Cancel"}) + .click(function () { conf.hide(); }), + ); + $('',{class:"fakelink",text:"delete"}) + .appendTo(filefuncs).click(function () { + conf.show(); + }); + conf.hide(); + conf.appendTo(filefuncs); } - $('',{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( $('',{style:"clear:both;"}) ); + var ta = $('').appendTo(div); targ.before(div); + filename.trigger('input'); // see above var cm = makeCM(ta, !fn.match(/\.pl$/i), ro); div.data('CodeMirrorInstance', 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) { - var found = $('div.outputs>.filename') - .filter(function(){ return $(this).text() == fn }); var cm; - if (found.length) { - var div = found.parent(); - cm = div.data('CodeMirrorInstance'); + if (fn) { + var founddiv = $('div.outputs') + .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); cfn.div.addClass("outputs"); cm = cfn.cm; @@ -205,23 +254,7 @@ function setupOutputFile (fn, text) { } function setupInputFile (inp) { - var fn; - 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 fn = inp["fn"] ? inp.fn : pickNewFilename(true); var cfn = makeCodeWithFn(fn, $('#inputhere'), 0); cfn.div.addClass("inputs"); if (inp["text"]) @@ -237,19 +270,19 @@ function getFileData () { var scriptdiv = $('#script'); if (scriptdiv.is(':visible')) { filedata.script = scriptdiv.data('CodeMirrorInstance').getValue(); - filedata.script_fn = scriptdiv.find('>.filename').text(); + filedata.script_fn = scriptdiv.find('.filename').val(); } // inputs $('.inputs').each(function () { var div = $(this); - var fn = $('>.filename',div).text(); + var fn = $('.filename',div).val(); var text = div.data('CodeMirrorInstance').getValue(); if (!filedata["inputs"]) filedata.inputs = []; filedata.inputs.push( { fn:fn, text:text } ); }); // outputs $('.outputs').each(function () { - var fn = $(this).find('>.filename').text(); + var fn = $(this).find('.filename').val(); if (!filedata["outputs"]) filedata.outputs = []; filedata.outputs.push(fn); }); @@ -262,12 +295,19 @@ $(function () { var hash = hashdata.length>0 ? JSON.parse(decodeURIComponent(hashdata)) : {}; $('#addinput').click(function () { - var fn = prompt("Please choose a filename for the new input file:"); - if (fn) setupInputFile( {fn:fn} ); + setupInputFile( {} ); }); $('#addoutput').click(function () { - var fn = prompt("Please choose a filename for the new output file:"); - if (fn) setupOutputFile( fn ); + setupOutputFile(); + }); + + var argv_inp = $('#argv'); + var argv_autosize = $('', + {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 @@ -283,7 +323,8 @@ $(function () { // command line if (hash["cmdline"]) - $('#argv').val(hash.cmdline); + argv_inp.val(hash.cmdline); + argv_inp.trigger('input'); // input files $('.inputs').remove(); @@ -294,11 +335,11 @@ $(function () { // stdout/stderr if (hash["mergeStdOutErr"]) { mergeStdOutErr = 1; - $('#stdout>.filename').text("STDOUT+STDERR"); + $('#stdout .filename').val("STDOUT+STDERR"); } else { mergeStdOutErr = 0; - $('#stdout>.filename').text("STDOUT"); + $('#stdout .filename').val("STDOUT"); } clearStdOutput(); @@ -311,7 +352,7 @@ $(function () { $('#runperl').click( function () { clearStdOutput(); // command-line args - var argv = parseCmdLine($('#argv').val()); + var argv = parseCmdLine(argv_inp.val()); if (argv.length<1 || argv[0]!="perl") { $('#runnererrors>pre').text('Invalid command line, command must be "perl"'); $('#runnererrors').show(); @@ -338,13 +379,13 @@ $(function () { -