@run-at document-start in FF12 fires script twice on Facebook.com?

318 views
Skip to first unread message

Matt Kruse

unread,
May 24, 2012, 12:16:27 PM5/24/12
to greasemonkey-users
After updating FF from 3.6 to the current 12, user scripts run at
document-start (in certain situations) are firing twice - once at
document-start as intended, then again at document-end.

Sample script:
// ==UserScript==
// @name FB Test
// @namespace http://userscripts.org/users/86416
// @include https://www.facebook.com/
// @run-at document-start
// ==/UserScript==
alert(document.getElementsByTagName('BODY').length);

When viewing the home news feed, this alerts "0" (expected), but then
also alerts "1" after the document loads.
But when I log off and load the login page, it only alerts "0"!

Any idea if this is a Greasemonkey bug or a FF bug? Or a quick in
Facebook? I can't duplicate the same functionality on CNN.com, for
example.

Is Facebook doing something that causes GM to fire again?

I've not yet tested other browser versions, will do that as well.

Thanks!

Matt Kruse

LWChris@LyricWiki

unread,
May 24, 2012, 4:02:29 PM5/24/12
to greasemon...@googlegroups.com
I could well imagine some iframe that retriggers the script because two
"document-start" events are fired, maybe? Or does the page have two html
or body tags?

Matt Kruse

unread,
May 24, 2012, 11:28:28 PM5/24/12
to greasemonkey-users
On May 24, 3:02 pm, "LWChris@LyricWiki" <lwch...@gmx.de> wrote:
> I could well imagine some iframe that retriggers the script because two
> "document-start" events are fired, maybe? Or does the page have two html
> or body tags?

Nope, no iframes, and no multiple body tags. I've done tests, and it's
definitely firing twice on the same page.
For now, my work-around is to set a variable on unsafeWindow, and if
it's defined, I exit the script immediately.
I still have no clue as to what is different in this page that causes
it to trigger twice, and apparently not in FF3.6, but it does in FF12.

Matt

Sam Larison

unread,
May 25, 2012, 3:19:57 AM5/25/12
to greasemon...@googlegroups.com
Do you experience different results using the refresh button versus pressing enter in the URL bar?

Unless there is facebook specific code, I would venture a guess that this can be reproduced on another site...

An idea would be saving the facebook page as HTML and uploading it somewhere, although my guess is that won't trigger the same behavior.

--
You received this message because you are subscribed to the Google Groups "greasemonkey-users" group.
To post to this group, send email to greasemon...@googlegroups.com.
To unsubscribe from this group, send email to greasemonkey-us...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/greasemonkey-users?hl=en.


Anthony Lieuallen

unread,
May 25, 2012, 9:05:13 AM5/25/12
to greasemon...@googlegroups.com
On Thu, May 24, 2012 at 12:16 PM, Matt Kruse <ma...@thekrusefamily.com> wrote:
When viewing the home news feed, this alerts "0" (expected), but then
also alerts "1" after the document loads.

I do not see that behavior.  Try in a fresh profile:
http://wiki.greasespot.net/Troubleshooting_%28Users%29

Matt Kruse

unread,
May 29, 2012, 1:29:37 AM5/29/12
to greasemonkey-users
On May 25, 8:05 am, Anthony Lieuallen <arant...@gmail.com> wrote:
> On Thu, May 24, 2012 at 12:16 PM, Matt Kruse <m...@thekrusefamily.com>wrote:
> > When viewing the home news feed, this alerts "0" (expected), but then
> > also alerts "1" after the document loads.
> I do not see that behavior.  Try in a fresh profile:http://wiki.greasespot.net/Troubleshooting_%28Users%29

On a fresh profile, with only Greasemonkey running, with no other user
scripts, I see the same behavior.

This is Firefox 12.0, Greasemonkey 0.9.20 and exactly this user
script:

// ==UserScript==
// @name fb test
// @namespace xxx
// @include https://www.facebook.com/
// @run-at document-start
// ==/UserScript==
alert(document.getElementsByTagName('BODY').length);

I've tried using 3 different FB accounts, all with the same behavior.

I get an alert of "0" before page load, then "1" after the dom loads.

Any other ideas?

Matt Kruse

Sam Larison

