Подтвердить что ты не робот

Загрузка файла в виде данных формы через расширение хром

Я загружаю файл через расширение chrome как данные формы, и мой код приведен ниже. Проблема здесь в том, что окно просмотра файлов открывается всего на секунду, а затем исчезает.
Проблема появляется только в Mac OS.

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'
  });
}
4b9b3361

Ответ 1

Немного "истории":

Вы хотите разрешить пользователю выбирать и выгружать файл из своего всплывающего окна. Но в OSX, как только открывается диалог выбора файла, всплывающее окно теряет фокус и закрывается, в результате чего его JS-контекст также будет уничтожен. Таким образом, диалог открывается и закрывается немедленно.

Это известная ошибка на MAC в течение некоторого времени.


Решение:

Вы можете переместить логику открытия диалога на фоновый рисунок, на который не влияет потеря фокуса. Из всплывающего окна вы можете отправить сообщение на справочную страницу, попросив инициировать процесс просмотра и загрузки (см. Пример кода ниже).

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();
    }
});

<суб > Заголовки:
В качестве меры предосторожности Chrome выполнит fileChooser.click() только, если это результат взаимодействия пользователя.
В приведенном выше примере пользователь нажимает кнопку во всплывающем окне, который отправляет сообщение на фоновое изображение, которое вызывает fileChooser.click();. Если вы попытаетесь назвать это программным способом, это не сработает. (Например, вызов его при загрузке документа не будет иметь никакого эффекта.) Суб >

Ответ 2

Решение ExpertSystem не работало для меня, так как это не позволило мне называть элемент в фоновом режиме script, но я придумал обходной путь, используя большую часть его кода. Если у вас нет проблемы с незначительной потерей текущей вкладки, поместите свой код background.js в контент script с соответствующими обертками передачи сообщений. Большая часть кредитов принадлежит ExpertSystem, я просто перетасовывал вещи.

Фон:

Проблема, которую мне нужно решить, заключалась в том, что я хотел разрешить загрузку JSON файла и его анализ в своем расширении через всплывающее окно. Обходной путь, который я придумал для этого, потребовал замысловатого танца из всех трех частей; сценарии всплывающих окон, фона и содержимого.

popup.js

// handler for import button
// sends a message to the content script to create the file input element and click it
$('#import-button').click(function() {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        chrome.tabs.sendMessage(tabs[0].id, {message: "chooseFile"}, function(response) {
            console.log(response.response);
        });
    });
});

content.js

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.message == "chooseFile") {
        /* Creates an `input[type="file]` */
        var fileChooser = document.createElement('input');
        fileChooser.type = 'file';

        fileChooser.addEventListener('change', function () {
            console.log("file change");
            var file = fileChooser.files[0];

            var reader = new FileReader();
            reader.onload = function(){
                var data = reader.result;
                fields = $.parseJSON(data);
                // now send the message to the background
                chrome.runtime.sendMessage({message: "import", fields: fields}, function(response) {
                    console.log(response.response);
                });
            };
            reader.readAsText(file);
            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);

        fileChooser.click();
        sendResponse({response: "fileChooser clicked"});
    }

});

background.js

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.message == "import") {
        fields = request.fields; // use the data
        sendResponse({response: "imported"});
    }
});

Причина, по которой это работает, пока другая может или не может быть вызвана тем, что элемент ввода файла создается в пределах текущей вкладки, которая сохраняется на протяжении всего процесса.