4

I want to write a Chrome extension that reacts to the clicking on a specific element on a page (example of this type of page: https://www.mentimeter.com/s/ea1639a1b16e623b9c7b4bc884f86aae/cc3aaa4bae22).

The specific element I really am interested in is a <rect> element, but for the sake of simplicity I provide this demo which shows that I can get the script to react to the clicking on a high-level <div id="root"> element but not its child <div class="application mm-ui"> (see listing of page elements in image).

page elements shown by Chrome dev tools

I would be grateful for any clue as to how I can select other elements lower down in the DOM. The jQuery code for selecting the <div class="application mm-ui"> element works fine if I enter it into the javascript console in Chrome Dev Tools instead of using the extension.

The extension folder includes a downloaded copy of jQuery 3.3.1 (name: "jquery.js") in addition to the manifest.json and the content.js.

(I guess there is also a way to make the page download jQuery from googleapis but I haven't yet managed to find out how. One thing at a time.)

manifest.json

 {
  "manifest_version": 2, 
  "name": "Mentimeter demo",
  "version": "0.1.0",
  "description": "Mentimeter demo",
 "content_scripts": [{
      "js": ["jquery.js","content.js"],
    "matches": ["https://www.mentimeter.com/*"]
  }]
}

content.js

$(document).ready(function(){
//$("div#root").click(function(){//works
$("div.application").click(function(){//does not work
alert("click");
});
});

Wait. There's more.

The puzzling thing is that a simpler version using vanilla JS manages to select the <rect> elements without problem:

manifest.json

{
  "manifest_version": 2,

  "name": "Vanilla JS selection demo",
  "version": "0.1.0",
  "description": "Vanilla JS selection demo",

  "content_scripts": [{
    "js": ["content.js"],
    "matches": ["https://www.mentimeter.com/*"]
  }]

content.js

document.addEventListener("click",function(event){
var target = event.target;
if(target.tagName.toLowerCase() == "rect"){
alert("rect clicked");
} 
},false);
danbae
  • 563
  • 2
  • 8
  • 22
  • Can't remember what it exactly was, but Chrome extensions I think might not run inside a space where `document` is defined. Maybe not even `window`? I would suggest Googling how to edit the document from within a Chrome extension. (If you want to be sure, run a `console.log(window, document);` and see what's available) – minitauros Nov 02 '18 at 12:13
  • Could it be that the DOM node in question is added after the initial document is parsed (from a script)? Then `$(document).ready()` is too early and you'll have to [watch for the node being added](https://stackoverflow.com/q/5525071/934239). – Xan Nov 02 '18 at 12:18
  • 2
    @NirajKaushal Incorrect; it's a separate content script JS context. – Xan Nov 02 '18 at 12:21
  • 1
    The typical solution is to use event delegation: $(document).on('click', 'div.application', function() { ...... }) – wOxxOm Nov 02 '18 at 12:23
  • And if you don't want to use event delegation you can consider using this excellent library http://github.com/uzairfarooq/arrive – Aefits Nov 02 '18 at 12:29
  • @minitauros: I forgot to mention that I already have an extension using vanilla JS where selection of the ``element works. I have edited my post accordingly. I need jQuery to make a more advanced version of the actual extension (these are just demos). – danbae Nov 02 '18 at 12:32
  • @danbae your working code basically does the same as event delegation in jQuery. – wOxxOm Nov 02 '18 at 12:34
  • @Xan: if you are right about the delay, why does the vanilla JS (added to my post above) work? – danbae Nov 02 '18 at 12:37
  • why does the vanilla JS work? Because as @wOxxOm said its using event delegation. – Aefits Nov 02 '18 at 12:39
  • @elegant-user: please help me understand how I should modify my jQuery code such that it works like the vanilla JS. Complete sentences are appreciated – I'm no expert as I'm sure you have noticed already. – danbae Nov 02 '18 at 12:48
  • Use what @wOxxOm has suggested `$(document).on('click', 'div.application', function() { ...... })` or use this easy to use `mutationObserver` library http://github.com/uzairfarooq/arrive if you don;t want to use event delegation. – Aefits Nov 02 '18 at 12:50
  • @elegant-user and wOxxOm: Thanks a lot... I'm a bit slow, sorry about that. It works now. Please feel free to create an answer and take credit for solving this. `$(document).on("click","rect",function(){alert("click");});` – danbae Nov 02 '18 at 12:57
  • @elegant-user It works, because [events bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture). – Xan Nov 02 '18 at 14:41
  • Quick vanillaJS tip: instead of checking `target.tagName.toLowerCase()`, you can also issue a `if (target instanceof HTMLRectElement) {}` (you would have to look up if the element is indeed a `HTMLRectElement`, but this is how this usually works). – minitauros Nov 03 '18 at 09:28

1 Answers1

3

As discussed in the comments:

Use what @wOxxOm has suggested use jQuery event delegation.

$(document).on('click', 'rect', function() { ...... }) 

or use this easy to use mutationObserver library github.com/uzairfarooq/arrive if you don't want to use event delegation.

Aefits
  • 3,399
  • 6
  • 28
  • 46