How to force download of local information in the browser? [duplicate]

3

I'm trying to do something like this:

$('button').on('click', function() {

  obj = {};
   
  $('pseudoform').find('input,textarea').each(function() {
    obj[$(this).attr('name')] = String($(this).val());
  });

  json = JSON.stringify(obj);
  
  $('input[name=proof]').val(json);
  
  alert('Queria que baixasse: ' + json);

});
textarea,
input,
button {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><pseudoform><label>Titulo:<inputtype="text" name="title" value="um valor">
  </label>

  <label>Descrição:
    <textarea name="desc">qualquer</textarea>
  </label>

  <input type="hidden" value="123456" name="challenge">
  <input type="hidden" value="999999" name="nonce">

</pseudoform>

<form target="#">

  <input type="hidden" value="{valor aqui}" name="proof">
  <button>Baixar</button>

</form>

The idea is that value of proof is dynamically defined with a json. This json would have the values of all the inputs that exist on top of it, within pseudoform .

The other step would be for the user to download the content by clicking the "download" button, this is the issue .

How can I make Javascript in the browser force the user to download this content ( {"title":"um valor","desc":"qualquer","challenge":"123456","nonce":"999999"} ) when they click "download"?

The reason for the user to download what he writes is that I need the user to sign the content using OpenGPG, with some smartcard. The server should only receive the json information (which is in the input) and the signature ( armored detached signature file ) of this json.

    
asked by anonymous 03.07.2017 / 20:47

2 answers

4

For compatibility reasons Internet Explorer use navigator.msSaveBlob , another important point is to note that some browsers do not support the download attribute in some situations, such as cross-domain , but I do not think I influence the case, I just quoted as informative.

Also, if the download attribute is not recognized, perhaps because it is an older browser or other behavior, in this case it would be interesting to use mime-type application/octet-stream which may help, an important detail of this is that on some mobile devices

An example would be something like:

function downloadData(name, data, nw) {

    //Internet Explorer
    if (navigator.msSaveBlob) {
        var blob = new Blob([data]); //Aplica o conteúdo para baixar
        navigator.msSaveBlob(blob, name); //Nome do arquivo
        return;
    }

    var body = document.body;

    var uridown = "data:application/octecstream," + encodeURIComponent(data);

    var el = document.createElement("a"); //Cria o link

    el.download = name; //Define o nome

    el.href = uridown; //Define a url

    //Adiciona uma classe css pra ocultar
    el.className = "hide-link";

    //Força abrir em uma nova janela
    if (nw) {
        el.target = "_blank";
    }

    //Adiciona no corpo da página (necessário para evitar comportamento variado em diferentes navegadores)
    body.appendChild(el);

    if (el.fireEvent) {
        //Simula o click pra navegadores com suporte ao fireEvent
        el.fireEvent("onclick");
    } else {
        //Simula o click com MouseEvents
        var evObj = document.createEvent("MouseEvents");
        evObj.initEvent("click", true, false);
        el.dispatchEvent(evObj);
    }

    //Remove o link da página
    setTimeout(function() {
        body.removeChild(el);
    }, 100);
}

In CSS add this (do not use iOS behavior may vary in different browsers):

.hide-link {
   position: absolute;
   top: -9999px;
   left: -9999px;
}

Using the script:

json = JSON.stringify(obj);

$('input[name=proof]').val(json);

downloadData('meujson.json', json);

In order to avoid piling, I recommend that you prefer to try opening in a new page / tab like this:

downloadData('meujson.json', json, true);

Example

Test the example:

downloadData("foo.json", '{ "foo": "bar" }', true);

function downloadData(name, data, nw) {

    //Internet Explorer
    if (navigator.msSaveBlob) {
        var blob = new Blob([data]); //Aplica o conteúdo para baixar
        navigator.msSaveBlob(blob, name); //Nome do arquivo
        return;
    }

    var body = document.body;

    var uridown = "data:application/octecstream," + encodeURIComponent(data);

    var el = document.createElement("a"); //Cria o link

    el.download = name; //Define o nome

    el.href = uridown; //Define a url

    //Adiciona uma classe css pra ocultar
    el.className = "hide-link";

    //Força abrir em uma nova janela
    if (nw) {
        el.target = "_blank";
    }

    //Adiciona no corpo da página (necessário para evitar comportamento variado em diferentes navegadores)
    body.appendChild(el);

    if (el.fireEvent) {
        //Simula o click pra navegadores com suporte ao fireEvent
        el.fireEvent("onclick");
    } else {
        //Simula o click com MouseEvents
        var evObj = document.createEvent("MouseEvents");
        evObj.initEvent("click", true, false);
        el.dispatchEvent(evObj);
    }

    //Remove o link da página
    setTimeout(function() {
        body.removeChild(el);
    }, 100);
}
.hide-link {
   position: absolute;
   top: -9999px;
   left: -9999px;
}
    
04.07.2017 / 21:36
4

You can use a <a> tag with the download so you can force the download of json you want, passing a blob as the href, next to the appropriate mime type. Here's an example below:

var btn  = document.getElementById('btnDownload');

	btn.addEventListener('click', function(){
		var obj  = {"id":1, "name": "Lorem"};  
	  	var data = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));
		var a = document.getElementById('aDownload');
		a.setAttribute("href",data);
		a.setAttribute("download", "data.json");
		a.click();
	});
<a id="aDownload" style="display: none;"></a>
<button id="btnDownload">Baixar</button>
    
03.07.2017 / 21:50