0

I've made an Greasemonkey script which uses jQuery appendTo('body').
Everything is working fine but the HTML is also appended to other DOM elements like Google ads and gadgets on my igoogle page.

Is there something to fix this? I don't think some example code is necessary for this issue. Instead I've uploaded a picture that shows my problem:

my igoogle page


As you can see, my appended HTML shows up in many different places.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
kasper Taeymans
  • 6,950
  • 5
  • 32
  • 51

2 Answers2

2

The reason you are seeing your HTML appended to multiple items is most likely because of the existence of iframes in the markup you are dealing with.

Each iFrame (an I suspect that the gadgets, ads are iFrames) have their own entire HTML structure complete with <html></html> and <body></body> tags. When you .appendTo('body'), your script will append the content to any element that matches the 'body' selector.

You'll want to give a more unique selector than $('body').


What you might want to do is try using $('body:first') of some sort of other unique selector in addition to the generic body selector. You might have to play with this a bit because you are depending on HTML that is not in your control - I assume you'd like your GM script to run on any page - so you are limited to the structure of that page. There is no guarantee for example, that the :first <body> tag will be the correct one.

If you ask me, the one sure fire way to do this would be to iterate over all of the <body> elements that $('body') returns and for each one see if it has a parent element that is an Iframe.

Something like this -

var selectedElement = '';
$('body').each(function(index,elem){
  if ($(elem).closest('iframe').length){
    selectedElement = $(elem);
  }
});

if (selectedElement){
  // appendTo(selectedElement);
}

  • I'm using the .each() function to iterate over all the elements that match the given selector - in this case - body.

  • I'm using the .closest() function here to navigate through all of the parent elements and find the ancestor that matches the given selector - in this case - iframe.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Lix
  • 47,311
  • 12
  • 103
  • 131
  • yes thank you, I know but how can I do that? What selector is more unique than $('body') and exists in all pages? – kasper Taeymans May 12 '12 at 14:04
  • $('body:first') does not solve the issue. is there a list of selectors I could try? or maybe I have to select the body that is not in an iframe. – kasper Taeymans May 12 '12 at 14:13
  • thank you again! i've tried your method but $(elem).closest('iframe').length is always returning 0 so selectedElement can't be populated with the correct body tag. – kasper Taeymans May 12 '12 at 14:39
  • 1
    Your assumption of the cause is correct; you can remove the disclaimer. The solution is a little much for most occasions though. ;) – Brock Adams May 12 '12 at 23:17
2

Yes, this is caused by the fact that Greasemonkey treats each frame and iframe as its own page (which in a way, it is), and runs as the @include, @exclude, and/or @match directives indicate.
(Note that iframes without a src attribute are considered to be from the same URL as the base page.)

To stop a script from triggering on iframes, place this code near the top of your script:

if (window.top != window.self)  //-- Don't run on frames or iframes.
    return;


If you actually want to run on some iframes and not others, tune the @include, @exclude, and/or @match directives if possible, or link to the target page for help choosing a method to selectively block iframes.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295