unread,
May 29, 2012, 2:07:41 AM5/29/12
to greasemon...@googlegroups.com
The only guess I can venture is that the loading of XMLHTTP data by facebook is somehow triggering a document created event.

Sam Larison

unread,
May 29, 2012, 2:21:12 AM5/29/12
to greasemon...@googlegroups.com
Does it run again when you click a photo someone posted?

Anthony Lieuallen

unread,
May 29, 2012, 9:28:19 AM5/29/12
to greasemon...@googlegroups.com
On Tue, May 29, 2012 at 1:29 AM, Matt Kruse <ma...@thekrusefamily.com> wrote:
On a fresh profile, with only Greasemonkey running, with no other user
scripts, I see the same behavior.

How exactly do you navigate to the page the script runs on?  Windows?  Logged in to facebook?

Matt Kruse

unread,
May 29, 2012, 2:57:07 PM5/29/12
to greasemonkey-users
On May 29, 1:07 am, Sam Larison <samlari...@gmail.com> wrote:
> The only guess I can venture is that the loading of XMLHTTP data by
> facebook is somehow triggering a document created event.

I thought of this also, but I can't identify anything of this sort.
I'll keep looking.

> Does it run again when you click a photo someone posted?

YES! When it pops up the photo viewer, I get a "1". And when I pres
ESC to close it, I get a "1" again. So clearly, the event that
Greasemonkey is hooking into is being called multiple times. I didn't
realize that there was any way to manually trigger this event. Do you
have any clue what might be going on?

Matt Kruse

Matt Kruse

unread,
May 29, 2012, 2:59:15 PM5/29/12
to greasemonkey-users
On May 29, 8:28 am, Anthony Lieuallen <arant...@gmail.com> wrote:
> On Tue, May 29, 2012 at 1:29 AM, Matt Kruse <m...@thekrusefamily.com> wrote:
> > On a fresh profile, with only Greasemonkey running, with no other user
> > scripts, I see the same behavior.
> How exactly do you navigate to the page the script runs on?  Windows?
> Logged in to facebook?

I just log into Facebook and make sure I'm on the newsfeed. Refresh,
and the symptoms show.

I'm on Windows, but I'm not sure that's relevant. I haven't tested
other OS's.

Matt Kruse

Sam Larison

