function initFields() { $('#upload-file').filestyle('clear'); $(':input','#filesubmit') .removeAttr('checked') .removeAttr('selected') .not(':button, :submit, :reset, :hidden, :radio, :checkbox') .val(''); $('.container') .removeClass("opt") .removeClass("no-cert"); $(".winmsg").addClass("hidden"); $('Select').val('0'); $('#flash-messages').empty(); $("#image").empty(); $("#maininfo").empty(); $('#qrcode').empty(); } /*jslint vars: true browser: true*/ /*global $, jQuery, alert, FileReader, FormData*/ /* * Handle the file/url upload UI. Close */ function handleLevelSelectedUI($uploadfile, $uploadurl) { "use strict"; // File Upload style plugin : http://markusslima.github.io/bootstrap-filestyle/ $uploadfile.filestyle({buttonBefore: true, buttonName: "btn-primary", buttonText: " Choose a level file", badge: false, placeholder: "No file"}); var $filestyle = $uploadfile.next('.bootstrap-filestyle'), x_html = '×'; $uploadfile.on('change', function () { $('#dismiss-upload').remove(); $(x_html).appendTo($filestyle); $uploadurl.slideUp(); $uploadurl.find("input").val(""); $('#dismiss-upload').on('click', function () { $uploadfile.filestyle('clear'); $uploadurl.slideDown(); initFields(); $(this).remove(); }); }); } // apply automatically to pages using the standard names (function () { "use strict"; var $uploadfile = $("#upload-file"), $uploadurl = $("#upload-url"); if ($uploadfile.length === 1 && $uploadurl.length === 1) { handleLevelSelectedUI($uploadfile, $uploadurl); } }()); function validateJSON(file) { try { var fileReader = new FileReader(); fileReader.onload = function (fileLoadedEvent) { var textFromFileLoaded = fileLoadedEvent.target.result; var data = JSON.parse(textFromFileLoaded); }; fileReader.readAsText(file, "UTF-8"); // if came to here, then valid return true; } catch(e) { // failed to parse return false; } } /* Guess whether a file is "image", "json", or "unknown" mime type */ function fileType(file) { "use strict"; // console.log(file); if (file.type.startsWith("image/")) { return "image"; // } else if (file.type.indexOf("json") !== -1) { } else if (validateJSON(file)) { return "json"; } else { return "unknown"; } } /* Create a jQuery image object from file data */ function imageFromFile(file) { "use strict"; if (!file.type.match(/^image/)) { throw "File Type must be an image"; } var $img = $("", { "class": 'img-responsive' }); // Using FileReader to display the image content var reader = new FileReader(); reader.onload = (function (aImg) { return function (e) { aImg.attr('src', e.target.result); }; }($img)); reader.readAsDataURL(file); return $img; } /* Create a jQuery image object with a src url */ function imageFromURL(src) { "use strict"; var $img = $("", { "class": 'img-responsive', "src": src }); return $img; } /* Upload a file to the specified URL * Returns a deferred object that will receive the level json upon resolution */ function uploadFile(url, file) { "use strict"; var deferredLevel = jQuery.Deferred(); var xhr = new XMLHttpRequest(); var fd = new FormData(); xhr.open("POST", url, true); xhr.onreadystatechange = (function (deferred) { return function () { if (xhr.readyState === 4) { if (xhr.status === 200) { // Every thing ok, file uploaded //console.log(xhr.responseText); // handle response. var levelJson = xhr.responseText; var level = JSON.parse(levelJson); deferred.resolve(level); } else { deferred.reject(xhr.responseText); } } }; }(deferredLevel)); fd.append("file", file); xhr.send(fd); return deferredLevel; } /* * uploadFile: DOM object of the upload-file input * imageCallback: function($img) called immediately upon upload with a jQuery image tag * jsonCallback: function(json) called after the upload finishes with the reponse JSON * * throws error strings if no files selected or unsupported file format */ function handleLevelSelectedFile(files, imageCallback, jsonCallback) { "use strict"; if (!files || files.length < 1) { throw "No file specified"; } var $img, src, ftype = fileType(files[0]); // console.log(ftype); // Fast client-side response switch (ftype) { case "image": // If image, display client-side $img = imageFromFile(files[0]); $("#maininfo").empty().text("Parsing level..."); // Begin upload uploadFile("/decode.json", files[0]) .then(jsonCallback) .done(function(){ imageCallback($img); }) .fail(function (err) { var data = JSON.parse(err); if (data.hasOwnProperty('message')) { flash_message(data.message, 'danger'); } }); break; default: try { // JSON? We need to load asynchronously the file (onload) var fileReader = new FileReader(); fileReader.onload = function (fileLoadedEvent) { // This part is not sequencial so when need to do this from inside var textFromFileLoaded = fileLoadedEvent.target.result; var data = JSON.parse(textFromFileLoaded); // No image file so a random one if (Math.random() < 0.5) { src = "/static/images/JSON_Upload_brackets.png"; } else { src = "/static/images/JSON_Upload_escher.png"; } $img = imageFromURL(src); $("#maininfo").empty().text("Parsing level..."); // Begin upload uploadFile("/decode.json", files[0]) .then(jsonCallback) .done(function(){ imageCallback($img); }) .fail(function (err) { var data = JSON.parse(err); if (data.hasOwnProperty('message')) { flash_message(data.message, 'danger'); } }); }; fileReader.readAsText(files[0], "UTF-8"); } catch(e) { throw "Unsupported file format"; } } } /* * uploadFile: DOM object of the upload-file input * imageCallback: function($img) called immediately upon upload with a jQuery image tag * jsonCallback: function(json) called after the upload finishes with the reponse JSON * * throws error strings if no files selected or unsupported file format */ function handleLevelSelectedUrl(src, imageCallback, jsonCallback, errorCallback) { "use strict"; var $img = imageFromURL(src); imageCallback($img); // Fetch level var data = { "upload-url": src, "name": "file", "filename": "" } //jQuery.post("/decode.json", data, jsonCallback, "json"); $.post("/decode.json", data, jsonCallback, "json") .fail(function() { flash_message("Sorry, an error occurred... :(", "danger"); if (errorCallback) {errorCallback();} }); } /* Create a collapsible button and div * id: ID for the collabsible div. must be unique * header: Text for the button * contents: jQuery object with the contents */ function mkCollapsable(id, header, contents) { "use strict"; var $button = $("", { "data-toggle": "collapse", "data-target": "#" + id, "class": "btn btn-primary" }).text(header); // var $scroller = $("
")
    //   .addClass("pre-scrollable")
    //   .text(contents);
    // var $innerDiv = $("
").addClass("panel-body").append($scroller); var $innerDiv = $("
").addClass("panel-body").append(contents); var $contentDiv = $("
", { "id": id, "class": "collapse panel panel-default" }).append($innerDiv); return $("
").append($button, $contentDiv); } function flash_message(message, category) { category = category || 'info' var flash = ''; $('#flash-messages').append(flash); } $("#filesubmit").submit(function( event ) { // Stop form from submitting normally event.preventDefault(); // Get some values from elements on the page: var $form = $( this ), dataform = new FormData($form[0]), url = $form.attr( "action" ); $('#flash-messages').empty(); $qrcode = $('#qrcode'); $qrcode.html('

Loading...

'); var startDownload = false; var $pgDownload = undefined; var $gencode = $("#gencode"); $gencode.prop('disabled', true); var sendxhr = $.ajax({ xhr: function() { var xhr = new window.XMLHttpRequest(); // Upload progress xhr.upload.addEventListener("progress", function(evt){ if (evt.lengthComputable) { var percentComplete = Math.ceil(100 * evt.loaded / evt.total); if (percentComplete < 100) { $gencode.val('Sending card... '+percentComplete+'%'); } else { $gencode.val('Processing...'); } } }, false); // Download progress xhr.addEventListener("progress", function(evt){ if (evt.lengthComputable) { if (!startDownload) { pg = '
'; $qrcode.html(pg); $pgDownload = $("#qrcode > .progress > div"); } startDownload = true; var percentComplete = Math.ceil(100 * evt.loaded / evt.total); $pgDownload.css('width', percentComplete+'%').attr('aria-valuenow', percentComplete); $gencode.val('Downloading... '+percentComplete+'%'); } }, false); return xhr; }, url: url, type: 'POST', // Form data data: dataform, // Tell jQuery not to process data or worry about content-type // You *must* include these options! cache: false, contentType: false, processData: false, // timeout: 10000 }) .done(function (data) { console.log('JSON: POST success, now analysing answer'); // console.log(data); if (data) { if (data.qrcode ) { var qrcode = data.qrcode; if (qrcode.match('^{.*}$')) { var msg = JSON.parse(qrcode); flash_message(msg.message, msg.category); qrcode = '

Error...

'; } $qrcode.html(qrcode); } else { var msg = JSON.parse(data); flash_message(msg.message, msg.category); $qrcode.empty(); } } }) .fail(function (jqXHR, textStatus, error) { var err = textStatus + ', ' + error; console.log('JSON: request failed: ' + err); data = '

Error...

'; $qrcode.html(data); jqXHR.abort(); }) .always(function() { console.log('JSON: complete'); $gencode.val('Generate').prop('disabled', false); }); });