1
\$\begingroup\$

I recently wrote a small demo that allows users to send and receive files from an HTML5 Javascript application. It's all client-side. I thought this would be a good place to get feedback about what I've done.

It's hosted here: http://danielsadventure.info/HTML5FileDemo/

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <title>HTML5 File Upload Demo With Saxon-CE and ACE</title>
 <style>
 /* ACE won't work without explicit CSS. */
 .aceEditor
 {
 position: relative;
 width: 500px;
 height: 200px;
 }
 </style>
 <script src='Scripts/ace/ace.js'></script>
 <script src='Scripts/saxon-ce/Saxonce.nocache.js'></script>
 <!--
 FileSaver.js is an open-source Javascript project that provides support for the HTML5 FileSaver API
 on browsers that do not natively support it.
 -->
 <script src='Scripts/FileSaver.js'></script>
</head>
<body>
 Input XML
 <br />
 <div class='aceEditor' id='aceInputXml' style='float:left;'>&lt;test&gt;
 &lt;testing&gt;
 1 2 3
 &lt;/testing&gt;
&lt;/test&gt;</div>
 <div>
 To input XML, drag-and-drop a file into the text editor to the left,
 use the file input below, or key XML into the text editor.
 <br />
 <input id='xmlFileInput' type='file' />
 </div>
 <br style='clear:both;' />
 Input XSLT 
 <br />
 <div class='aceEditor' id='aceInputXslt' style='float:left;'>&lt;!-- 
 Note: This sample XSLT is an "identity" transformation.
 The result of applying this transformation to a document should be the original document.
--&gt;
&lt;xsl:stylesheet version=&quot;1.0&quot;
 xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
 &lt;xsl:template match=&quot;node()|@*&quot;&gt;
 &lt;xsl:copy&gt;
 &lt;xsl:apply-templates select=&quot;node()|@*&quot;/&gt;
 &lt;/xsl:copy&gt;
 &lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;</div>
 <div>
 To input XSLT, drag-and-drop a file into the text editor to the left,
 use the file input below, or key XSLT into the text editor.
 <br />
 <input id='xsltFileInput' type='file' />
 </div>
 <br style='clear:both;' />
 Output
 <div class='aceEditor' id='aceOutputXml'></div> 
 <br />
 <input type='button' id='btnTransform' value='Transform' /> 
 <input type='button' id='btnSave' value='Save' />
