Integración de input[type=file] con la API de Filesystem

Supongamos que tienes una app de edición de fotos y quieres que los usuarios puedan arrastrar cientos de fotos y copiarlas en tu app. Bien, ¿qué haces?

Iniciar demostración
Demostración de lanzamiento

En una publicación reciente, Eiji Kitamura destacó una nueva función sutil pero potente en las APIs de arrastrar y soltar: la capacidad de arrastrar carpetas y recuperarlas como objetos FileEntry y DirectoryEntry de la API de Filesystem de HTML5 (se hace accediendo a un método nuevo en DataTransferItem, .webkitGetAsEntry()).

Lo que es muy interesante de la extensión .webkitGetAsEntry() es la elegancia con la que permite importar archivos y carpetas completas. Una vez que tengas un FileEntry o DirectoryEntry de un evento de soltar, solo debes usar el copyTo() de la API de Filesystem para importarlo a tu app.

Ejemplo de cómo copiar varias carpetas que se soltaron en el sistema de archivos:

var fs = null; // Cache filesystem for later.

// Not shown: setup drag and drop event listeners.
function onDrop(e) {
    e.preventDefault();
    e.stopPropagation();

    var items = e.dataTransfer.items;

    for (var i = 0, item; item = items[i]; ++i) {
    var entry = item.webkitGetAsEntry();

    // Folder? Copy the DirectoryEntry over to our local filesystem.
    if (entry.isDirectory) {
        entry.copyTo(fs.root, null, function(copiedEntry) {
        // ...
        }, onError);
    }
    }
}

window.webkitRequestFileSystem(TEMPORARY, 1024 * 1204, function(fileSystem) {
    fs = fileSystem;
}, function(e) {
    console.log('Error', e);
});

¡Muy bien! Una vez más, la simplicidad proviene de la integración de DnD con las llamadas a la API de Filesystem.

Si damos un paso más, también podemos arrastrar y soltar una carpeta o archivos en un <input type="file"> normal y, luego, acceder a las entradas como directorios o entradas de archivos del sistema de archivos. Esto se hace a través de .webkitEntries:

<input type="file" multiple>
function onChange(e) {
    e.stopPropagation();
    e.preventDefault();

    var entries = e.target.webkitEntries; // Get all dropped items as FS API entries.

    [].forEach.call(entries, function(entry) {

    // Copy the entry into our local filesystem.
    entry.copyTo(fs.root, null, function(copiedEntry) {
        ...
    }, onError);

    });
}

document.querySelector('input[type="file"]').addEventListener('change', onChange);

Elaboré una demostración de la galería de fotos para mostrar estas diferentes técnicas de importación de archivos o carpetas.

Demostración de lanzamiento

Para obtener más información sobre la API de Filesystem de HTML5, consulta Explorar las APIs de Filesystem.