web-dev-qa-db-fra.com

onClick dans Chrome Extension ne fonctionne pas

Cela semble être la chose la plus facile à faire, mais cela ne fonctionne tout simplement pas. Dans un navigateur normal, les fichiers .html et .js fonctionnent parfaitement, mais dans l'extension Chrome, la fonction onClick n'effectue pas ce qu'elle est censée faire.

fichier .js:

function hellYeah(text) {
  document.getElementById("text-holder").innerHTML = text;
}

fichier .html:

<!doctype html>
<html>
  <head>
    <title>
      Getting Started Extension's Popup
    </title>
    <script src="popup.js"></script>
  </head>
  <body>
    <div id="text-holder">
      ha
    </div>
    <br />
    <a onClick=hellYeah("xxx")>
      hyhy
    </a>
  </body>
</html>

Donc, en gros, une fois que l'utilisateur clique sur "hyhy", "ha" devrait devenir "xxx". Et encore une fois - cela fonctionne parfaitement dans le navigateur, mais ne fonctionne pas dans l'extension. Est-ce que tu sais pourquoi? Juste au cas où je joindrais aussi le fichier manifest.json ci-dessous.

Merci d'avance!

manifest.json:

{
  "name": "My First Extension",
  "version": "1.0",
  "manifest_version": 2,
  "description": "The first extension that I made.",
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "permissions": [
    "http://api.flickr.com/"
  ]
}
58
teeZee

Les extensions Chrome ne vous permettent pas d’avoir du code JavaScript intégré ( documentation ). Vous allez devoir faire quelque chose de similaire à cela.

Attribuez un identifiant au lien (<a onClick=hellYeah("xxx")> devient <a id="link">) et utilisez addEventListener pour lier l'événement. Mettez ce qui suit dans votre fichier popup.js:

document.addEventListener('DOMContentLoaded', function() {
    var link = document.getElementById('link');
    // onClick's logic below:
    link.addEventListener('click', function() {
        hellYeah('xxx');
    });
});
104
David

Raison

Cela ne fonctionne pas car Chrome interdit tout type de code en ligne dans les extensions via la stratégie de sécurité du contenu.

JavaScript en ligne ne sera pas exécuté. Cette restriction interdit les deux blocs <script> inline et gestionnaires d'événements inline (par exemple, <button onclick="...">).

Comment détecter

Si tel est effectivement le problème, Chrome générera l'erreur suivante dans la console:

A refusé d'exécuter le script en ligne car il enfreint la directive de sécurité du contenu suivante: "script-src 'self' chrome-extension-resource:". Le mot clé 'unsafe-inline', un hachage ('sha256 -...') ou un nonce ('nonce -...') est requis pour permettre l'exécution en ligne.

Pour accéder à la console JavaScript d'une popup (ce qui est utile pour le débogage en général), cliquez avec le bouton droit de la souris sur le bouton de votre extension et sélectionnez "Inspecter la popup" dans le menu contextuel.

Plus d'informations sur le débogage d'un popup est disponible ici .

Comment réparer

Il faut supprimer tout le JavaScript en ligne. Il y a un guide dans la documentation Chrome .

Supposons que l'original ressemble à:

<a onclick="handler()">Click this</a> <!-- Bad -->

Il faut supprimer l'attribut onclick et attribuer à l'élément un identifiant unique:

<a id="click-this">Click this</a> <!-- Fixed -->

Et attachez ensuite l'auditeur à partir d'un script (qui doit être dans un fichier .js, supposez popup.js):

// Pure JS:
document.addEventListener('DOMContentLoaded', function() {
  document.getElementById("click-this").addEventListener("click", handler);
});

// The handler also must go in a .js file
function handler() {
  /* ... */
}

Notez le wrapping dans un événement DOMContentLoaded. Cela garantit que l'élément existe au moment de l'exécution. Ajoutez maintenant la balise de script, par exemple dans le <head> du document:

