0

Scenario

I’m writing a Chrome extension / userscript to add a little usability to a third-party site. The page that the extension is made for has a few elements that have `click` event listeners attached (per-element, no bubbling) via `addEventListener` (the `onclick` and other properties are empty). My extension clones (`cloneNode`) one of the elements and appends it to the list.

For example with this,

<div id="list">
  <div id="d1">A</div>
  <div id="d2">B</div>
  <div id="d3">C</div>
</div>

my extension would add a D element.


Problem

Extending the list works fine, but when the original nodes are clicked, they perform the expected action, while clicking the new one does nothing.


Tests

Test 1

I examined the event listeners of the elements in Chrome’s Developer Tools and tried copying the anonymous function to my new elements with `addEventListener` (making sure to duplicate the parameters), but that did not work. It did perform some of the expected actions, but not all of them.

Test 2

I tried anfilat’s suggestion of using the trick from [this question][1]. I inserted a `script` block that then called `addEventHanlder` for the new node, and it did indeed have the new handler (with a `sourceName` referring to the site—the page, not the `.JS` file—instead of the extension), however it still threw a variable not found error.

Hypothesis

I suspect that it is a domain issue because the click-handler calls a function in an external `.JS` as referenced in the `sourceName` and `lineNumber` of the event listener as seen below. Note that the `listenerBody` is identical, but the sources differ.

Question

Is there a way to access, copy, or clone the handlers of an element and/or edit the `lineNumber` and `sourceName`?

Appendix A: Diagrams

Figure 1: Handlers of original elements referring to a .JS on the site (with slight filename edits):

Site

Figure 2: Handlers of new elements referring to the extension:

Extension

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Synetech
  • 9,643
  • 9
  • 64
  • 96
  • Look at http://stackoverflow.com/questions/8927887/executing-host-script-from-an-injected-page – anfilat Feb 11 '12 at 08:59
  • Thanks, that looks like it should help. (I wonder if that’s why someone hit-and-run down-voted.) – Synetech Feb 11 '12 at 21:56
  • What exactly don't work? I tested that code in Chrome and Safary extensions and it worked. – anfilat Feb 12 '12 at 05:57
  • I updated the question to reflect the test. I was able to add a script block that called `addEventListener` to add the same anonymous function to the new blocks from within the page instead of from the extension, but it still throws a variable-not-found error in the JS console when they are clicked but the existing blocks show no errors. – Synetech Feb 12 '12 at 06:16
  • I wrote a new example. It contains all details that you describe. It works. – anfilat Feb 12 '12 at 08:40

1 Answers1

1

I wrote the small working test.

Crome extension inject script:

var myScriptElement = document.createElement('script'); 
myScriptElement.innerHTML =
  'b=document.getElementById("button");' +
  'c=b.cloneNode(true);' +
  'b.parentElement.appendChild(c);' +
  'c.addEventListener("click", function(e){foo("from new button")}, false);';
document.querySelector('head').appendChild(myScriptElement);

test html:

<html>
<script type='text/javascript' src='test.js'></script>
<body>
<button id='button'>test</button>
<script>
document.getElementById('button').addEventListener('click', function (event) {
  foo('from page');
}, false);
</script>
</body>
</html>

and test.js:

function foo(text) {
  console.log(text);
};
anfilat
  • 706
  • 4
  • 4
  • Hmm, you cloned the element with the script too. I only added the event handler with the script (I created the element from the extension). I’ll try offloading the entire script from the extension to the injected script and try it again… (though it’s a couple of dozen lines, so it won’t be pretty). `:-|` – Synetech Feb 12 '12 at 17:51
  • Okay, I tried creating the elements via an injected script instead of from the extension but that did not work either. I started examining the (frustratingly extensive—and obfuscated) scripts of the page and eventually found an initialization function that is called to add the handlers and such, so I simply called that after adding my own nodes. That did not work the first time when I did it from the extension, but by using the injection method from the page you suggested, I was able to call the init function and get it to work as expected. Thanks! – Synetech Feb 12 '12 at 21:08