admin管理员组

文章数量:1401790

So, I have the following code:

var clicks = 0; // click counter

// Make sure this only runs on facebook
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (tab.url.indexOf("facebook") > -1) {
        chrome.pageAction.show(tabId);
    }
});

// Called when the user clicks on the page action.
chrome.pageAction.onClicked.addListener(function(tab) {
  if (clicks == 0) {
    chrome.pageAction.setIcon({path: "dontlike.png", tabId: tab.id}); // Update icon
    chrome.pageAction.setTitle({title: "idontlike", tabId: tab.id}); // Update title
    chrome.tabs.executeScript({ // Hide like buttons
      code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display="none"; }'
    });
  } 
  else {
    chrome.pageAction.setIcon({path: "like.png", tabId: tab.id}); // Update icon
    chrome.pageAction.setTitle({title: "like", tabId: tab.id}); // Update title
    chrome.tabs.executeScript({ // Show like buttons
      code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display=""; }'
    });
  }

  // wrap coutner around
  clicks++;
  if (clicks > 1)
    clicks = 0;
});

for a chrome extension that hides all "Like" buttons on facebook when a pageaction icon is clicked. This works; however, any time a new facebook url is loaded, the state of the extension is lost, e.g. if the button is in dislike mode (hide all likes), if I go to a new page, it is reset to like mode.

I had an idea to persist the state of the extension using the click counter, and to make the code more functional with something like the following

var clicks = 0; // click counter

function like() {
  chrome.pageAction.setIcon({path: "like.png", tabId: tab.id}); // Update icon
  chrome.pageAction.setTitle({title: "like", tabId: tab.id}); // Update title
  chrome.tabs.executeScript({ // Show like buttons
    code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display="none"; }'
  });

  clicks++;
  if (clicks > 1) {
    clicks = 0;
  }
}

function dislike() {
  chrome.pageAction.setIcon({path: "like.png", tabId: tab.id}); // Update icon
  chrome.pageAction.setTitle({title: "like", tabId: tab.id}); // Update title
  chrome.tabs.executeScript({ // Show like buttons
    code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display=""; }'
  });

  clicks++;
  if (clicks > 1) {
    clicks = 0;
  }
}

// Make sure this only runs on facebook
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (tab.url.indexOf("facebook") > -1) {
      chrome.pageAction.show(tabId);
      if (clicks == 0) {
        like();
      } 
      else {
        dislike();
      }
    }
});

// Called when the user clicks on the page action.
chrome.pageAction.onClicked.addListener(function(tab) {
  if (clicks == 0) {
    like();
  } 
  else {
    dislike();
  }
});

But that code doesn't work at all (when I click on the page action icon, nothing happens and no error messages appear in the chrome console).

I'm new to JS and Chrome Extensions. Is there an easy way to persist the state of my extension, and a better way to execute the script I need to hide all like buttons?

Thank you!

So, I have the following code:

var clicks = 0; // click counter

// Make sure this only runs on facebook
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (tab.url.indexOf("facebook.") > -1) {
        chrome.pageAction.show(tabId);
    }
});

// Called when the user clicks on the page action.
chrome.pageAction.onClicked.addListener(function(tab) {
  if (clicks == 0) {
    chrome.pageAction.setIcon({path: "dontlike.png", tabId: tab.id}); // Update icon
    chrome.pageAction.setTitle({title: "idontlike", tabId: tab.id}); // Update title
    chrome.tabs.executeScript({ // Hide like buttons
      code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display="none"; }'
    });
  } 
  else {
    chrome.pageAction.setIcon({path: "like.png", tabId: tab.id}); // Update icon
    chrome.pageAction.setTitle({title: "like", tabId: tab.id}); // Update title
    chrome.tabs.executeScript({ // Show like buttons
      code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display=""; }'
    });
  }

  // wrap coutner around
  clicks++;
  if (clicks > 1)
    clicks = 0;
});

for a chrome extension that hides all "Like" buttons on facebook when a pageaction icon is clicked. This works; however, any time a new facebook url is loaded, the state of the extension is lost, e.g. if the button is in dislike mode (hide all likes), if I go to a new page, it is reset to like mode.

I had an idea to persist the state of the extension using the click counter, and to make the code more functional with something like the following

var clicks = 0; // click counter

function like() {
  chrome.pageAction.setIcon({path: "like.png", tabId: tab.id}); // Update icon
  chrome.pageAction.setTitle({title: "like", tabId: tab.id}); // Update title
  chrome.tabs.executeScript({ // Show like buttons
    code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display="none"; }'
  });

  clicks++;
  if (clicks > 1) {
    clicks = 0;
  }
}

function dislike() {
  chrome.pageAction.setIcon({path: "like.png", tabId: tab.id}); // Update icon
  chrome.pageAction.setTitle({title: "like", tabId: tab.id}); // Update title
  chrome.tabs.executeScript({ // Show like buttons
    code: 'var like = document.getElementsByClassName("UFILikeLink"); for (index = 0; index < like.length; ++index) { like[index].style.display=""; }'
  });

  clicks++;
  if (clicks > 1) {
    clicks = 0;
  }
}

// Make sure this only runs on facebook
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (tab.url.indexOf("facebook.") > -1) {
      chrome.pageAction.show(tabId);
      if (clicks == 0) {
        like();
      } 
      else {
        dislike();
      }
    }
});

// Called when the user clicks on the page action.
chrome.pageAction.onClicked.addListener(function(tab) {
  if (clicks == 0) {
    like();
  } 
  else {
    dislike();
  }
});

