web-dev-qa-db-fra.com

Chrome Extension Comment envoyer des données depuis un script de contenu vers popup.html

Je sais que cela a été demandé dans de nombreux messages, mais honnêtement, je ne les comprends pas. Je suis nouveau dans JavaScript, Chrome Extensions et tout, et j’ai cette affectation de classe. Je dois donc créer un plug-in qui compterait les objets DOM sur toute page donnée à l’aide de requêtes interdomaines. J'ai réussi jusqu'à présent à utiliser ceci avec Chrome Extension API. Maintenant, le problème est que je dois afficher les données sur ma page popup.html à partir du fichier contentScript.js. Je ne sais pas comment Pour ce faire, j'ai essayé de lire la documentation, mais la messagerie est dans chrome Je ne comprends tout simplement pas quoi faire.

voici le code jusqu'à présent.

manifest.json

{
"manifest_version":2,

"name":"Dom Reader",
"description":"Counts Dom Objects",
"version":"1.0",

"page_action": {
    "default_icon":"icon.png",
    "default_title":"Dom Reader",
    "default_popup":"popup.html"
},

"background":{
    "scripts":["eventPage.js"],
    "persistent":false
},

"content_scripts":[
    {
        "matches":["http://pluralsight.com/training/Courses/*", "http://pluralsight.com/training/Authors/Details/*",                                          "https://www.youtube.com/user/*", "https://sites.google.com/site/*", "http://127.0.0.1:3667/popup.html"],
        "js":["domReader_cs.js","jquery-1.10.2.js"]
        //"css":["pluralsight_cs.css"]
    }
],

"permissions":[
    "tabs",
    "http://pluralsight.com/*",
    "http://youtube.com/*",
    "https://sites.google.com/*",
    "http://127.0.0.1:3667/*"
]

popup.html

<!doctype html>
<html>

    <title> Dom Reader </title>    
    <script src="jquery-1.10.2.js" type="text/javascript"></script>
    <script src="popup.js" type="text/javascript"></script>

<body>
    <H1> Dom Reader </H1>
    <input type="submit" id="readDom" value="Read DOM Objects" />

   <div id="domInfo">

    </div>
</body>
</html>

eventPage.js

var value1,value2,value3;

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action == "show") {
    chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
        chrome.pageAction.show(tabs[0].id);
    });
}

value1 = request.tElements;
});

popup.js

$(function (){
$('#readDom').click(function(){
chrome.tabs.query({active: true, currentWindow: true}, function (tabs){
    chrome.tabs.sendMessage(tabs[0].id, {action: "readDom"});

 });
});
});

contentScript

var totalElements;
var inputFields;
var buttonElement;

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse){
if(request.action == "readDom"){

    totalElements = $("*").length;
    inputFields = $("input").length;
    buttonElement = $("button").length;


}
})

chrome.runtime.sendMessage({ 
action: "show", 
tElements: totalElements, 
Ifields: inputFields, 
bElements: buttonElement 

});

Toute aide serait appréciée et s'il vous plaît éviter tout noobness je l'ai fait :)

81
Sumair Baloch

Bien que vous soyez vraiment dans la bonne direction (et en fait assez près de la fin), votre code contient de nombreuses (mauvaises) pratiques (par exemple, injecter une bibliothèque entière (jquery) pour une tâche aussi triviale, déclarer des autorisations inutiles, rendre superflous appels aux méthodes API, etc.).
Je n'ai pas testé votre code moi-même, mais d'après un rapide aperçu, je pense que la correction de ce qui suit pourrait aboutir à une solution efficace (même si elle n'est pas très proche de l'optimum):

  1. Dans manifest.json : modifiez l'ordre des scripts de contenu, en plaçant jquery en premier. Selon les documents pertinents:

    "js" [...] La liste des fichiers JavaScript à injecter dans les pages correspondantes. Ceux-ci sont injectés dans l'ordre dans lequel ils apparaissent dans ce tableau.

    (c'est moi qui souligne)

  2. Dans contentscript.js : déplacez le chrome.runtime.sendMessage ({...}) bloque à l'intérieur le rappel de l'auditeur onMessage.


Ceci dit, voici l’approche proposée:

Flux de contrôle:

  1. Un script de contenu est injecté dans chaque page correspondant à certains critères.
  2. Une fois injectés, les scripts de contenu envoient un message à la page d'événement (page d'arrière-plan non persistante a.k.a.) et la page d'événement associe une action de page à l'onglet.
  3. Dès que la fenêtre contextuelle d'action de page est chargée, il envoie un message au script de contenu, lui demandant les informations dont il a besoin.
  4. Le script de contenu traite la demande et répond afin que la fenêtre contextuelle d'action de page puisse afficher les informations.

