Etapa 6: exportar tudo para o sistema de arquivos

Nesta etapa, você vai aprender:

  • Como conseguir uma referência a um arquivo no sistema de arquivos externo.
  • Como gravar no sistema de arquivos.

Tempo estimado para concluir esta etapa: 20 minutos.
Para conferir o que você vai concluir nesta etapa, vá até o final desta página ↓.

Exportar tarefas

Esta etapa adiciona um botão de exportação ao app. Quando clicados, os itens de tarefas atuais são salvos em um arquivo de texto selecionado pelo usuário. Se o arquivo existir, ele será substituído. Caso contrário, um novo arquivo será criado.

Atualizar permissões

As permissões do sistema de arquivos podem ser solicitadas como uma string para acesso somente leitura ou um objeto com outras propriedades. Exemplo:

// Read only
"permissions": ["fileSystem"]

// Read and write
"permissions": [{"fileSystem": ["write"]}]

// Read, write, autocomplate previous input, and select folder directories instead of files
"permissions": [{"fileSystem": ["write", "retainEntries", "directory"]}]

Você precisa de acesso de leitura e gravação. No manifest.json, solicite a permissão {fileSystem: [ "write" ] }:

"permissions": [
  "storage", 
  "alarms", 
  "notifications", 
  "webview",
  "<all_urls>", 
  { "fileSystem": ["write"] } 
],

Atualizar visualização HTML

Em index.html, adicione um botão Exportar para disco e uma div em que o app mostre uma mensagem de status:

<footer id="info">
  <button id="toggleAlarm">Activate alarm</button>
  <button id="exportToDisk">Export to disk</button>
  <div id="status"></div>
  ...
</footer>

Ainda em index.html, carregue o script export.js:

...
<script src="js/alarms.js"></script>
<script src="js/export.js"></script>

Criar script de exportação

Crie um arquivo JavaScript chamado export.js usando o código abaixo. Salve-o na pasta js.

(function() {

  var dbName = 'todos-vanillajs';

  var savedFileEntry, fileDisplayPath;

  function getTodosAsText(callback) {
  }

  function exportToFileEntry(fileEntry) {
  }

  function doExportToDisk() {
  }

  document.getElementById('exportToDisk').addEventListener('click', doExportToDisk);

})();

No momento, export.js contém apenas um listener de clique no botão Export to disk e stubs para getTodosAsText(), exportToFileEntry e doExportToDisk().

Receber itens de tarefas como texto

Atualize getTodosAsText() para que ele leia tarefas de chrome.storage.local e gere uma representação textual delas:

function getTodosAsText(callback) {
  chrome.storage.local.get(dbName, function(storedData) {
    var text = '';

    if ( storedData[dbName].todos ) {
      storedData[dbName].todos.forEach(function(todo) {
          text += '- ';
          if ( todo.completed ) {
            text += '[DONE] ';
          }
          text += todo.title;
          text += '\n';
        }, '');
    }

    callback(text);

  }.bind(this));
}

Escolha um arquivo

Atualize doExportToDisk() com chrome.fileSystem.chooseEntry() para permitir que o usuário escolha um arquivo:

function doExportToDisk() {

  if (savedFileEntry) {

    exportToFileEntry(savedFileEntry);

  } else {

    chrome.fileSystem.chooseEntry( {
      type: 'saveFile',
      suggestedName: 'todos.txt',
      accepts: [ { description: 'Text files (*.txt)',
                   extensions: ['txt']} ],
      acceptsAllTypes: true
    }, exportToFileEntry);

  }
}

O primeiro parâmetro de chrome.fileSystem.chooseEntry() é um objeto de opções. O segundo parâmetro é um método de callback.

Se já houver um FileEntry salvo, use-o ao chamar exportToFileEntry(). As referências de arquivo existem durante a vida útil do objeto que representa o FileEntry. Este exemplo vincula FileEntry à janela do app para que o código JavaScript possa gravar no arquivo selecionado sem nenhuma interação do usuário, desde que a janela do app permaneça aberta.

Usar a FileEntry para gravar itens da lista de tarefas no disco

Atualize exportToFileEntry() para salvar as tarefas como texto usando a API Web FileEntry:

function exportToFileEntry(fileEntry) {
  savedFileEntry = fileEntry;

  var status = document.getElementById('status');

  // Use this to get a file path appropriate for displaying
  chrome.fileSystem.getDisplayPath(fileEntry, function(path) {
    fileDisplayPath = path;
    status.innerText = 'Exporting to '+path;
  });

  getTodosAsText( function(contents) {

    fileEntry.createWriter(function(fileWriter) {

      var truncated = false;
      var blob = new Blob([contents]);

      fileWriter.onwriteend = function(e) {
        if (!truncated) {
          truncated = true;
          // You need to explicitly set the file size to truncate
          // any content that might have been there before
          this.truncate(blob.size);
          return;
        }
        status.innerText = 'Export to '+fileDisplayPath+' completed';
      };

      fileWriter.onerror = function(e) {
        status.innerText = 'Export failed: '+e.toString();
      };

      fileWriter.write(blob);

    });
  });
}

chrome.fileSystem.getDisplayPath() recebe um caminho de arquivo que pode ser exibido e gera o status div.

Use fileEntry.createWriter() para criar um objeto FileWriter. fileWriter.write() pode gravar um Blob no sistema de arquivos. Use fileWriter.onwriteend() e fileWriter.onerror() para atualizar o status div.

Para saber mais sobre FileEntry, leia Como explorar as APIs FileSystem no HTML5Rocks ou consulte a FileEntry docs no MDN.

Manter objetos FileEntry

Avançado: objetos FileEntry não podem ser mantidos indefinidamente. Seu app precisa pedir que o usuário escolha um arquivo sempre que for iniciado. Se o app foi forçado para reiniciar devido a uma falha ou atualização no ambiente de execução, restoreEntry() é uma opção para restaurar um FileEntry.

Se quiser, faça um teste salvando o ID retornado por retainEntry() e restaurando-o na reinicialização do app. Dica: adicione um listener ao evento onRestarted na página em segundo plano.

Iniciar o app Todo concluído

Você concluiu a Etapa 6! Atualize o app e adicione algumas tarefas. Clique em Exportar para disco para exportar todos para um arquivo .txt.

O app Todo com tarefas exportadas

Mais informações

Para informações mais detalhadas sobre algumas das APIs introduzidas nesta etapa, consulte:

Tudo pronto para passar à próxima etapa? Vá para a Etapa 7: publicar seu aplicativo »