javascript - para - inspeccionar elemento teclado
Cómo cargar y enumerar directorios en firefox y chrome/chromium usando eventos de cambio y caída (1)
Los navegadores mozilla y webkit ahora permiten cargar directorios.
Cuando el directorio o directorios se seleccionan en el elemento
<input type="file">
o se sueltan en un elemento, cómo listar todos los directorios y archivos en el orden en que aparecen en el directorio real en Firefox y Chrome / Chrome, y realizar tareas en archivos cuando se han iterado todos los directorios cargados?
Puede establecer los
webkitdirectory
y
allowdirs
en el elemento
<input type="file">
;
adjunte
change
,
drop
eventos al elemento
<input type="file">
;
use
.getFilesAndDirectories()
en mozilla,
.createReader()
,
.readEntries()
en
webkit
,
Array.prototype.reduce()
,
Promise
, recursión.
La nota en firefox
drop
event no enumera la selección como un
Directory
, pero un objeto
File
que tiene un
size
0
, por lo que soltar el directorio en firefox no proporciona una representación de la carpeta soltada, incluso cuando se utiliza
event.dataTransfer.getFilesAndDirectories()
firefox también proporciona dos elementos de entrada cuando se
allowdirs
atributo
allowdirs
;
el primer elemento permite la carga de archivos individuales, el segundo elemento permite la carga de directorios.
chrome / chromium proporciona un solo elemento
<input type="file">
donde solo se pueden seleccionar uno o varios directorios, no un solo archivo.
En los directorios que contienen archivos y directorios, los directorios se leen primero.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
input[type="file"] {
width: 98%;
height: 180px;
}
label[for="file"] {
width: 98%;
height: 180px;
}
.area {
display: block;
border: 5px dotted #ccc;
text-align: center;
}
.area:after {
display: block;
border: none;
white-space: pre;
content: "Drop your files or folders here!/aOr click to select files folders";
position: relative;
left: 0%;
top: -75px;
text-align: center;
}
.drag {
border: 5px dotted green;
background-color: yellow;
}
#result ul {
list-style: none;
margin-top: 20px;
}
#result ul li {
border-bottom: 1px solid #ccc;
margin-bottom: 10px;
}
#result li span {
font-weight: bold;
color: navy;
}
</style>
</head>
<body>
<label id="dropArea" class="area">
<input id="file" type="file" directory allowdirs webkitdirectory/>
</label>
<output id="result">
<ul></ul>
</output>
<script>
var dropArea = document.getElementById("dropArea");
var output = document.getElementById("result");
var ul = output.querySelector("ul");
function dragHandler(event) {
event.stopPropagation();
event.preventDefault();
dropArea.className = "area drag";
}
function filesDroped(event) {
var webkitResult = [];
var mozResult = [];
var files;
console.log(event);
event.stopPropagation();
event.preventDefault();
dropArea.className = "area";
// do mozilla stuff
// TODO adjust, call `listDirectory()`, `listFile()`
function mozReadDirectories(entries, path) {
console.log("dir", entries, path);
return [].reduce.call(entries, function(promise, entry) {
return promise.then(function() {
return Promise.resolve(entry.getFilesAndDirectories() || entry)
.then(function(dir) {
return dir
})
})
}, Promise.resolve())
.then(function(items) {
var dir = items.filter(function(folder) {
return folder instanceof Directory
});
var files = items.filter(function(file) {
return file instanceof File
});
if (files.length) {
// console.log("files:", files, path);
files.forEach(function(file) {
console.log(file)
});
mozResult = mozResult.concat.apply(mozResult, files);
}
if (dir.length) {
// console.log(dir, dir[0] instanceof Directory);
return mozReadDirectories(dir, dir[0].path || path);
} else {
if (!dir.length) {
return Promise.resolve(mozResult).then(function(complete) {
return complete
})
}
}
})
};
function handleEntries(entry) {
let file = "webkitGetAsEntry" in entry ? entry.webkitGetAsEntry() : entry
return Promise.resolve(file);
}
function handleFile(entry) {
return new Promise(function(resolve) {
if (entry.isFile) {
entry.file(function(file) {
listFile(file, entry.fullPath).then(resolve)
})
} else if (entry.isDirectory) {
var reader = entry.createReader();
reader.readEntries(webkitReadDirectories.bind(null, entry, handleFile, resolve))
} else {
var entries = [entry];
return entries.reduce(function(promise, file) {
return promise.then(function() {
return listDirectory(file)
})
}, Promise.resolve())
.then(function() {
return Promise.all(entries.map(function(file) {
return listFile(file)
})).then(resolve)
})
}
})
function webkitReadDirectories(entry, callback, resolve, entries) {
console.log(entries);
return listDirectory(entry).then(function(currentDirectory) {
console.log(`iterating ${currentDirectory.name} directory`, entry);
return entries.reduce(function(promise, directory) {
return promise.then(function() {
return callback(directory)
});
}, Promise.resolve())
}).then(resolve);
}
}
// TODO: handle mozilla directories, additional directories being selected dropped and listed without
// creating nested list at `html` where different directory selected or dropped
function listDirectory(entry) {
console.log(entry);
var path = (entry.fullPath || entry.webkitRelativePath.slice(0, entry.webkitRelativePath.lastIndexOf("/")));
var cname = path.split("/").filter(Boolean).join("-");
console.log("cname", cname)
if (!document.getElementsByClassName(cname).length) {
var directoryInfo = `<li><ul class=${cname}>
<li>
<span>
Directory Name: ${entry.name}<br>
Path: ${path}
<hr>
</span>
</li></ul></li>`;
var curr = document.getElementsByTagName("ul");
var _ul = curr[curr.length - 1];
var _li = _ul.querySelectorAll("li");
if (!document.querySelector("[class*=" + cname + "]")) {
if (_li.length) {
_li[_li.length - 1].innerHTML += `${directoryInfo}`;
} else {
_ul.innerHTML += `${directoryInfo}`
}
} else {
ul.innerHTML += `${directoryInfo}`
}
}
return Promise.resolve(entry);
}
// TODO: handle mozilla files
function listFile(file, path) {
path = path || file.webkitRelativePath || "/" + file.name;
var filesInfo = `<li>
Name: ${file.name}</br>
Size: ${file.size} bytes</br>
Type: ${file.type}</br>
Modified Date: ${file.lastModifiedDate}<br>
Full Path: ${path}
</li>`;
var currentPath = path.split("/").filter(Boolean);
currentPath.pop();
var appended = false;
var curr = document.getElementsByClassName(`${currentPath.join("-")}`);
if (curr.length) {
for (li of curr[curr.length - 1].querySelectorAll("li")) {
if (li.innerHTML.indexOf(path.slice(0, path.lastIndexOf("/"))) > -1) {
li.querySelector("span").insertAdjacentHTML("afterend", `${filesInfo}`);
appended = true;
break;
}
}
if (!appended) {
curr[curr.length - 1].innerHTML += `${filesInfo}`;
}
}
console.log(`reading ${file.name}, size: ${file.size}, path:${path}`);
webkitResult.push(file);
return Promise.resolve(webkitResult)
};
function processFiles(files) {
Promise.all([].map.call(files, function(file, index) {
return handleEntries(file, index).then(handleFile)
}))
.then(function() {
console.log("complete", webkitResult)
})
.catch(function(err) {
alert(err.message);
})
}
if ("getFilesAndDirectories" in event.target) {
return (event.type === "drop" ? event.dataTransfer : event.target).getFilesAndDirectories()
.then(function(dir) {
if (dir[0] instanceof Directory) {
console.log(dir)
return mozReadDirectories(dir, dir[0].path || path)
.then(function(complete) {
console.log("complete:", complete);
event.target.value = null;
});
} else {
if (dir[0] instanceof File && dir[0].size > 0) {
return Promise.resolve(dir)
.then(function(complete) {
console.log("complete:", complete);
})
} else {
if (dir[0].size == 0) {
throw new Error("could not process ''" + dir[0].name + "'' directory"
+ " at drop event at firefox, upload folders at ''Choose folder...'' input");
}
}
}
}).catch(function(err) {
alert(err)
})
}
// do webkit stuff
if (event.type === "drop" && event.target.webkitdirectory) {
files = event.dataTransfer.items || event.dataTransfer.files;
} else if (event.type === "change") {
files = event.target.files;
}
if (files) {
processFiles(files)
}
}
dropArea.addEventListener("dragover", dragHandler);
dropArea.addEventListener("change", filesDroped);
dropArea.addEventListener("drop", filesDroped);
</script>
</body>
</html>