Question

I have a button in a google page. DOM Inspector gives its id. However trying to obtain the object fails. I get an undefined result while tying to write its class name in the console. There's only one iframe in the page and my object is not inside it (as far as I know).

manifest.json:

{
    "manifest_version": 2,
    "name": "modify strings",
    "description": "modify strings in bulk",
    "version": "1.0",
    "permissions": [
       "tabs",
       "history",
       "http://*/*",
       "https://*/*"
    ],  

    "content_scripts": [
        {
            "matches": ["https://play.google.com/apps/*"],
            "js": ["jquery-1.11.1.min.js", "myInject.js"],
            "all_frames": true
        }
    ],

    "web_accessible_resources": [
        "script.js",
        "jquery-1.11.1.min.js"
    ],

    "browser_action": {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    }



}

myInject.js (content script):

var buttonJGET = jQuery("gwt-uid-115", document);   
console.log(buttonJGET.className);
Was it helpful?

Solution

jQuery uses CSS-like selectors.

To select element by its id, you need to use #. Also, jQuery always returns an array of results, even if it is unique.

var buttonJGET = jQuery("#gwt-uid-115")[0];

jQuery elements are different from DOM elements; they do not have className attribute. To get it, one can use, for instance:

console.log(buttonJGET.attr('class'));

There are also other functions to deal with elements' classes.

Otherwise, you can extract a DOM element out of a jQuery element:

var buttonJGET = jQuery("#gwt-uid-115").get(0);
console.log(buttonJGET.className);

If the code still fails, it might be because at the moment the script is run there is no element with that id (yet). To achieve "run my code every time such an element is added", one can use DOM mutation observers (canonical answer here):

// Runs a function for every added DOM element that matches a filter
// filter -- either function(DOM_node){/*...*/}, returns true or false 
//           OR a jQuery selector
// callback -- function(DOM_node){/*...*/}
function watchNodes(filter, callback){
  var observer = new MutationObserver( function (mutations) {
    mutations.forEach( function (mutation){
      if(typeof filter === "function"){
        $(mutation.addedNodes).filter(
          function(i){ return filter(this); }
        ).each(
          function(i){ callback(this); }
        );
      } else {
        $(mutation.addedNodes).filter(filter).each(
          function(i){ callback(this); }
        );
      }
    });
  });

  // For every added element, a mutation will be processed
  //   with mutation.taget == parent
  //   and mutation.addedNodes containing the added element
  observer.observe(document, { subtree: true, childList: true });

  return observer;
}

To use (note, filter and callback use DOM elements):

function logger(node) {
  console.log(node.className); 
}

var observer = watchNodes("#gwt-uid-115", logger);

Or, if, for instance, you want to catch all nodes whose id's start with gwt-uid, you can write a custom filter:

function filter(node) {
  if(node.id && node.id.match(/^gwt-uid/)) return true;
  else return false;
}

var observer2 = watchNodes(filter, logger);

Injecting this at run_at: "document_start" will ensure you'll capture all elements added.

To stop observing, call observer.disconnect() on the returned observer object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top