Mottie
Mottie

Reputation: 86433

Chrome extension popup injecting javascript more than once

I am just starting to learn how to make extensions...

I want it so that when the popup first opens, it injects javascript into the active tab. There are also some buttons in the popup that interact with the injected javascript.

The problem I am having is every time I open the popup, it injects the javascript into the active tab. Each time that happens, any saved variables are reset. So, I ended up just making a global variable to get around this issue.

Here is a sample of the code I am using:

popup.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Extension</title>
    <link href="popup.css" rel="stylesheet">
    <script src="popup.js"></script>
</head>

<body>
    <div class="controls">
        <div class="action1">action 1</div>
        <div class="action2">action 2</div>
    </div>
</body>
</html>

popup.js

var command = {
    action1 : function(){
        chrome.tabs.executeScript(null, {
            code: 'myExtension("action1");'
        });
    },
    action2 : function(){
        chrome.tabs.executeScript(null, {
            code: 'myExtension("action2");'
        });
    }
};

chrome.windows.getCurrent( function(win) {
    chrome.tabs.query({
        'windowId': win.id,
        'active': true
    }, function(tabArray) {

        // windows.done pretty much doesn't do anything
        if ( !window.done ) {
            chrome.tabs.insertCSS( tabArray[0].id, {
                file: 'myextension.css'
            });

            chrome.tabs.executeScript(null, {
                file: 'myextension.js'
            }, function(){
                window.done = true;
                chrome.tabs.executeScript(null, {
                    code: 'myExtension("init");'
                });
            });
        }

        // action1
        var el = document.querySelector( '.action1' );
        el.removeEventListener( 'click', commands.action1 );
        el.addEventListener( 'click', commands.action1 );

        // action2
        var el = document.querySelector( '.action2' );
        el.removeEventListener( 'click', commands.action2 );
        el.addEventListener( 'click', commands.action2 );

    });
});

In my myextension.js file, I do something like this so I don't lose internal variables that I need to save:

(function(){

  window.myExtension = function( command ) {
    if ( typeof myExtensionVariables === 'undefined' ) {
      window.myExtensionVariables = {
        que   : [],
        flags : {}
      }
    }
    if ( command === 'init' ) {
      // initialize!
    }

    // etc

  };

})();

I don't think I have a need for a background.html or background.js,

What I would really like is to prevent javascript injection from happening more than once.

Any suggestions?

Upvotes: 2

Views: 1450

Answers (1)

woxxom
woxxom

Reputation: 73616

If the size of the injected content script is a problem then inject a small code to check the state:

chrome.tabs.executeScript({code: "window.myExtensionVariables"}, function(result) {
    if (!result[0]) {
        /* inject the script */
    }
});

The global variable myExtensionVariables isn't a problem because only your injected content script sees it, not the webpage.

As for window.done in the popup script, window refers to the popup miniwindow, not the webpage, so indeed it's useless for the task.

Overall I'd stick with your implementation because it's the simplest one. Otherwise you'd have to track webNavigation events and maintain a list of tab ids with injected scripts in chrome.storage or a persistent background page.

Upvotes: 2

Related Questions