Загрузка файла в виде данных формы через расширение хром
Я загружаю файл через расширение 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'
});
}
Ответы
Ответ 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"});
}
});
Причина, по которой это работает, пока другая может или не может быть вызвана тем, что элемент ввода файла создается в пределах текущей вкладки, которая сохраняется на протяжении всего процесса.