<script src="popup.js"></script>

Alternative si vous utilisez jQuery:

// jQuery
$(document).ready(function() {
  $("#click-this").click(handler);
});

Assouplir la politique

Q: L'erreur mentionne différentes manières d'autoriser le code en ligne. Je ne veux pas/ne peux pas changer mon code, comment puis-je activer les scripts en ligne?

A: Malgré ce que dit l'erreur, vous ne pouvez pas activer le script en ligne

Il n'y a pas de mécanisme permettant d'assouplir la restriction empêchant l'exécution de JavaScript en ligne. En particulier, la définition d'une stratégie de script incluant 'unsafe-inline' n'aura aucun effet.

Update: Depuis Chrome 46, il est possible de mettre en liste blanche des blocs de code en ligne spécifiques:

À partir de Chrome 46, les scripts en ligne peuvent être ajoutés à la liste blanche en spécifiant le hachage codé en base64 du code source dans la stratégie. Ce hachage doit être préfixé par l'algorithme de hachage utilisé (sha256, sha384 ou sha512). Voir Utilisation du hachage pour les éléments <script> pour un exemple.

Cependant, je ne vois pas facilement pourquoi je l'utilisais et cela n'activerait pas les attributs intégrés tels que onclick="code".

35
Xan

J'ai eu le même problème et je ne voulais pas réécrire le code. J'ai donc écrit une fonction pour modifier le code et créer les événements déclarés en ligne:

function compile(qSel){
    var matches = [];
    var match = null;
    var c = 0;

    var html = $(qSel).html();
    var pattern = /(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/mg;

    while (match = pattern.exec(html)) {
        var arr = [];
        for (i in match) {
            if (!isNaN(i)) {
                arr.Push(match[i]);
            }
        }
        matches.Push(arr);
    }
    var items_with_events = [];
    var compiledHtml = html;

    for ( var i in matches ){
        var item_with_event = {
            custom_id : "my_app_identifier_"+i,
            code : matches[i][5],
            on : matches[i][3],
        };
        items_with_events.Push(item_with_event);
        compiledHtml = compiledHtml.replace(/(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/m, "<$2 custom_id='"+item_with_event.custom_id+"' $7 $8");
    }

    $(qSel).html(compiledHtml);

    for ( var i in items_with_events ){
        $("[custom_id='"+items_with_events[i].custom_id+"']").bind(items_with_events[i].on, function(){
            eval(items_with_events[i].code);
        });
    }
}

$(document).ready(function(){
    compile('#content');
})

Cela devrait supprimer tous les événements en ligne du nœud sélectionné et les recréer avec jquery à la place.

1
sergio0983

Je décide de publier l'exemple que j'ai utilisé dans mon cas. J'ai essayé de remplacer le contenu en div en utilisant un script. Mon problème était que Chrome n'a pas reconnu/n'a pas exécuté ce script. 

Plus en détail Ce que je voulais faire: cliquer sur un lien, et sur ce lien pour "lire" un fichier HTML externe, afin qu'il soit chargé dans une section div. 

  • J'ai découvert qu'en plaçant le script avant la DIV avec l'ID portant le nom , Le script ne fonctionnait pas. 
  • Si le script était dans une autre DIV, cela ne fonctionne pas non plus
  • Le script doit être codé en utilisant document.addEventListener ('DOMContentLoaded', function () comme il a été dit

        <body>
        <a id=id_page href ="#loving"   onclick="load_services()"> loving   </a>
    
            <script>
                    // This script MUST BE under the "ID" that is calling
                    // Do not transfer it to a differ DIV than the caller "ID"
                    document.getElementById("id_page").addEventListener("click", function(){
                    document.getElementById("mainbody").innerHTML = '<object data="Services.html" class="loving_css_edit"; ></object>'; });
                </script>
        </body>
    
      <div id="mainbody" class="main_body">
            "here is loaded the external html file when the loving link will 
             be  clicked. "
      </div>
    
0