0

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);
kawa
  • 422
  • 4
  • 16

1 Answers1

2

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.

Community
  • 1
  • 1
Xan
  • 74,770
  • 16
  • 179
  • 206
  • Used all kinds of prependers still not working. So I used var buttonJGET = jQuery("#gwt-uid-115"); but not working, still gives me undefined , and I've correctly reloaded the extension. – kawa May 13 '14 at 08:10
  • Updated my answer, but please do not edit away your problem: Stack Overflow is supposed to be a record of answers to problems. – Xan May 13 '14 at 08:15
  • Thanks, I've edited back to how it was; I've entered your correction but I now get an error : "Uncaught TypeError: Cannot read property 'className' of undefined" – kawa May 13 '14 at 08:19
  • This means that there are no elements with that id, at least at the moment the query executes (you would agree it looks dynamic). You need to rethink your code around that possibility. But I think your original question is answered. – Xan May 13 '14 at 08:20
  • What do I neeed to add in the manifest as run_at fields so the script runs at all possible times? – kawa May 13 '14 at 08:22
  • Updated the answer; your error was easier than what I initially thought, but I added the dynamic-element bit. – Xan May 13 '14 at 11:29
  • Just added your code with mutations and the run_at key and I get the following error: **"Uncaught TypeError: Cannot read property 'match' of undefined "**. It gets stuck at : `if(node.id.match(/^gwt-uid/)) return true;` Also , `console.log(buttonJGET.attr('class'));` I've already tried and still gives undefined . Also, I've checked and rechecked the id and it's the correct one. – kawa May 13 '14 at 12:12
  • Surely it's something you can fix yourself! But, fixed the answer. – Xan May 13 '14 at 12:16
  • `watchNodes("#gwt-uid-115", logger);` works! `watchNodes(filter, logger);` gives the error – kawa May 13 '14 at 13:32