</body>
<script>
 (function () {
 'use strict';
 var aceInputXml, aceInputXslt, aceOutputXml, editors, saxon;
 setupAce();
 setupFileDragAndDrop();
 setupFileInput();
 setupFileDownload();
 setupSaxonce();
 // Initialize the ACE editors and save their object references.
 function setupAce() {
 var x;
 aceInputXml = ace.edit('aceInputXml');
 aceInputXslt = ace.edit('aceInputXslt');
 aceOutputXml = ace.edit('aceOutputXml');
 editors = [aceInputXml, aceInputXslt, aceOutputXml];
 for (x in editors) {
 editors[x].setTheme('ace/theme/monokai');
 editors[x].getSession().setMode('ace/mode/xml');
 }
 }
 // Rig up the Input XML and Input XSLT ACE editors so that the user can populate them
 // by dragging and dropping a file that contains XML.
 function setupFileDragAndDrop() {
 var inputXml, inputXslt;
 inputXml = document.getElementById('aceInputXml');
 inputXslt = document.getElementById('aceInputXslt');
 addFileDragAndDropEventListeners(inputXml, aceInputXml);
 addFileDragAndDropEventListeners(inputXslt, aceInputXslt);
 function addFileDragAndDropEventListeners(aceInputDiv, aceObject) {
 aceInputDiv.addEventListener('dragover', function (e) {
 stopEvent(e);
 });
 aceInputDiv.addEventListener('drop', function (e) {
 putFileContentsInAceEditor(e.dataTransfer.files[0], aceObject);
 stopEvent(e);
 });
 function stopEvent(e) {
 e.stopPropagation();
 e.preventDefault();
 }
 } // end addFileDragAndDropEventListeners
 } // end setupFileDragAndDrop 
 // Set up the HTML5 file inputs so that the user can populate the ACE editors
 // by selecting a file.
 function setupFileInput() {
 (function () {
 var xmlFileInput;
 xmlFileInput = document.getElementById('xmlFileInput');
 xmlFileInput.addEventListener('change', function (e) {
 var file;
 file = e.srcElement.files[0];
 putFileContentsInAceEditor(file, aceInputXml);
 });
 })();
 (function () {
 var xsltFileInput;
 xsltFileInput = document.getElementById('xsltFileInput');
 xsltFileInput.addEventListener('change', function (e) {
 var file;
 file = e.srcElement.files[0];
 putFileContentsInAceEditor(file, aceInputXslt);
 });
 })();
 }
 // Setup the button that the user can click to download the output.
 function setupFileDownload() {
 var button;
 button = document.getElementById('btnSave');
 button.addEventListener('click', function (e) {
 var outputXmlStr, blob;
 outputXmlStr = aceOutputXml.getSession().getValue();
 // If the string is null or empty, do nothing.
 if (!outputXmlStr)
 return;
 blob = new Blob([outputXmlStr], { type: 'text/plain' });
 // Use the FileSaver.js interface to download the file.
 saveAs(blob, 'Output.xml');
 });
 }
 // A small function that takes a file and an ACE editor object.
 // The function reads the file and copies its contents into the ACE editor.
 function putFileContentsInAceEditor(file, aceEditor) {
 var reader, text;
 reader = new FileReader();
 reader.onload = (function (file) {
 text = file.target.result;
 aceEditor.getSession().setValue(text);
 });
 reader.readAsText(file);
 }
 function setupSaxonce() {
 // This object is required by Saxon.
 // Saxon will automatically invoke this function when it loads.
 window.onSaxonLoad = function () {
 saxon = Saxon;
 setupTransformButton(Saxon);
 };
 }
 // Note that this gets called when setupSaxonce runs.
 // This ensures that the Saxon object is available when the user clicks the [Transform] button.
 function setupTransformButton(Saxon) {
 var button;
 button = document.getElementById('btnTransform');
 button.addEventListener('click', function (e) {
 var inputXmlStr, inputXsltStr, outputXmlStr,
 inputXmlDoc, inputXsltDoc, outputXmlDoc, processor;
 // Get the input XML and XSLT strings from the ACE editors.
 inputXmlStr = aceInputXml.getSession().getValue();
 inputXsltStr = aceInputXslt.getSession().getValue();
 // Transform the inputs into Saxon XML documents.
 inputXmlDoc = Saxon.parseXML(inputXmlStr);
 inputXsltDoc = Saxon.parseXML(inputXsltStr);
 // Get an XSLT20Processor object that will apply the transformation.
 processor = Saxon.newXSLT20Processor(inputXsltDoc);
 // Apply the transformation.
 outputXmlDoc = processor.transformToDocument(inputXmlDoc);
 outputXmlStr = Saxon.serializeXML(outputXmlDoc);
 // Put the results of the transformation in the output ACE editor.
 aceOutputXml.getSession().setValue(outputXmlStr);
 });
 }
 })(); 
</script>
</html>
asked Nov 12, 2013 at 23:26
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Your code looks fine to me,

I would probably have aceInputXml, aceInputXslt and aceOutputXml be properties of 'editors'.

Then you could slightly rewrite setupAce as

function setupAce() 
{
 var key;
 editors = 
 {
 InputXml : ace.edit('aceInputXml'),
 InputXslt : ace.edit('aceInputXslt'),
 OutputXml : ace.edit('aceOutputXml')
 }
 for (key in editors)
 {
 editors[key].setTheme('ace/theme/monokai');
 editors[key].getSession().setMode('ace/mode/xml');
 }
}

