diff --git a/index.php b/index.php index d24e0fdd35491b0b4e69ac3dfaca340d8b3738a7..f6b4213916e1ff8b65b07508aff5b62ab9fde71c 100644 --- a/index.php +++ b/index.php @@ -76,7 +76,7 @@ <option value="preview">Preview</option> <option value="jats">alias for jats_archiving</option> <option value="asciidoc">AsciiDoc (modern) as interpreted by AsciiDoctor</option> - <option value="asciidoc_legacy.">AsciiDoc as interpreted by asciidoc-py</option> + <option value="asciidoc_legacy">AsciiDoc as interpreted by asciidoc-py</option> <option value="biblatex">BibLaTeX bibliography</option> <option value="bibtex">BibTeX bibliography</option> <option value="context">ConTeXt</option> @@ -183,17 +183,24 @@ </label> </div> <input type="button" id="example" name="example" value="Use markdown example" onclick="useExample()"> - <!-- <div id="files" class="two-column"> + <div id="files" class="two-column"> <div class="left"> <label for="cb-inputfile" title="Use a file as input"> - <input type="checkbox" id="cb-inputfile" name="cb-inputfile" onchange="useInputFile()">Use file as input</label> - <form class="file" action="/input" method="post" enctype="multipart/form-data"> - <label for="inputfile">File</label> - <input id="inputfile" name="file" type="file" /> - <button>Upload</button> + <input type="checkbox" id="cb-inputfile" name="cb-inputfile" onchange="checkInputFile()">Use file as input</label> + <form id="inputfile-form" class="file" action="/input" method="post" enctype="multipart/form-data"> + <label for="inputfile">File + <input id="inputfile" name="file" type="file" /></label> + <button id="upload-button">Upload</button> </form> </div> - </div> --> + <div class="right"> + <label for="cb-outputfile" title="Use a file for output"> + <input type="checkbox" id="cb-outputfile" name="cb-outputfile" onchange="checkOutputFile()">Use file for output</label> + <div class="download"> + <a download="test.txt" href='#' id="download">Download the output file</a> + </div> + </div> + </div> </div> </details> <div class="two-column"> @@ -233,6 +240,9 @@ WIN: [ Alt ] + [ c ]" accesskey="c" onclick="copyOutput()">Copy output field [c] closeButton.addEventListener("click", () => { dialog.close(); }); + // disable form for input file + checkInputFile(); + checkOutputFile(); </script> </body> diff --git a/pandoc.php b/pandoc.php index 644be7790a02b5a22ceca1120b5380dd1c3ec08d..6bd0b1098c2e4dc778d126dc2f466ea5a6ae17ee 100644 --- a/pandoc.php +++ b/pandoc.php @@ -16,9 +16,10 @@ } // give input file a name that shouldn't collide with other users - $file = 'input/input' . microtime(true) . '.txt'; + $timestamp = microtime(true); + $inputFile = 'input/input' . $timestamp . '.txt'; // always use a file instead a string from stdin (because of security and special characters like ') - file_put_contents($file, $_POST['input']); + file_put_contents($inputFile, $_POST['input']); // run pandoc in a sandbox, limiting IO operations in readers and writers to reading the files specified on the command line. $command = 'pandoc --sandbox'; @@ -73,12 +74,21 @@ // option 'preview' should be rendered in the gui so use HTML if ($_POST['to'] == "preview") { $command .= ' --to=html5'; + // pdf - see https://pandoc.org/MANUAL#context + // you need to have context installed - see https://wiki.contextgarden.net/Installation + } elseif ($_POST['to'] == "pdf") { + $command .= ' --to=context+tagging -V pdfa=3a'; + // pdf is only working in standalone mode + if ($_POST['standalone'] == "false") {$command .= ' --standalone';} } else { $command .= ' --to=' . $_POST['to']; } - + // set output file if asked for + if ($_POST['useOutputFile'] == "true") { + $command .= ' -o output/output' . $timestamp . '.' . $_POST['outputFileExtension']; + } // always use a file instead a string from stdin (because of security and special characters like ') - $command .= ' ' . $file; + $command .= ' ' . $inputFile; // DEBUG: output error messages from cmd line if ($debug) { @@ -100,8 +110,18 @@ // execute pandoc $return = shell_exec($command); // delete input file as it is not needed anymore - unlink($file); - // put the output string back to the client - echo "$return"; + if (file_exists($inputFile)) { + unlink($inputFile); + } + + // return result + if ($_POST['useOutputFile'] == "false") { + // put the output string back to the client + echo "$return"; + } else { + // return the file binary + readfile('output/output' . $timestamp . '.' . $_POST['outputFileExtension']); + unlink('output/output' . $timestamp . '.' . $_POST['outputFileExtension']); + } } ?> diff --git a/script.js b/script.js index e107ef712c039b72a706084c8070e0887a721059..d0a95184b440da3c66fda07c267f47a24c2ebb2b 100644 --- a/script.js +++ b/script.js @@ -1,5 +1,9 @@ const urlHost = window.location.href.substr(0, window.location.href.lastIndexOf("/")); +// the following object keeps the file extension for the select option values of 'from' and 'to' +// access: value = extension["key"] +const extension = {"asciidoc_legacy": "asciidoc", "asciidoc": "asciidoc", "beamer": "tex", "biblatex": "bib", "bibtex": "bibtex", "chunkedhtml": "zip", "commonmark_x": "md", "commonmark": "md", "context": "tex", "creole": "txt", "csljson": "json", "csv": "csv", "docbook5": "xml", "docbook": "xml", "docx": "docx", "dokuwiki": "txt", "dzslides": "html", "endnotexml": "xml", "epub2": "epub", "epub3": "epub", "fb2": "fb2", "gfm": "md", "haddock": "md", "html4": "html", "html5": "html", "html": "html", "icml": "icml", "ipynb": "ipynb", "jats_archiving": "xml", "jats_articleauthoring": "xml", "jats_publishing": "xml", "jats": "xml", "jira": "txt", "json": "json", "latex": "tex", "man": "man", "markdown_mmd": "md", "markdown_phpextra": "md", "markdown_strict": "md", "markdown": "md", "markua": "md", "mediawiki": "txt", "ms": "ms", "muse": "txt", "native": "hs", "odt": "odt", "opendocument": "odf", "opml": "xml", "org": "txt", "pdf": "pdf", "plain": "txt", "pptx": "pptx", "preview": "html", "revealjs": "html", "ris": "ris", "rst": "rst", "rtf": "rtf", "s5": "html", "slideous": "html", "slidy": "html", "t2t": "t2t", "tei": "tei", "texinfo": "texi", "textile": "textile", "tikiwiki": "txt", "tsv": "tsv", "twiki": "txt", "typst": "typ", "vimwiki": "txt", "xwiki": "txt", "zimwiki": "txt"}; + function pandoc(alert) { var url = urlHost + '/pandoc.php'; if (typeof alert === 'undefined') { @@ -14,6 +18,15 @@ function pandoc(alert) { var wrap = document.getElementById('wrap').value; var highlightStyle = document.getElementById('highlight-style').value; var htmlMathMethod = document.getElementById('html-math-method').value; + // files + var useInputFile = document.getElementById('cb-inputfile').checked; + console.log(document.getElementById('from').value); + var inputFileExtension = extension[document.getElementById('from').value]; + console.log(inputFileExtension); + var useOutputFile = document.getElementById('cb-outputfile').checked; + console.log(document.getElementById('to').value); + var outputFileExtension = extension[document.getElementById('to').value]; + console.log(outputFileExtension); // content var from = document.getElementById('from').value; if (from === "none") { @@ -40,6 +53,11 @@ function pandoc(alert) { formData.append('wrap', wrap); formData.append('highlightStyle', highlightStyle); formData.append('htmlMathMethod', htmlMathMethod); + // files + formData.append('useInputFile', useInputFile); + formData.append('inputFileExtension', inputFileExtension); + formData.append('useOutputFile', useOutputFile); + formData.append('outputFileExtension', outputFileExtension); // content formData.append('from', from); formData.append('to', to); @@ -50,23 +68,41 @@ function pandoc(alert) { body: formData }) .then(response => { - if (!response.ok) { - throw new Error("HTTP error " + response.status); - } + if (!response.ok) { + throw new Error("HTTP error " + response.status); + } + console.log('response'); + if (useOutputFile) { + return response.blob(); + } else { return response.text(); + } }) - .then(text => { + .then(content => { + console.log('context'); + if (useOutputFile) { + // output as file + let blob = new Blob([content], {type: 'text/plain'}); + let download = document.getElementById('download'); + download.href = URL.createObjectURL(blob); + let timestamp = new Date().toISOString().replaceAll('T','_').replaceAll(':', '-').slice(0, 19); + download.setAttribute("download", "output_" + timestamp + "." + outputFileExtension); + // set a notice on the output field + document.getElementById("output").innerText = "Use download link above to download 'output_" + timestamp + "." + outputFileExtension + "'."; + } else { // console.log(text); if (to === "preview") { // console.log("preview"); - document.getElementById("output").innerHTML = text; + document.getElementById("output").innerHTML = content; } else { // delete all elements contents document.getElementById("output").innerHTML = ""; var node = document.createElement("pre"); document.getElementById("output").appendChild(node); - node.innerText = text; + node.innerText = content; } + } + console.log('end of fetch'); }) .catch(error => { console.log('Error fetching pandoc output: ' + error); @@ -87,6 +123,24 @@ function toggleToc() { } } +function checkInputFile() { + if (document.getElementById('cb-inputfile').checked === true) { + document.getElementById('inputfile').removeAttribute("disabled"); + document.getElementById('upload-button').removeAttribute("disabled"); + } else { + document.getElementById('inputfile').setAttribute("disabled", "disabled"); + document.getElementById('upload-button').setAttribute("disabled", "disabled"); + } +} + +function checkOutputFile() { + if (document.getElementById('cb-outputfile').checked === true) { + document.getElementById('download').setAttribute("href", "#"); + } else { + document.getElementById('download').removeAttribute("href"); + } +} + // This will return the raw HTML, but perhaps you want to do something different, // for example: recursively embed computed styles: // https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle diff --git a/style.css b/style.css index 1ab4153531f02151702e52d82b23af1d98c116f6..0abd20d7ab98ed91cc95f2e6c4f18a27bc7d5fa5 100644 --- a/style.css +++ b/style.css @@ -57,11 +57,15 @@ dialog button { a { color: #ffffff; +} + +header a { text-decoration: none; } -#output a { - text-decoration: underline; +/* kind of disabled link - text-decoration will be none automatically */ +a:not([href]) { + color: #AAAAAA; } header { @@ -237,10 +241,25 @@ input[type="file"] { background-color: inherit; } +button:disabled, input:disabled { + background-color: inherit; + color: #AAAAAA; + border-color: inherit; +} + +label:has(> input:disabled) { + color: #AAAAAA; +} + form.file { padding-top: var(--default-top-padding); } +div.download { + /* + 5px to align with the button in the left segment */ + padding-top: calc(var(--default-top-padding) + 5px); +} + #example { margin-top: var(--default-top-padding); }