שלב 5: הוספת תמונות מהאינטרנט

בשלב זה נלמד:

  • איך לטעון משאבים מחוץ לאפליקציה ולהוסיף אותם ל-DOM באמצעות XHR ו-ObjectURLs.

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

איך CSP משפיע על השימוש במשאבים חיצוניים

פלטפורמת אפליקציות Chrome מאלצת את האפליקציה לפעול בתאימות מלאה למדיניות אבטחת תוכן (CSP). אי אפשר לטעון ישירות משאבי DOM כמו תמונות, גופנים ו-CSS שלא נמצאים בחבילת האפליקציות של Chrome.

אם רוצים להציג תמונה חיצונית באפליקציה, צריך לבקש אותה דרך XMLHttpRequest, לשנות אותה ל-Blob וליצור ObjectURL. אפשר להוסיף את ObjectURL הזה ל-DOM כי הוא מפנה לפריט בזיכרון בהקשר של האפליקציה.

הצגת תמונות ממוזערות של משימות לביצוע

בואו נשנה את האפליקציה שלנו כדי לחפש כתובות URL של תמונות בפריט לביצוע. אם כתובת ה-URL נראית כמו תמונה (לדוגמה, מסתיימת ב- .png , .jpg, .svg או .gif), צריך להחיל את התהליך שהוזכר למעלה כדי להציג תמונה ממוזערת לצד כתובת ה-URL.

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

באפליקציית Chrome אפשר לבצע קריאות XMLHttpRequest לכל כתובת URL, כל עוד מציינים את הדומיין שלה במניפסט. מכיוון שלא תוכלו לדעת מראש איזו כתובת URL של תמונה המשתמש יקליד, כדאי לבקש הרשאה לשלוח בקשות אל "<all_urls>".

ב-manifest.json, מבקשים את ההרשאה :

"permissions": ["storage", "alarms", "notifications",
                "webview", "<all_urls>"],

יצירה וניקוי של ObjectURLs

ב-controller.js, מוסיפים שיטה _createObjectURL() כדי ליצור ObjectURLs מ-Blob:

Controller.prototype._createObjectURL = function(blob) {
  var objURL = URL.createObjectURL(blob);
  this.objectURLs = this.objectURLs || [];
  this.objectURLs.push(objURL);
  return objURL;
};

ל-ObjectURLs יש זיכרון, לכן כשאין לך עוד צורך ב-ObjectURL, עליך לבטל אותם. כדי לטפל במקרים האלה, מוסיפים את השיטה _clearObjectURL() ל-controller.js:

Controller.prototype._clearObjectURL = function() {
  if (this.objectURLs) {
    this.objectURLs.forEach(function(objURL) {
      URL.revokeObjectURL(objURL);
    });
    this.objectURLs = null;
  }
};

שליחה של בקשת XHR

מוסיפים שיטת _requestRemoteImageAndAppend() כדי להפעיל XMLHttpRequest בכתובת URL נתונה של תמונה:

Controller.prototype._requestRemoteImageAndAppend = function(imageUrl, element) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', imageUrl);
  xhr.responseType = 'blob';
  xhr.onload = function() {
    var img = document.createElement('img');
    img.setAttribute('data-src', imageUrl);
    img.className = 'icon';
    var objURL = this._createObjectURL(xhr.response);
    img.setAttribute('src', objURL);
    element.appendChild(img);
  }.bind(this);
  xhr.send();
};

בטעינת XHR, השיטה הזו יוצרת ObjectURL מתגובת ה-XHR, ומוסיפה ל-DOM רכיב <img> עם ObjectURL הזה.

ניתוח של כתובות URL של תמונות בפריטים לביצוע

עכשיו צריך להוסיף את השיטה _parseForImageURLs(), שמחפשת את כל הקישורים שעדיין לא עובדו ומחפשת בהם תמונות. בכל כתובת URL שנראית כמו תמונה, מריצים את הפקודה _requestRemoteImageAndAppend():

Controller.prototype._parseForImageURLs = function () {
  // remove old blobs to avoid memory leak:
  this._clearObjectURL();
  var links = this.$todoList.querySelectorAll('a[data-src]:not(.thumbnail)');
  var re = /\.(png|jpg|jpeg|svg|gif)$/;
  for (var i = 0; i<links.length; i++) {
    var url = links[i].getAttribute('data-src');
    if (re.test(url)) {
      links[i].classList.add('thumbnail');
      this._requestRemoteImageAndAppend(url, links[i]);
    }
  }
};

עיבוד תמונות ממוזערות ברשימת המשימות לביצוע

אפשר להתקשר עכשיו אל _parseForImageURLs() באמצעות showAll(), showActive() וגם showCompleted():

/**
 * An event to fire on load. Will get all items and display them in the
 * todo-list
 */
Controller.prototype.showAll = function () {
  this.model.read(function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

/**
 * Renders all active tasks
 */
Controller.prototype.showActive = function () {
  this.model.read({ completed: 0 }, function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

/**
 * Renders all completed tasks
 */
Controller.prototype.showCompleted = function () {
  this.model.read({ completed: 1 }, function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

חוזרים על הפעולה לגבי editItem():

Controller.prototype.editItem = function (id, label) {
  ...
  var onSaveHandler = function () {
    ...
    if (value.length && !discarding) {
      ...
      label.innerHTML = this._parseForURLs(value);
      this._parseForImageURLs();
    } else if (value.length === 0) {
  ...
}

להגביל את מידות התמונה המוצגות

לבסוף, בקטע _bowercomponents/todomvc-common/base.css מוסיפים כלל CSS להגבלת גודל התמונה:

.thumbnail img[data-src] {
  max-width: 100px;
  max-height: 28px;
}

הפעלת האפליקציה הסתיימה של משימות לביצוע

סיימת את שלב 5! טוענים מחדש את האפליקציה ומוסיפים פריט לביצוע עם כתובת URL לתמונה שמתארחת באינטרנט. אפשר להשתמש בכתובות URL מסוימות: http://goo.gl/nqHMF#.jpg או http://goo.gl/HPBGR#.png.

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

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

מוכנים להמשיך לשלב הבא? עבור לשלב 6 - ייצוא משימות לביצוע למערכת הקבצים »