1

I'm learning to write JavaScript extensions, and chose a basic application to start with. The extension I'm writing simply adds the attribute target='_blank' in each link. The extension gets activated on clicking the icon. It works perfectly, but I'm adding listeners to update, replace and activate events, and none of them is working. Already checked some SO posts but it didn't help (say this, this, and many more). Googled enough to reach saturation point and post a question. Please help.

Here is my code.

background.js

chrome.browserAction.onClicked.addListener(function(tab){
  chrome.storage.local.get('click',function(result){
    if(result.click == 0){
        chrome.storage.local.set({"click":1},function(){
        mainProc(tab.id,result.click);
        });
    } else if (result.click == 1) {
        chrome.storage.local.set({"click":0},function(){
        mainProc(tab.id,result.click);
        });
    } else if (result.click == undefined) {
      chrome.storage.local.set({"click":1},function(){
      mainProc(tab.id,result.click);
      });
    }
  })
});

chrome.tabs.onActivated.addListener(function(activeInfo){
  chrome.storage.local.get("click",function(result){
    if(result.click == 1){
      mainProc(activeInfo.tabId,result.click);
    }
  })
})

chrome.tabs.onUpdated.addListener(function(tabid,changeInfo,tab) {
  if(changeInfo.status == "complete"){
    chrome.storage.local.get("click",function(result){
      if(result.click == 1){
      chrome.tabs.query({active:true,currentWindow:true},function(tabs){
        mainProc(tabs[0].id,result.click);
      });
      }
    })
  }
})

chrome.tabs.onReplaced.addListener(function(addedTabId,removedTabId){
  chrome.storage.local.get("click",function(result){
    if(result.click == 1){
      mainProc(addedTabId,result.click); //tried with removedTabId too, just to be sure
    }
  })
})

function changeIcon(clicked){
  if(clicked == 1){
    chrome.browserAction.setIcon({path: 'light.png'});
  }else {
    chrome.browserAction.setIcon({path: 'dark.png'});
  }
}

function activate(id){
  chrome.storage.local.get("click",function(result){
    if(result.click == 1){
      mainProc(id,result.click);
    }
  })
}

function clickListener(id){
  chrome.storage.local.get("click",function(result){
    if (result.click == 0) {
      chrome.storage.local.set({"click":1},function(){
        mainProc(id,result.click);
      });
    } else if (result.click == 1) {
      chrome.storage.local.set({"click":0},function(){
        mainProc(id,result.click);
      });
    } else if (result.click == null) {
      chrome.storage.local.set({"click":1},function(){
        mainProc(id,result.click);
      });
    } else if (result.click == undefined) {
      chrome.storage.local.set({"click":1},function(){
        mainProc(id,result.click);
      });
    }
  })
}

function mainProc(id,click){
  changeIcon(click);
  chrome.tabs.sendMessage(id,{clicked:click});
}

script.js

chrome.runtime.onMessage.addListener(function(msg,sender){
  var a = document.getElementsByTagName("a");
  if(msg.clicked == 1){
    console.log("clicked:",msg.clicked);
    for(var i = 0;i<a.length;i++){
      a[i].setAttribute("target","_blank");
      a[i].className += " newtab";
    }
  } else if (msg.clicked == 0) {
    console.log("clicked:",msg.clicked);
    for(var i = 0;i<a.length;i++){
      if(a[i].classList.contains("newtab")){
        a[i].classList.remove("newtab");
        a[i].removeAttribute("target");
      }
    }
  }
});

manifest.json

{
  "manifest_version":2,

  "name":"newtab",
  "description": "This extension lets you open each link in new tab",
  "version":"1.0.0",
  "author": "ritik saxena",

  "browser_action":{
    "default_icon":"dark.png",
    "default_title": "newTab"
  },
  "background":{
    "persistent":true,
    "scripts":["background.js"]
  },
  "content_scripts":[{
    "js":["script.js"],
    "matches":["<all_urls>"]
    }],
    "permissions":[
      "tabs",
      "storage"
    ]
}
Community
  • 1
  • 1
