שלב 4: פתיחת קישורים חיצוניים באמצעות WebView

בשלב זה נלמד:

  • איך להציג תוכן חיצוני מהאינטרנט באפליקציה שלכם באופן מאובטח ובארגז חול.

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

מידע נוסף על תג WebView

בחלק מהאפליקציות צריך להציג תוכן אינטרנט חיצוני ישירות למשתמש, אבל להשאיר אותן בתוך חוויית האפליקציה. לדוגמה, אתר אגרגטור של חדשות עשוי לרצות להטמיע חדשות מאתרים חיצוניים עם כל העיצוב, התמונות וההתנהגות של האתר המקורי. לשימושים אלה ואחרים, יש לאפליקציות Chrome תג HTML מותאם אישית שנקרא webview.

האפליקציה Todo באמצעות WebView

הטמעה של תג ה-WebView

צריך לעדכן את אפליקציית Todo כדי לחפש כתובות URL בטקסט של פריט המשימות וליצור היפר-קישור. כשלוחצים על הקישור, נפתח חלון חדש של אפליקציית Chrome (לא כרטיסייה בדפדפן) עם WebView שמציג את התוכן.

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

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

"permissions": [
  "storage",
  "alarms",
  "notifications",
  "webview"
],

יצירת דף הטמעה של WebView

יוצרים קובץ חדש ברמה הבסיסית (root) של תיקיית הפרויקט ונותנים לו את השם webview.html. הקובץ הזה הוא דף אינטרנט בסיסי עם תג <webview> אחד:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <webview style="width: 100%; height: 100%;"></webview>
</body>
</html>

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

בסוף controller.js, מוסיפים שיטה חדשה שנקראת _parseForURLs():

  Controller.prototype._getCurrentPage = function () {
    return document.location.hash.split('/')[1];
  };

  Controller.prototype._parseForURLs = function (text) {
    var re = /(https?:\/\/[^\s"<>,]+)/g;
    return text.replace(re, '<a href="$1" data-src="$1">$1</a>');
  };

  // Export to window
  window.app.Controller = Controller;
})(window);

בכל פעם שנמצאת מחרוזת שמתחילה ב-"http://" או ב-"https://", נוצר תג עוגן של HTML שנועד לעטוף את כתובת ה-URL.

ניתן למצוא את showAll() ב-controller.js. מעדכנים את showAll() כדי לנתח קישורים באמצעות השיטה _parseForURLs() שהוספתם קודם לכן:

/**
 * 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.view.show(data);
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
  }.bind(this));
};

יש לחזור על הפעולה עבור showActive() ו-showCompleted():

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

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

לסיום, מוסיפים את _parseForURLs() ל-editItem():

Controller.prototype.editItem = function (id, label) {
  ...
  var onSaveHandler = function () {
    ...
      // Instead of re-rendering the whole view just update
      // this piece of it
      label.innerHTML = value;
      label.innerHTML = this._parseForURLs(value);
    ...
  }.bind(this);
  ...
}

עדיין ב-editItem(), תקנו את הקוד כך שישתמש ב-innerText של התווית במקום ב-innerHTML של התווית:

Controller.prototype.editItem = function (id, label) {
  ...
  // Get the innerHTML of the label instead of requesting the data from the
  // Get the innerText of the label instead of requesting the data from the
  // ORM. If this were a real DB this would save a lot of time and would avoid
  // a spinner gif.
  input.value = label.innerHTML;
  input.value = label.innerText;
  ...
}

פתיחת חלון חדש שמכיל את ה-WebView

הוספת שיטת _doShowUrl() ל-controller.js. השיטה הזו פותחת חלון חדש של אפליקציית Chrome דרך chrome.app.window.create(), עם webview.html כמקור החלון:

  Controller.prototype._parseForURLs = function (text) {
    var re = /(https?:\/\/[^\s"<>,]+)/g;
    return text.replace(re, '<a href="$1" data-src="$1">$1</a>');
  };

  Controller.prototype._doShowUrl = function(e) {
    // only applies to elements with data-src attributes
    if (!e.target.hasAttribute('data-src')) {
      return;
    }
    e.preventDefault();
    var url = e.target.getAttribute('data-src');
    chrome.app.window.create(
     'webview.html',
     {hidden: true},   // only show window when webview is configured
     function(appWin) {
       appWin.contentWindow.addEventListener('DOMContentLoaded',
         function(e) {
           // when window is loaded, set webview source
           var webview = appWin.contentWindow.
                document.querySelector('webview');
           webview.src = url;
           // now we can show it:
           appWin.show();
         }
       );
     });
  };

  // Export to window
  window.app.Controller = Controller;
})(window);

בקטע chrome.app.window.create() קריאה חוזרת (callback), בודקים איך כתובת ה-URL של ה-webview מוגדרת באמצעות src מאפיין התג.

לסיום, צריך להוסיף פונקציות listener של אירועי קליק בתוך ה-builder של Controller כדי להפעיל את doShowUrl() כשמשתמש לוחץ על קישור:

function Controller(model, view) {
  ...
  this.router = new Router();
  this.router.init();

  this.$todoList.addEventListener('click', this._doShowUrl);

  window.addEventListener('load', function () {
    this._updateFilterState();
  }.bind(this));
  ...
}

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

סיימת את שלב 4! אם טוענים מחדש את האפליקציה ומוסיפים פריט לביצוע עם כתובת URL מלאה שמתחילה ב-http:// או ב-https://, אתם אמורים לראות משהו כזה:

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

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

מוכנים להמשיך לשלב הבא? מעבר אל שלב 5 – הוספת תמונות מהאינטרנט »