שלב 6: מייצאים את המשימות למערכת הקבצים

בשלב הזה תלמדו:

  • איך מקבלים הפניה לקובץ במערכת הקבצים החיצונית.
  • איך לכתוב במערכת הקבצים.

הזמן המשוער לביצוע השלב הזה: 20 דקות.
כדי לראות מה תצטרכו להשלים בשלב הזה, אפשר לגלול למטה לתחתית הדף ↓.

ייצוא של משימות

בשלב הזה מוסיפים לאפליקציה לחצן ייצוא. כשלוחצים עליו, הפריטים הנוכחיים ברשימת המשימות נשמרים בקובץ טקסט שנבחר על ידי המשתמש. אם הקובץ קיים, הוא מוחלף. אחרת, ייווצר קובץ חדש.

עדכון ההרשאות

אפשר לבקש הרשאות למערכת קבצים כמחרוזת לגישה לקריאה בלבד, או כאובייקט עם מאפיינים נוספים. לדוגמה:

// 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"]}]

נדרשת הרשאת קריאה וכתיבה. ב-manifest.json, מבקשים את ההרשאה {fileSystem: [ "write" ] }:

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

עדכון תצוגת ה-HTML

בקובץ index.html, מוסיפים לחצן ייצוא לדיסק ו-div שבהם האפליקציה מציגה הודעת סטטוס:

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

ב-index.html, טוענים גם את הסקריפט export.js:

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

יצירת סקריפט ייצוא

יוצרים קובץ JavaScript חדש בשם export.js באמצעות הקוד הבא. שומרים אותו בתיקייה js.

(function() {

  var dbName = 'todos-vanillajs';

  var savedFileEntry, fileDisplayPath;

  function getTodosAsText(callback) {
  }

  function exportToFileEntry(fileEntry) {
  }

  function doExportToDisk() {
  }

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

})();

נכון לעכשיו, הקובץ export.js מכיל רק מאזין לקליק על הלחצן ייצוא לדיסק וקטעי קוד חלולים (stubs) עבור getTodosAsText(),‏ exportToFileEntry ו-doExportToDisk().

הצגת פריטים של 'דברים שצריך לעשות' כטקסט

מעדכנים את getTodosAsText() כך שתקריא את המשימות מ-chrome.storage.local ותיצור ייצוג טקסטואלי שלהן:

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

בחירת קובץ

מעדכנים את doExportToDisk() ב-chrome.fileSystem.chooseEntry() כדי לאפשר למשתמש לבחור קובץ:

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

  }
}

הפרמטר הראשון של chrome.fileSystem.chooseEntry() הוא אובייקט של אפשרויות. הפרמטר השני הוא שיטת קריאה חוזרת.

אם כבר יש FileEntry שמור, צריך להשתמש בו במקום זאת כשקוראים ל-exportToFileEntry(). הפניות לקובץ קיימות במשך כל משך החיים של האובייקט שמייצג את FileEntry. בדוגמה הזו, משייכים את FileEntry לחלון האפליקציה כדי שקוד ה-JavaScript יוכל לכתוב בקובץ שנבחר בלי אינטראקציה של המשתמש, כל עוד חלון האפליקציה נשאר פתוח.

שימוש ב-FileEntry כדי לכתוב פריטים של 'דברים שצריך לעשות' בדיסק

מעדכנים את exportToFileEntry() כדי לשמור את המשימות כטקסט באמצעות Web API של 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() מקבלת נתיב קובץ שאפשר להציג, שמועבר כפלט לסטטוס div.

משתמשים ב-fileEntry.createWriter() כדי ליצור אובייקט FileWriter. לאחר מכן, fileWriter.write() יכול לכתוב Blob למערכת הקבצים. משתמשים ב-fileWriter.onwriteend() וב-fileWriter.onerror() כדי לעדכן את הסטטוס div.

למידע נוסף על FileEntry, אפשר לקרוא את המאמר Exploring the FileSystem APIs ב-HTML5Rocks, או לעיין במאמר FileEntry docs ב-MDN.

שמירת אובייקטים מסוג FileEntry

מתקדם: אי אפשר לשמור אובייקטים מסוג FileEntry ללא הגבלת זמן. האפליקציה צריכה לבקש מהמשתמש לבחור קובץ בכל פעם שהיא מופעלת. אם האפליקציה אולצה להתחיל מחדש בגלל קריסת זמן ריצה או עדכון, אפשר להשתמש ב-restoreEntry() כדי לשחזר FileEntry.

אם רוצים, אפשר לנסות לשמור את המזהה שמוחזר על ידי retainEntry() ולשחזר אותו כשמפעילים מחדש את האפליקציה. (טיפ: מוסיפים listener לאירוע onRestarted בדף הרקע).

הפעלת אפליקציית Todo שהשלמתם

סיימתם את שלב 6! טענו מחדש את האפליקציה והוסיפו כמה משימות. לוחצים על ייצוא לדיסק כדי לייצא את המשימות לקובץ ‎ .txt.

אפליקציית Todo עם המשימות שיוצאו

אפשר לקבל מידע נוסף

מידע מפורט יותר על חלק מממשקי ה-API שצוינו בשלב הזה זמין במאמרים הבאים:

רוצה להמשיך לשלב הבא? עוברים אל שלב 7 – פרסום האפליקציה »