But that code doesn't work at all (when I click on the page action icon, nothing happens and no error messages appear in the chrome console).

I'm new to JS and Chrome Extensions. Is there an easy way to persist the state of my extension, and a better way to execute the script I need to hide all like buttons?

Thank you!

Share Improve this question asked Aug 4, 2015 at 2:54 glcohenglcohen 1931 gold badge2 silver badges11 bronze badges 3
  • I Haven't very well understand what You're extension have to do. What I have understand is that you have to mode : a mode where "like" buttons are hidden, and an other one where "like" buttons are shown. And you can switch betwen this to state with a click on the page action button. Am I right ? – Emrys Myrooin Commented Aug 4, 2015 at 8:13
  • @EmrysMyrooin that's right! – glcohen Commented Aug 4, 2015 at 12:51
  • So I have made an answer, and I think for you'r use case that the second solution is the best because it will save the state over chrome sessions – Emrys Myrooin Commented Aug 4, 2015 at 12:58
Add a ment  | 

2 Answers 2

Reset to default 9

The question of states in chrome extension can have several answers. The choice depend of the situation. Whet I have understand in your case is that you only have tow states, so I will give you some idea.

1. Persistent background script

By default, background script is loaded at chrome startup, so it lives during the whole execution of chrome, until the user explicitly close chrome. In bination with Content Script, you can have a state full system.

So You can use this background script to save a state during the execution and inform listening content scripts of the changes :

background.js

var state = 0;

chrome.pageAction.onClicked.addListener(function(tab) {
    if (state = 0) {
        state = 1;
        state0Actions(); //Do what you want
    } 
    else {
        state = 0;
        state1Actions(); //Do what you want
    }

    //Inform content scripts that the state have changed
    chrome.tabs.sendMessage(tab.id, {state : state});
});

//At initialisation, Content scipts will request the current state to background script.
chrome.runtime.onMessage(function(message, sender, callback){
    if(message.getState) callback({state : state});
});

You can then inject a content script to all facebook pages by adding this to your manifest.json file

"content_scripts" :
[
    {
        "matches": ["https://www.facebook./*","http://www.facebook./*"],
        "all_frames": true,

        "js": ["contentScript.js"]
    }
]

It will automatically inject the contentScipt.js script to all page beginning with http(s)://www.facebook..

contenScript.js //the actions to do for each states function state0Actions() { //Do what you want for the state 0 }

function state1Actions()
{
    //Do what you want for the state 1
}

//Message will be received at each update of state in the background page
chrome.runtime.onMessage.addListner(function(message, sender, callback))
{
    //Check the message is valid
    if(message.state == null)
    {
        console.log("Unreconized message");
        return;
    }

    //Do actions for the right state
    //You also can use if statements here... Switch are more used when there is lots of states
    switch(message.state) {
        case 0 : state0Actions(); break;
        case 1 : state1Actions(); break;
    }
}

//Request the current state to initialise the script
chrome.runtime.sendMessage({getState: true});

Here, the onMessage handler will be call a first time when he is loaded and then each time the background change the state.

Pay attention that the state will be reset at the chrome startup.

2. Chrome storage

You can use chrome.storage API to manage the state. The main point of this is that the state will be saved and will not be reset at chrome startup.

To do this, you have pretty the same background code :

chrome.pageAction.onClicked.addListener(function(tab) {
    chrome.storage.local.get("state", function(result)
    {
        //First initialisation of the state in the local storage
        if(result.state == null)
        {
            chrome.storage.local.set({state: 0});
            state0Actions(); //Do what you want
        }
        else if (result.state == 0) {
            result.state = 1;
            state0Actions(); //Do what you want
        } 
        else {
            result.state = 0;
            state1Actions(); //Do what you want
        }

        //Save the new state to the storage
        chrome.storage.set({state: result.state});
    }
});

And the content script will listen changes of the local storage instead of wating update notification from the background page :

//the actions to do for each states
function state0Actions()
{
    //Do what you want for the state 0
}

function state1Actions()
{
    //Do what you want for the state 1
}

chrome.storage.local.onChanged.addListener(function(changes, areaName)
{
    if(areaName != "local" || changes.state == null) return;

    switch(changes.state)
    {
        case 0 : state0Actions(); break;
        case 1 : state1Actions(); break;
    }
})

chrome.storage.local.get("state", function(result){
    if(result.state == null) state0Actions(); //Do what you want if the state is not yet initialised
    else if (result.state == 0) state0Actions(); //Do what you want
    else if (result.state == 1) state1Actions(); //Do what you want
})

You also can use chrome.storage.sync instead of chrome.storage.local for a shared state with all user's devices.


This are to way to play with state. you have to pare what is the better for your use case. The code I have written is not tested, they are only example to illustrate my explanation.

Don't forget to check Chrome API documentation

When the extension is using a non-persistent background page aka Event page it is unloaded after ~5 seconds of inactivity. And every time it's reloaded the code runs again and all variables are re-initialized, thus losing the previous state.

The solution is to store the state in localStorage which doesn't require any additional permissions in manifest.json:

  • Initialization:

    var clicks = localStorage.clicks || 0; // click counter
    
  • Toggling and storing (no need for ++ and if):

    var clicks = localStorage.clicks = 1 - clicks;
    

The value will be stringified and stored as "0" or "1" but for the above arithmetic it's not a problem.

本文标签: javascriptPersist a page action39s state in a chrome extensionStack Overflow