Ritik Saxena
  • 694
  • 1
  • 11
  • 23
  • 2
    I'm having a hard time understanding the goal of using onActivated and onUpdated as well as the meaning of `click` value. And why getting the active tab in onUpdated if the updated tab may be any of the inactive tabs? Anyway, start by [debugging your background page](https://stackoverflow.com/a/10258029): you can set breakpoints in the listeners or use console.log. – wOxxOm Feb 02 '17 at 14:49
  • @wOxxOm onActivated is used so that when the extension is active and the user changes tab, it scraps through the new page too. onUpdated is when user changes the url, or in better words, updates the page. the value of click denotes whether the extension is active or not. – Ritik Saxena Feb 02 '17 at 15:22
  • 1
    It seams like this would be more effective for your content script to just read the value from `storage.local` itself rather than wait for a message, and listen for changes in that value using `storage.onChanged`. If you are using a class to indicate that your script is the one which made the change to add `_blank`, then A) You need to check to see if `target` is already `_blank` and B) You need to use a class which is *much* more likely to not already be used on the page (e.g. `ritikSaxenaNewtab`), because `newtab` is *way* to easy to already be used on random pages. – Makyen Feb 02 '17 at 17:05
  • @Makyen if I change the functionality to just reading the value of storage.local without passing message, then how will I make my extension work on tab change, tab update, and new tab? As far as I know, only background scripts can handle the tab listeners, not the content scripts. Somehow I need the content script to know that the tab has been changed, or updated, or replaced. Moreover, talking about your concern regarding the class and conditionals, that stuff is secondary, I'll take care of it before publishing the extension, in case I publish. – Ritik Saxena Feb 03 '17 at 04:16
  • 1
    @RitikSaxena, if you're listening to `storage.onChanged`, your background script can just store something to cause the content script to re-read the value and act. However, most of the events which you are talking about invalidate the content script context (i.e. stop the script) and inject the content script once the new page exists. Thus, there's not much reason for the content script to be notified of most of the events which you are considering (and no ability for the content script to actualy act on such because it does not exist, or will shortly not exist, prior to being created again.) – Makyen Feb 03 '17 at 06:21
  • @Makyen Can u please point out the events which are invalidating the content script context? Maybe then I'll be able to understand my mistake. Moreover, if I use `storage.onChanged`, then also i'll need to call `chrome.tabs.sendMessage` on updating, activating, or replacing the tab, so that i can inject the content script on the freshly available page, how would it differ from what I'm doing now? except avoiding an extra function each time I change the value. – Ritik Saxena Feb 03 '17 at 12:06
  • 1
    @RitikSaxena, If your content script (CS) is listening to `storage.onChanged` then your content script gets an event whenever a value is changed in a [StorageArea](https://developer.chrome.com/extensions/storage#type-StorageArea). Thus, using `tabs.sendMessage()` to communicate that the value has changed is redundant. The CS context is invalidated whenever the page reloads, or transitions to a new URL. When *exactly* that happens is complex. With a `content_scripts` entry in *manifest.json* your CS is automatically injected in tabs/frames that match the criteria specified. – Makyen Feb 03 '17 at 15:36
  • Part of what we are discussing is an [XY problem](https://www.google.com/search?as_q=XY+problem). Please describe in more detail what it is you are attempting to achieve with sending the messages you envision using. – Makyen Feb 03 '17 at 15:37
  • @Makyen So that means I don't have to pass any value to content script from background to make it work. It'll itself start each time a page is reloaded? – Ritik Saxena Feb 04 '17 at 02:44
  • I've already achieved what I wanted. Now that I'm somewhat clear with your point I'll improve my code accordingly. Thanks. – Ritik Saxena Feb 04 '17 at 02:46
  • 1
    That is the idea. At least everything you have shown in the question indicates that the only information you are using `tabs.sendMessage()` to send to the content script is data you get from `storage.local`. The content script can get that itself, and listen for changes to what is stored in `chrome.storage`. – Makyen Feb 04 '17 at 06:30

0 Answers0