Structure du répertoire:

          root-directory/
           |_____img
                 |_____icon19.png
                 |_____icon38.png
           |_____manifest.json
           |_____background.js
           |_____content.js
           |_____popup.js
           |_____popup.html

manifest.json:

{
  "manifest_version": 2,
  "name": "Test Extension",
  "version": "0.0",
  "offline_enabled": true,

  "background": {
    "persistent": false,
    "scripts": ["background.js"]
  },

  "content_scripts": [{
    "matches": ["*://*.stackoverflow.com/*"],
    "js": ["content.js"],
    "run_at": "document_idle",
    "all_frames": false
  }],

  "page_action": {
    "default_title": "Test Extension",
    //"default_icon": {
    //  "19": "img/icon19.png",
    //  "38": "img/icon38.png"
    //},
    "default_popup": "popup.html"
  }

  // No special permissions required...
  //"permissions": []
}

background.js:

chrome.runtime.onMessage.addListener((msg, sender) => {
  // First, validate the message's structure.
  if ((msg.from === 'content') && (msg.subject === 'showPageAction')) {
    // Enable the page-action for the requesting tab.
    chrome.pageAction.show(sender.tab.id);
  }
});

content.js:

// Inform the background page that 
// this tab should have a page-action.
chrome.runtime.sendMessage({
  from: 'content',
  subject: 'showPageAction',
});

// Listen for messages from the popup.
chrome.runtime.onMessage.addListener((msg, sender, response) => {
  // First, validate the message's structure.
  if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
    // Collect the necessary data. 
    // (For your specific requirements `document.querySelectorAll(...)`
    //  should be equivalent to jquery's `$(...)`.)
    var domInfo = {
      total: document.querySelectorAll('*').length,
      inputs: document.querySelectorAll('input').length,
      buttons: document.querySelectorAll('button').length,
    };

    // Directly respond to the sender (popup), 
    // through the specified callback.
    response(domInfo);
  }
});

popup.js:

// Update the relevant fields with the new data.
const setDOMInfo = info => {
  document.getElementById('total').textContent = info.total;
  document.getElementById('inputs').textContent = info.inputs;
  document.getElementById('buttons').textContent = info.buttons;
};

// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', () => {
  // ...query for the active tab...
  chrome.tabs.query({
    active: true,
    currentWindow: true
  }, tabs => {
    // ...and send a request for the DOM info...
    chrome.tabs.sendMessage(
        tabs[0].id,
        {from: 'popup', subject: 'DOMInfo'},
        // ...also specifying a callback to be called 
        //    from the receiving end (content script).
        setDOMInfo);
  });
});

popup.html:

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="popup.js"></script>
  </head>
  <body>
    <h3 style="font-weight:bold; text-align:center;">DOM Info</h3>
    <table border="1" cellpadding="3" style="border-collapse:collapse;">
      <tr>
        <td nowrap>Total number of elements:</td>
        <td align="right"><span id="total">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Number of input elements:</td>
        <td align="right"><span id="inputs">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Number of button elements:</td>
        <td align="right"><span id="buttons">N/A</span></td>
      </tr>
    </table>
  </body>
</html>
149
gkalpak

Vous pouvez utiliser localStorage pour cela. Vous pouvez stocker toutes les données dans un format de table de hachage dans la mémoire du navigateur, puis y accéder à tout moment. Je ne sais pas si nous pouvons accéder à localStorage à partir du script de contenu (il a déjà été bloqué), essayez de le faire vous-même. Voici comment le faire via votre page d'arrière-plan (je passe d'abord les données du script de contenu à la page d'arrière-plan, puis je les enregistre dans localStorage):

dans contentScript.js:

chrome.runtime.sendMessage({
  total_elements: totalElements // or whatever you want to send
});

dans eventPage.js (votre page d'arrière-plan):

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse){
       localStorage["total_elements"] = request.total_elements;
    }
);

Ensuite, vous pouvez accéder à cette variable dans popup.js avec localStorage ["total_elements"].

Peut-être pouvez-vous accéder à localStorage directement à partir du script de contenu des navigateurs modernes. Ensuite, vous n'avez pas besoin de transmettre les données via votre page d'arrière-plan.

Bonne lecture à propos de localStorage: http://diveintohtml5.info/storage.html

4
gthacoder