views:

900

answers:

4

I want to reload a page so that it does not cause the effects of a full-page refresh, like displaying "Loading..." on the page's tab.

Here's the code I have so far. My theory was that I could overwrite the body section with a <frame>-wrapped version of the updated site, gotten via GM_xmlhttpRequest.

reloader.js

setInterval(reload, 10000);

function reload() {
    GM_xmlhttpRequest({method: 'GET',
      url: location.href,
      onload: function(responseDetails) {
       document.body.innerHTML =
                                '<frame>\n'
                                + responseDetails.responseText
                                + '</frame>\n';
      }});
}

When testing with Firebug on stackoverflow.com, I found that this script updates the body as if I had performed a full-page refresh, without the side effects. Yay! Mysteriously, the <frame> tags are nowhere to be found.

Questions

What I have right now does a good job of reloading the page, but I have two questions:

  1. How do I stay logged in after a reload? Specifically, what do I need to do to keep me logged in to Stack Overflow?
  2. Can someone explain why my script works? Why are there no <frame> tags within the body?

Updates

I've incorporated elements from Cleiton, Havenard, and Henrik's answers so far. I tried sending cookies via the header: { 'Cookie': document.cookie } entry in the data sent through GM_xmlhttpRequest. This sent some, but not all of the cookies. It turns out that if I turn on third party cookies in the Firefox then I'll get the necessary extra cookies (.ASPXAUTH, ASP.NET_SessionId, and user), but this is a bad idea.

+8  A: 
document.body.innerHTML =
     responseDetails.responseText.match(/<body>([\s\S]*)<\/body>/i)[1];

Update: For <body> with properties:

document.body.innerHTML =
     responseDetails.responseText.match(/<body[^>]*>([\s\S]*)<\/body>/i)[1];
Havenard
I tried your solution, but I don't get any matches. I've verified that the response text does have a set of `<body></body>` tags. Strangely, when I run your regexp against '<html><head></head><body><p>stuffhere</p>/body></html>', I get the expected match. Maybe I'm having Unicode problems?
Andrew Keeton
I figured out what was wrong! Apparently the . (dot) operator doesn't match newlines. Instead, you have to use `[\s\S]` to match _every_ character. The working regexp is `/<body>([\s\S]*)<\/body>/`.
Andrew Keeton
Also, this still leaves me logged out after reload.
Andrew Keeton
I should clarify: When I fetch stackoverflow.com from `GM_xmlhttpRequest` it obviously has no way to authenticate as me, so the page comes back as if I were not logged in. Moving to another part of the site manually gets a logged-in page.
Andrew Keeton
Maybe you need to grab the document.cookie together with the GM_xmlhttpRequest. It isn't regular use of XMLHttpRequest, but I don't know Greasemonkey or how it behaves... **Maybe this GM_xmlhttpRequest is not linked to the contempled domain**, so you have to manage it yourself placing setRequestHeader("Cookie", document.cookie) somewhere.
Havenard
@Havenard Can you please change your answer so that it includes the comment I made earlier about the regexp?
Andrew Keeton
Hum... apparently . matches thru newlines only on IE. Good observation. Looks weird as JS String.match() doesn't support the /s flag, it should work as it were enabled all the time. Btw, updated my answer so that it works on FF.
Havenard
+1  A: 

As for the logged in state I would expect this to be tracked via some form of session cookie. Make sure to set them explicitly in the GM_xmlhttpRequest header, as it does not do so by itself.

Not sure about the exact syntax right now, but it should be something like this:

GM_xmlhttpRequest({method: 'GET',
                url: location.href,
                headers: {'Cookie': document.cookie},
                onload: function(responseDetails) { ...
Henrik Opel
Maybe the cookies are [HTTP only] (http://www.codinghorror.com/blog/archives/001167.html)?
rq
Good Point, some are indeed. Care to add the comment to the original post?
Henrik Opel
+3  A: 

@Andrew Keeton,

First install fiddler in your machine and see if http requests made by GM_xmlhttpRequest are being sent with all cookies. if isnt go to about:config option "network.cookie.cookieBehavior" and set it to 0, do another test. if it works. you will be in trouble because there isnt a safe way to perform this change using greasemonkey and you will have to use @Henrik tricky.

Cleiton
That did it. By sending `document.cookie` in the header (@hopel's answer) I was able to send some, but not all cookies. Specifically, I was missing the .ASPXAUTH, ASP.NET_SessionId, and user cookies. Changing network.cookie.cookieBehavior to 0 sent those cookies, thus keeping me logged in.
Andrew Keeton
Unfortunately, as you said, there's no safe way to set network.cookie.cookieBehavior. In fact, doing so is equivalent to allowing third party cookies, which is bad news http://www.grc.com/cookies.htm.
Andrew Keeton
Actually, Google Analytics uses some JavaScript to capture all (to my understanding) cookies of the site you're visiting and sends those to Google Headquarters. So maybe peek into Google's ga.js?
Arjan
A: 

What site/sites are you trying to do this for?

Depending on what you need, if may be far easier/better to just change the timeout on the cookie they give you, you can set the expiry yourself, forever :)

Noon Silk