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

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

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

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

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

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

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

הטמעת תג WebView

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

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

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

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

יצירת דף להטמעת Webview

יוצרים קובץ חדש ברמה הבסיסית של תיקיית הפרויקט ומעניקים לו את השם 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;
  ...
}

פתיחת חלון חדש שמכיל תצוגת אינטרנט

מוסיפים את השיטה _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);

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

לבסוף, מוסיפים מאזין לאירועי לחיצה בתוך המבנה הגנרטיבי 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));
  ...
}

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

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

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

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

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