unread,
May 29, 2012, 3:03:24 PM5/29/12
to greasemon...@googlegroups.com
Yes, since document start fires onLocationChange - and the URL bar is updating to a new location (not simply using the #historycrumb method) - even though the dom is not destroyed - and even though the same document, body, and all the other elements are still there (behind the photo you click on) - facebook has used that new javascript API for directly modifying the URL bar and creating a history entry, which is fine, but unfortunately since this is how we currently detect document-start ( onLocationChange ) the script will fire again.  

A similar method that you use in script to prevent things from running (or otherwise decide to run something) could be implemented within greasemonkey however that solution is still not ideal.  If you match a certain page within facebook then you may not experience as many issues.

see window.history.pushState

http://stackoverflow.com/questions/824349/modify-the-url-without-reloading-the-page 


Matt Kruse

Matt Kruse

unread,
May 29, 2012, 3:11:03 PM5/29/12
to greasemonkey-users
On May 29, 2:03 pm, Sam Larison <samlari...@gmail.com> wrote:
> see window.history.pushState

Ah, I didn't realize that using pushState/replaceState would actually
trigger Greasemonkey to fire again. IMO, it really shouldn't, because
the DOM is not being re-loaded. Just because the url changes doesn't
necessarily mean that the page is changing, and you could run the risk
of a GM script being run twice or more on the same DOM.

I'm also finding that the script does not fire consistently. Even
though the url changes (I assume via pushState), the script is
sometimes not fired again. So it's not really dependable.

For now, I will stick with setting a flag on unsafeWindow, and exiting
my script if the flag is already set. That will guarantee that I run
only once. If there is a preferred work-around, let me know.

Thanks for the clarification!

Matt Kruse

Anthony Lieuallen

unread,
May 29, 2012, 4:46:52 PM5/29/12
to greasemon...@googlegroups.com
Thanks everyone for your work figuring this out so far.  It really should be reported as an issue which is tracked until it's fixed:

https://github.com/greasemonkey/greasemonkey/issues

Ideally, with a reproducible testcase which is standalone (not Facebook).  I'm a bit busy at the moment to do this myself, but if an issue is reported, I'll get to it when I have time.


Matt Kruse

Sam Larison

unread,
May 29, 2012, 6:42:08 PM5/29/12
to greasemon...@googlegroups.com
The event that fires for document-start script insertion [ tabLocationChange ] event itself probably holds some clues about what type of tab location change has occurred (this is my hope) and would make it easy to isolate when to run scripts and when not to.

Perhaps some scripts need updates as a result of this being fixed, although I agree they should never run again until a new document is created.

For people who will need to update their scripts; this may be relevant to users who wish to detect such events:

I am curious if you experience this or any similar problem in the behavior of document-end scripts on facebook, if not then existing document-end scripts probably pose a few solutions to the problem of detecting pushstate events.

Matt Kruse

unread,
May 29, 2012, 11:51:34 PM5/29/12
to greasemonkey-users
On May 29, 3:46 pm, Anthony Lieuallen <arant...@gmail.com> wrote:
> Thanks everyone for your work figuring this out so far.  It really should
> be reported as an issue which is tracked until it's fixed:

I think it needs more investigation...

> Ideally, with a reproducible testcase which is standalone (not Facebook).
> I'm a bit busy at the moment to do this myself, but if an issue is
> reported, I'll get to it when I have time.

I tried to create a simplified test case here:
http://socialfixer.com/temp/pushstate.html

And, the problem does not exhibit itself. So calling pushState by
itself is not enough. There is more going on. I'm going to dig in
further and see if I can figure out exactly what is triggering the GM
script to be re-executed.

Matt Kruse

Sam Larison

unread,
May 30, 2012, 12:09:41 AM5/30/12
to greasemon...@googlegroups.com
I am glad that you are committed to investigating this thoroughly.  I will likely fire up the test environment and see if I can figure out what's going on at some point, although pressing debt demands otherwise.  This issue is curious enough to merit attention.  Though I imagine I won't get far without digging into Firefox source code considering the limited nature of this problem.  I hope we can find at least one other site that reproduces such occurrence!


Matt Kruse

Anthony Lieuallen

unread,
May 30, 2012, 9:29:59 AM5/30/12
to greasemon...@googlegroups.com
On Tue, May 29, 2012 at 11:51 PM, Matt Kruse <ma...@thekrusefamily.com> wrote:
I tried to create a simplified test case here:
http://socialfixer.com/temp/pushstate.html

And, the problem does not exhibit itself. So calling pushState by
itself is not enough. There is more going on. I'm going to dig in
further and see if I can figure out exactly what is triggering the GM
script to be re-executed.

Ultimately, we're looking for whatever causes onLocationChange to be called:
https://github.com/greasemonkey/greasemonkey/blob/master/content/browser.js#L29

https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIWebProgressListener#onLocationChange%28%29

Neil Weinstock

unread,
May 30, 2012, 10:15:09 AM5/30/12
to greasemon...@googlegroups.com
Hi all,
Right now I'm dealing with a similar problem with my otherwise working script for Rally.  I routinely see up to three copies of the script running simultaneously.

I use waitForKeyElements() to trigger on the particular Rally page I want to work on.

So, as per the previous suggestion in this thread, I added the following wrapper to my script:

if (unsafeWindow.monkeyRunning === undefined) {
    unsafeWindow.monkeyRunning = "running";
 
        <the rest of my script>
}

This doesn't work at all.  As each script is triggered, the variable unsafeWindow.monkeyRunning *always* starts out undefined.  Which probably means I did something wrong here, but I'm not sure what else I should be doing.

Just checked, now I have 4 copies of the script running.

As before, it is hard to provide a publicly available test site for this problem, because Rally subscriptions are private.  I can try again if needed.

- Neil 


--

Sam Larison

unread,
May 30, 2012, 11:45:27 AM5/30/12
to greasemon...@googlegroups.com
aProgress.isLoadingDocument is probably what is tripping it up

https://developer.mozilla.org/en/nsIWebProgress 

This is the start point for the listener documentation


Monitoring onStateChange ourselves will possibly provide some clues or a workaround

Within facebook we might try something, I found the code for the history manager, could try over-riding it and see if the problem goes away

__d("HistoryManager", ["event-extensions", "function-extensions", "Cookie", "Env", "URI", "UserAgent", "copyProperties", "goOrReplace"], function (a, b, c, d, e, f) {return;});

Calling that may or may not do it!

For whatever reason facebook seems to be including it twice... found it inside two of their JS files, so calling the function again may over-ride it.  I didn't notice anything too suspicious in the manager itself.

On Wed, May 30, 2012 at 9:29 AM, Anthony Lieuallen <aran...@gmail.com> wrote:

Sam Larison

unread,
May 30, 2012, 11:48:10 AM5/30/12
to greasemon...@googlegroups.com
Is this script running at document-start?  Probably the easiest way to detect if it has run previously is attach a div with a unique ID to document.body

Neil Weinstock

unread,
May 30, 2012, 1:21:49 PM5/30/12
to greasemon...@googlegroups.com
For whatever reason, I had no luck attaching a <div> to the body.  However, I didn't need to figure that out because I figured out the *real* cause of my problem: iframes.  The script was triggering on each iframe.

I fixed that with belt and suspenders: First, I tweaked the "include" statement to match only the main URL, and not any of the iframe URLs.  Because I'm not 100% sure that'll always work perfectly, I also added a check inside the script for body#main, which is only used for the main page.

Seems to work properly now.  At some point I'll need to mess around further and see why I wasn't able to add the div as suggested, but for now I'll settle for a working script.

Thanks,
Neil

Anthony Lieuallen

unread,
May 30, 2012, 1:47:56 PM5/30/12
to greasemon...@googlegroups.com
if (window != window.top) return;

Matt Kruse

unread,
May 30, 2012, 4:02:26 PM5/30/12
to greasemonkey-users
On May 30, 10:45 am, Sam Larison <samlari...@gmail.com> wrote:
> aProgress.isLoadingDocument is probably what is tripping it up
> https://developer.mozilla.org/en/nsIWebProgress
> This is the start point for the listener documentation
> https://developer.mozilla.org/En/XUL/Method/AddTabsProgressListener
> Monitoring onStateChange ourselves will possibly provide some clues or a
> workaround
> Within facebook we might try something, I found the code for the history
> manager, could try over-riding it and see if the problem goes away
> __d("HistoryManager", ["event-extensions", "function-extensions", "Cookie",
> "Env", "URI", "UserAgent", "copyProperties", "goOrReplace"], function (a,
> b, c, d, e, f) {return;});

I got it! After debugging for quite some time (Facebook code is
ridiculously, unnecessarily complex), I found the culprit.

Their code is calling window.history.replaceState BEFORE the window is
loaded, which is triggering GM to fire again.
I've created the simplest test case I can that also fails:
http://socialfixer.com/temp/replacestate.html

In this test, I call replaceState() on DOMContentLoaded, and it in
turns fires the script again. The example "detection" script I am
using can be found on this page also.

I also noticed that FB is calling replaceState with only two
arguments, and no url. I'm not sure if this is part of the problem
too?

Hope this helps. Do you need any further investigation from me? I know
very little about how GM integrates into Firefox, so how you hook into
their events is beyond me :)

Matt Kruse

Anthony Lieuallen

unread,
May 30, 2012, 4:06:14 PM5/30/12
to greasemon...@googlegroups.com
This is great.  The only thing further I could as is an issue at github (link earlier in this thread) and the test case pasted into http://gist.github.com/ .

Matt Kruse

unread,
May 30, 2012, 4:58:54 PM5/30/12
to greasemonkey-users
On May 30, 3:06 pm, Anthony Lieuallen <arant...@gmail.com> wrote:
> This is great.  The only thing further I could as is an issue at github
> (link earlier in this thread) and the test case pasted intohttp://gist.github.com/.

I don't know anything about using github, or what gist is. I think
someone else would be better suited to take my test case and
officially enter it.
If no one wants to take that up, I'll look into doing this another
day.

Matt Kruse

Sam Larison

unread,
May 31, 2012, 4:45:45 PM5/31/12
to greasemon...@googlegroups.com
I will handle opening the issue and test case sometime between today and tomorrow.

Reply all
Reply to author
Forward
0 new messages