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 la app. Muy bien, ¿qué haces?

Iniciar demostración
Iniciar la demostración

En una publicación reciente, Eiji Kitamura destacó una nueva función sutil, pero poderosa, 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 (mediante el acceso a un método nuevo en DataTransferItem, .webkitGetAsEntry()).

Lo más interesante de la extensión .webkitGetAsEntry() es lo elegante que hace que importar archivos y carpetas enteras. Una vez que tengas un elemento FileEntry o DirectoryEntry de un evento de drop, solo deberás usar copyTo() de la API de Filesystem para importarlo a tu app.

Ejemplo de cómo copiar varias carpetas descartadas 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.

Para seguir avanzando, también tenemos la capacidad de arrastrar y soltar una carpeta o archivos en un <input type="file"> normal y, luego, acceder a las entradas como un directorio del sistema de archivos o entradas 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);

Armé una demostración de una galería de fotos a fin de demostrar estas diferentes técnicas para importar archivos y carpetas.

Iniciar demostración

Para obtener más información sobre la API del sistema de archivos HTML5, consulta Cómo explorar las APIs del sistema de archivos.