שינוי דפים מהרשת

This translation is incomplete. Please help translate this article from English

אחד השימושים הנפוצים להרחגה הוא לשנות דף מהרשת. לדוגמה,  הרחבה עשויה לרצות שלנות את הסגנון שבשימוש הדף , להסתיר צמתי DOM מסויימים, או להחדיר צמתי DOM נוןספים לדף.

קיימות שתי דרכים לעשות זאת עם ממשקי פיתוח הרחבות הרשת:

  • הצהרתית: על ידי הגדרת תבנית התואמת קבוצה של כתובות URL, וטעינת קבוצה של תסריטים לתוך בדפים שכתובת ה-URL שלהם תואמת את התבנית.
  • תכנותית: באמתעות ממשקי פיתוח יישומי ג'אווה-סקריפט, טעינת התסריט לתוך הדף המאורח בלשונית מסויימת.

בכל דרך, תסריטים אלה קרויים תסריטי תוכן, והם שונים מתסריטים אחרים שההרחבה עשויה מהם:

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

במאמר זה נתבונן בשתי השיטות של טעינת תסריט.

שינויים בדפים התואמים תבנית URL

קודם כל, צרו תיקייה חדשה בשם "modify-page". בתיקייה זו, צרו קובץ בשם   "manifest.json", המכיל את התוכן הבא:

{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "content_scripts": [
    {
      "matches": ["https://developer.mozilla.org/*"],
      "js": ["page-eater.js"]
    }
  ]

}

המפתח content_scripts הוא הדרך לטעון תסריטים לתוך דפים התואמים תבניות  URL  במקרה זה, content_scripts מורה לדפדפן לטעון תסריט בשם   "page-eater.js" לתוך כל הדפים תחת https://developer.mozilla.org/.

מאחר שהתכונה "js" של  content_scripts היא מערך, תוכלו להשתמש בה כדי להחדיר יותר מתסריט אחד לתוך דפים תואמים . אם תעשו זאת דף יחלוק את אותו התחום, כשם שתסריטים מרובים הנטענים על ידי דף, והם ייטענו בסדר שנרשמו בתוך המערך.

למפתח content_scripts יש גם תכונת "css" בה תוכלו להשתמש כדי להחסיר דפי סגנונות המקודדים ב-CSS

כעת, צרו קובץ בשם "page-eater.js" בתוך התיקייה "modify-page" , ושימו בו את התוכן הבא:

document.body.textContent = "";

var header = document.createElement('h1');
header.textContent = "This page has been eaten";
document.body.appendChild(header);

כעת iהתקינו את ההרחבה, ובקרו בדף https://developer.mozilla.org:/

שימו לב כי למרות שבסרטון מוצג תסריט תוכן הפועל ב- addons.mozilla.org, תסריטי תוכן לעת עתה חסומים באתר זה.

שינוי דפים תכנותית

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

תחילה, עדכנו את  "manifest.json" כך שיכיל את התוכן הבא:

{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "permissions": [
    "activeTab",
    "contextMenus"
  ],

  "background": {
    "scripts": ["background.js"]
  }

}

כאן, הוצאנו את המפתח content_scripts, והוספנו שני מפתחות חדשים:

  • permissions: להחדיר תסריטים לתוך דפים שדרושות הרשאות לדפים שאנו מעדכנים. ההרשאה activeTab היא דרך להשיג זאת זמנית עבור הלשונית הפעילה באותו רגע . דרושה לנו גם ההרשאה contextMenus כדי שנוכל להוסיף פריטים לתפריט ההקשר.
  • background: We're using this to load a persistent "background script" called "background.js", in which we'll set up the context menu and inject the content script.

Let's create this file. Create a new file called "background.js" in the "modify-page" directory, and give it the following contents:

browser.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

browser.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    browser.tabs.executeScript({
      file: "page-eater.js"
    });
  }
});

In this script we're creating a context menu item, giving it a specific id and title (the text to be displayed in the context menu). Then we set up an event listener so that when the user clicks a context menu item, we check to see if it is our eat-page item. If it is, we inject "page-eater.js" into the current tab using the tabs.executeScript() API. This API optionally takes a tab ID as an argument: we've omitted the tab ID, which means that the script is injected into the currently active tab.

At this point the extension should look like this:

modify-page/
    background.js
    manifest.json
    page-eater.js

Now reload the extension, open a page (any page, this time) activate the context menu, and select "Eat this page":

Note that although this video shows the content script working in addons.mozilla.org, content scripts are currently blocked for this site.

Messaging

Content scripts and background scripts can't directly access each other's state. However, they can communicate by sending messages. One end sets up a message listener, and the other end can then send it a message. The following table summarises the APIs involved on each side:

In content script In background script
Send a message browser.runtime.sendMessage() browser.tabs.sendMessage()
Receive a message browser.runtime.onMessage browser.runtime.onMessage

In addition to this method of communication, which sends one-off messages, you can also use a connection-based approach to exchange messages. For advice on choosing between the options, see Choosing between one-off messages and connection-based messaging.

Let's update our example to show how to send a message from the background script.

First, edit "background.js" so that it has these contents:

browser.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

function messageTab(tabs) {
  browser.tabs.sendMessage(tabs[0].id, {
    replacement: "Message from the extension!"
  });
}

function onExecuted(result) {
    var querying = browser.tabs.query({
        active: true,
        currentWindow: true
    });
    querying.then(messageTab);
}

browser.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    let executing = browser.tabs.executeScript({
      file: "page-eater.js"
    });
    executing.then(onExecuted);
  }
});

Now, after injecting "page-eater.js", we use tabs.query() to get the currently active tab, and then use tabs.sendMessage() to send a message to the content scripts loaded into that tab. The message has the payload {replacement: "Message from the extension!"}.

Next, update "page-eater.js" like this:

function eatPageReceiver(request, sender, sendResponse) {
  document.body.textContent = "";
  var header = document.createElement('h1');
  header.textContent = request.replacement;
  document.body.appendChild(header);
}
browser.runtime.onMessage.addListener(eatPageReceiver);

Now instead of just eating the page right away, the content script listens for a message using runtime.onMessage. When a message arrives, the content script runs essentially the same code as before, except that the replacement text is taken from request.replacement.

Since tabs.executeScript() is an asynchronous function, and to ensure we send message only after listener has been added in "page-eater.js", we use onExecuted which will be called after "page-eater.js" executed.

Press Ctrl+Shift+J (or Cmd+Shift+J on a Mac) OR web-ext run --bc to open Browser Console to view console.log in background script. Alternatively use Add-on Debugger  which allows you set breakpoint. There is currently no way to start Add-on Debugger directly from web-ext.

If we want send messages back from the content script to the background page,  we would use runtime.sendMessage() instead of tabs.sendMessage(), e.g.:

browser.runtime.sendMessage({
    title: "from page-eater.js"
});

These examples all inject JavaScript; you can also inject CSS programmatically using the tabs.insertCSS() function.

Learn more