Integrar input[type=file] à API Filesystem

Digamos que você tenha um app de edição de fotos e queira que os usuários possam arrastar centenas de fotos e copiá-las para o app. Certo, o que você faz?

Iniciar demonstração
Lançar demonstração

Em uma postagem recente, Eiji Kitamura destacou um novo recurso sutil, mas poderoso, nas APIs de arrastar e soltar: a capacidade de arrastar em pastas e recuperá-las como objetos FileEntry e DirectoryEntry da API HTML5 Filesystem (acessada ao acessar um novo método em DataTransferItem, .webkitGetAsEntry()).

O mais interessante da extensão .webkitGetAsEntry() é a elegância que ela torna a importação de arquivos e pastas inteiras. Quando você tiver um FileEntry ou DirectoryEntry de um evento de soltar, basta usar o copyTo() da API Filesystem para importá-lo para o app.

Um exemplo de cópia de várias pastas descartadas para o sistema de arquivos:

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

Muito bom! Novamente, a simplicidade vem da integração do DnD com as chamadas da API do sistema de arquivos.

Além disso, também podemos arrastar e soltar uma pasta e/ou arquivos em uma <input type="file"> normal e acessar as entradas como um diretório do sistema de arquivos ou entradas de arquivo. Isso é feito pelo .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);

Criei uma demonstração de galeria de fotos para demonstrar essas diferentes técnicas de importação de arquivos/pastas.

Iniciar demonstração

Para saber mais sobre a API do sistema de arquivos HTML5, consulte Explorar as APIs do sistema de arquivos.