الخطوة 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 لملف 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()، لاحظ كيفية ضبط عنوان URL لقسم WebView من خلال سمة العلامة 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));
  ...
}

تشغيل تطبيق "قوائم المهام" المكتمل

لقد أكملت الخطوة 4. إذا أعدت تحميل تطبيقك وأضفت عنصر قائمة مهام يتضمّن عنوان URL كاملاً يبدأ بـ http:// ‎ أو https://‎، من المفترض أن يظهر لك ما يلي:

لمزيد من المعلومات

لمزيد من المعلومات التفصيلية حول بعض واجهات برمجة التطبيقات التي تم تقديمها في هذه الخطوة، راجع:

هل أنت مستعد للمتابعة إلى الخطوة التالية؟ انتقِل إلى الخطوة 5: إضافة صور من الويب ».