Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload File as a Form Data through chrome extension

I am uploading a file through chrome extension as a form data and my code follows below. The problem here is that the file browsing window opens for just a second and then disappears.
The issue appears in Mac OS only.

manifest.json:

"background": {   "scripts": ["jszip.js", "background.js"] }, 

background.js:

chrome.runtime.onMessage.addListener(function (msg) {   if (msg.action === 'browse')   {     var myForm=document.createElement("FORM");     var myFile=document.createElement("INPUT");     myFile.type="file";     myFile.id="selectFile";     //myFile.onclick="openDialog()";     myForm.appendChild(myFile);     var myButton=document.createElement("INPUT");     myButton.name="submit";     myButton.type="submit";     myButton.value="Submit";     myForm.appendChild(myButton);     document.body.appendChild(myForm);   } }); 

popup.js:

window.onload = function () {   chrome.runtime.sendMessage({     action: 'browse'   }); } 
like image 675
Arvind Anandala Avatar asked Jan 15 '14 09:01

Arvind Anandala


People also ask

Can Chrome extensions collect data?

Starting next year, Chrome extensions will show what data they collect from users. Google will add a "Privacy practices" section on each Chrome extension's Web Store page listing what data they collect from users and what the developer plans to do with it.


1 Answers

A little "background story":

You want to let the user choose and upload a file from your popup. But in OSX, as soon as the file-chooser dialog opens, the popup loses focus and closes, causing its JS context to get destroyed as well. Thus, the dialog opens and closes immediately.

This is a known bug on MAC for quite some time.


The solution:

You can move the dialog opening logic to the background-page, which is not affected by loss of focus. From the popup, you can send a message to the background-page, requesting to initiate the browse-and-upload process (see sample code below).

manifest.json

{     ...     "background": {         "persistent": false,         "scripts": ["background.js"]     },      "browser_action": {         "default_title": "Test Extension", //        "default_icon": { //            "19": "img/icon19.png", //            "38": "img/icon38.png" //        },         "default_popup": "popup.html"     },      "permissions": [         "https://www.example.com/uploads"         // The above permission is needed for cross-domain XHR     ] } 

popup.html

    ...     <script src="popup.js"></script> </head> <body>     <input type="button" id="button" value="Browse and Upload" />     ... 

popup.js

document.addEventListener('DOMContentLoaded', function () {     document.getElementById('button').addEventListener('click', function () {         chrome.runtime.sendMessage({ action: 'browseAndUpload' });         window.close();     }); }); 

background.js

var uploadUrl = 'https://www.example.com/uploads';  /* Creates an `input[type="file]` */ var fileChooser = document.createElement('input'); fileChooser.type = 'file'; fileChooser.addEventListener('change', function () {     var file = fileChooser.files[0];     var formData = new FormData();     formData.append(file.name, file);      var xhr = new XMLHttpRequest();     xhr.open('POST', uploadUrl, true);     xhr.addEventListener('readystatechange', function (evt) {         console.log('ReadyState: ' + xhr.readyState,                     'Status: ' + xhr.status);     });      xhr.send(formData);     form.reset();   // <-- Resets the input so we do get a `change` event,                     //     even if the user chooses the same file });  /* Wrap it in a form for resetting */ var form = document.createElement('form'); form.appendChild(fileChooser);  /* Listen for messages from popup */ chrome.runtime.onMessage.addListener(function (msg) {     if (msg.action === 'browseAndUpload') {         fileChooser.click();     } }); 

Heads up:
As a security precaution, Chrome will execute fileChooser.click() only if it is a result of user interaction.
In the above example, the user clicks the button in the popup, which sends a message to the background-page, which calls fileChooser.click();. If you try to call it programmatically it won't work. (E.g. calling it on document load won't have any effect.)

like image 144
gkalpak Avatar answered Sep 19 '22 08:09

gkalpak