How to insert content script in google chrome extension when page was changed via history.pushState?
Asked Answered
K

2

13

I'm creating a small google chrome extension for website, and I want to change some html on particular pages.

The problem is that website load his content via ajax, and heavy use history.pushState API. So, I added this thing to manifest:

"content_scripts": [
   {
     "matches": ["http://vk.com/friends"],
     "js": ["js/lib/jquery.min.js", "js/friends.js"],      
   },
 ]

Everything works fine when I'm opening page first time or reloading it. But when I'm navigating between website pages, chrome don't insert my scripts on "/friends" page. I think this happening because the URL actually don't changing. They use history.pushState() and so, chrome can't insert/rerun my script again.

Is there any solution for this?

Kingsley answered 10/12, 2012 at 17:46 Comment(0)
R
7

You can add a window.onpopstate event in content script and listen for it, when an event fires you can re-run content script again.

References

a) extension.sendMessage()

b) extension.onMessage().addListener

c) tabs.executeScript()

d) history.pushState()

e) window.onpopstate

Sample Demonstration:

manifest.json

Ensure content script injected URL and all API's tabs have enough permission in manifest file

{
    "name": "History Push state Demo",
    "version": "0.0.1",
    "manifest_version": 2,
    "description": "This demonstrates how push state works for chrome extension",
    "background":{
        "scripts":["background.js"]
    },
    "content_scripts": [{
        "matches": ["http://www.google.co.in/"],
        "js": ["content_scripts.js"]
     }],
    "permissions": ["tabs","http://www.google.co.in/"]
}

content_scripts.js

Track for onpopstate event and send a request to background page for rerun of script

window.onpopstate = function (event) {
    //Track for event changes here and 
    //send an intimation to background page to inject code again
    chrome.extension.sendMessage("Rerun script");
};

//Change History state to Images Page
history.pushState({
    page: 1
}, "title 1", "imghp?hl=en&tab=wi");

background.js

Track for request from content script and execute script to the current page

//Look for Intimation from Content Script for rerun of Injection
chrome.extension.onMessage.addListener(function (message, sender, callback) {
    // Look for Exact message
    if (message == "Rerun script") {
        //Inject script again to the current active tab
        chrome.tabs.executeScript({
            file: "rerunInjection.js"
        }, function () {
            console.log("Injection is Completed");
        });
    }
});

rerunInjection.js

Some Trivial code

console.log("Injected again");

Output

enter image description here

Let me know if you need more information.

Redivivus answered 11/12, 2012 at 8:33 Comment(1)
Btw, pushState doesn't fire "popstate" event, so this code doesn't work.Clipped
V
15

I was able to get this working. From the Chrome Extension docs for webNavigation:

You need to set permissions for webNavigation in manifest.json:

  "permissions": [
     "webNavigation"
  ],

Then in background.js:

  chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
        console.log('Page uses History API and we heard a pushSate/replaceState.');
        // do your thing
  });
Verona answered 11/7, 2013 at 3:26 Comment(0)
R
7

You can add a window.onpopstate event in content script and listen for it, when an event fires you can re-run content script again.

References

a) extension.sendMessage()

b) extension.onMessage().addListener

c) tabs.executeScript()

d) history.pushState()

e) window.onpopstate

Sample Demonstration:

manifest.json

Ensure content script injected URL and all API's tabs have enough permission in manifest file

{
    "name": "History Push state Demo",
    "version": "0.0.1",
    "manifest_version": 2,
    "description": "This demonstrates how push state works for chrome extension",
    "background":{
        "scripts":["background.js"]
    },
    "content_scripts": [{
        "matches": ["http://www.google.co.in/"],
        "js": ["content_scripts.js"]
     }],
    "permissions": ["tabs","http://www.google.co.in/"]
}

content_scripts.js

Track for onpopstate event and send a request to background page for rerun of script

window.onpopstate = function (event) {
    //Track for event changes here and 
    //send an intimation to background page to inject code again
    chrome.extension.sendMessage("Rerun script");
};

//Change History state to Images Page
history.pushState({
    page: 1
}, "title 1", "imghp?hl=en&tab=wi");

background.js

Track for request from content script and execute script to the current page

//Look for Intimation from Content Script for rerun of Injection
chrome.extension.onMessage.addListener(function (message, sender, callback) {
    // Look for Exact message
    if (message == "Rerun script") {
        //Inject script again to the current active tab
        chrome.tabs.executeScript({
            file: "rerunInjection.js"
        }, function () {
            console.log("Injection is Completed");
        });
    }
});

rerunInjection.js

Some Trivial code

console.log("Injected again");

Output

enter image description here

Let me know if you need more information.

Redivivus answered 11/12, 2012 at 8:33 Comment(1)
Btw, pushState doesn't fire "popstate" event, so this code doesn't work.Clipped

© 2022 - 2024 — McMap. All rights reserved.