Search code examples
javascriptjquerygoogle-chromegoogle-chrome-extension

Chrome extension file upload browse window position off screen


I am having an issue with the file browse dialog window appearing off the screen on a Mac when attempting to upload a file within a Google Chrome extension I am developing. Does anyone have any ideas as to how to reposition the dialog window or append the file upload to the main window so it centers with that window? I followed this question to do my uploads. Any help appreciated! Thank you!

My manifest.json:

{
  "manifest_version": 2,

  "name": "Bookmark and Binder",
  "description": "example",
  "version": "1.0",

  "browser_action": {
   "default_icon": "icon.png",
   "default_popup": "/index.html"
  },
  "permissions": [
   "activeTab",
    "cookies",
    "http://example.com/"
   ]
}

A small part of index.html:

<div class="form-group chooseFile" id="showUpload" style="display:none">
                    <label>File Upload: </label>
                    <button type="button" id="uploadButton" class="btn btn-primary">Browse and Upload</button>
                </div>

On dom ready:

$('#uploadButton').on('click', function(){
    chrome.runtime.sendMessage({ action: 'browseAndUpload' });
  });

The rest of the script:

//background script

/* Creates an `input[type="file]` */
var fileChooser = document.createElement('input');
fileChooser.type = 'file';
fileChooser.multiple = "multiple";

fileChooser.addEventListener('change', function () {
    var files = fileChooser.files;
    var formData = new FormData();
    var inst = $.jstree.reference(newData.reference),
    obj = inst.get_node(newData.reference);
    var uploadURL = apiHost + '/binder/upload?location=' + obj.id;

    formData.append('location', obj.id);
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      formData.append('uploads', file, file.name);
    }

    var xhr = new XMLHttpRequest();
    xhr.open('POST', uploadURL, true);

    $('#createModal').one('hidden.bs.modal', function(){
      $('body').width('auto');
    })

    xhr.onload = function () {
    if (xhr.status === 200) {
        // File(s) uploaded.
        //uploadButton.innerHTML = 'Upload';
        var inst = $.jstree.reference(newData.reference),
        obj = inst.get_node(newData.reference);

        $('#createModal').modal('hide');
        inst.refresh();
      } else {
        alertEvent("Failure","Please try again later.")
      }
    };

    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') {
        $('body').width('1000px'); //attempt to move the dialog window
        fileChooser.click();
    }
});

Solution

  • Unfortunately there isn't much you can do to make the dialog show in the main window. The user filesystem is sensitive so the browser has several security measures to prevent an scripted upload, that means no dirty tricks here.

    So I'd recommend you to pick a different approach to be able to provide a good user experience for uploading a file even from the extension popup.

    One possibility is to make use of the browserAction popup as a drag and drop zone for your files. It's pretty simple to achieve it, like I demonstrate in this fiddle:

    http://jsfiddle.net/Lv1nj58p/1/

    HTML

    <div id="file-container">
        <b>DRAG YOUR FILES HERE</b>
        <input id="file" type="file"  multiple="multiple"/>
    </div>
    

    CSS

    #file-container {
        border:2px dashed #aaa;
        background:#eee;
        position:relative;
        width:200px;
        text-align:center;
        padding:20px;
        border-radius:8px;
        font-family:sans-serif;
    }
    
    #file {
        position:absolute;
        opacity:0;
        background:magenta;
        top:0;
        left:0;
        right:0;
        bottom:0;
    }
    

    This fiddle is very raw but if you throw that code in your index.html you'll see what I'm suggesting. One downside is, that to properly use the drag drop concept for file input, there is several events that needs to be handled in order to provide visual feedback when one or more files are selected. Fortunately, there are several libraries with that purpose; A good one is is Dropzone.js.

    Sadly that's more an alternative than a straight answer. I hope that this solution fits well in your context!

    Last but not least, the behavior that you described sounds like a bug to me (probably OS X specific). Feel free to file an issue to the chrome team so they can tell you if is that something buggy or ugly, i.e if it's something that they're going to fix or not.