In setupFileDragAndDrop you could probably make it so that you dont have to re-use the id's like 'aceInputXml' again ( DRY ). Also you should consider putting stopEvent out of addFileDragAndDropEventListeners, since you will now have 2 stopEvent functions ?

setupFileInput contains 50% copy pasted code, not DRY.

setupTransformButton contains a lot of declarations and assignments that could be merged. Also since you don't keep the button value around you could simply replace

function setupTransformButton(Saxon) {
 var button;
 button = document.getElementById('btnTransform');
 button.addEventListener('click', function (e) {
 var inputXmlStr, inputXsltStr, outputXmlStr,
 inputXmlDoc, inputXsltDoc, outputXmlDoc, processor;
 // Get the input XML and XSLT strings from the ACE editors.
 inputXmlStr = aceInputXml.getSession().getValue();
 inputXsltStr = aceInputXslt.getSession().getValue();
 // Transform the inputs into Saxon XML documents.
 inputXmlDoc = Saxon.parseXML(inputXmlStr);
 inputXsltDoc = Saxon.parseXML(inputXsltStr);
 // Get an XSLT20Processor object that will apply the transformation.
 processor = Saxon.newXSLT20Processor(inputXsltDoc);
 // Apply the transformation.
 outputXmlDoc = processor.transformToDocument(inputXmlDoc);
 outputXmlStr = Saxon.serializeXML(outputXmlDoc);
 // Put the results of the transformation in the output ACE editor.
 aceOutputXml.getSession().setValue(outputXmlStr);
 });
 }

with

function setupTransformButton(Saxon)
{
 document.getElementById('btnTransform').addEventListener('click', function (e) 
 {
 /* Get the input XML and XSLT strings from the ACE editors. */
 var inputXmlStr = aceInputXml.getSession().getValue(), 
 inputXsltStr = aceInputXslt.getSession().getValue(); 
 /* Transform the inputs into Saxon XML documents. */
 var inputXmlDoc = Saxon.parseXML(inputXmlStr),
 inputXsltDoc = Saxon.parseXML(inputXsltStr);
 /* Get an XSLT20Processor object that will apply the transformation */
 var processor = Saxon.newXSLT20Processor(inputXsltDoc);
 /* Apply the transformation */
 var outputXmlDoc = processor.transformToDocument(inputXmlDoc),
 outputXmlStr = Saxon.serializeXML(outputXmlDoc);
 /* Put the results of the transformation in the output ACE editor. */
 aceOutputXml.getSession().setValue(outputXmlStr);
 });
}

After writing this, I guess it really is a matter of taste, something to consider rather than a hard rule.

answered Nov 12, 2013 at 23:44
\$\endgroup\$
-1
\$\begingroup\$

I'm just changed a bit, to get local file is running!

 function setupFileInput(evt) {
 (function () {
 var xmlFileInput;
 xmlFileInput = document.getElementById('xmlFileInput');
 xmlFileInput.addEventListener('change', function (evt) {
 var file;
 file = evt.target.files[0];
 putFileContentsInAceEditor(file, aceInputXml);
 });
 })();
 (function () {
 var xsltFileInput;
 xsltFileInput = document.getElementById('xsltFileInput');
 xsltFileInput.addEventListener('change', function (evt) {
 var file;
 file = evt.target.files[0];
 putFileContentsInAceEditor(file, aceInputXslt);
 });
 })();
 }

Tested in mozilla firefox v.42.0

answered Dec 29, 2017 at 9:28
\$\endgroup\$
2
  • 4
    \$\begingroup\$ Please, don't just rewrite the code. CodeReview is about providing feedback and explaining better practices. \$\endgroup\$ Commented Dec 29, 2017 at 9:36
  • \$\begingroup\$ What do you mean by "to get local file is running" ? Is that some sort of improvement over the original code? Can you please explain what is the advice you are giving here? \$\endgroup\$ Commented Dec 29, 2017 at 16:26

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.