Reputation: 7454
This code works fine in Chrome. However, in Firefox, when it hits the GMxhr request, it simply stops. It gets right up to the GMxhr call, then just... stops. I've checked everything I can think of, making sure that the responseType param is only set for chrome, etc... yet still nothing. Any ideas?
var body = document.getElementsByTagName('body')[0]
, messageDiv = document.createElement('div')
;
messageDiv.id = 'xhrComlink';
body.appendChild(messageDiv);
function getUri(e) {
'use strict';
var chrome = navigator.userAgent.toString().toLowerCase().indexOf('chrome') !== -1;
var bin2base64 = function bin2base64 (binary) {
...
};
var storeRetrievedFile = function storeRetrievedFile(response) {
console.log(2);
var thisComlink = e.target
, evt = document.createEvent("MouseEvents")
;
var text = response.responseText
, len = text.length
, arr = new Uint8Array(len)
, i = 0
;
if (!chrome) {
for( i = 0; i < len; ++i ) {
arr[i] = text.charCodeAt(i) & 0xFF;
}
}
thisComlink.innerHTML = '';
thisComlink.appendChild(
document.createTextNode(
chrome ? bin2base64(response.responseText) : bin2base64(arr.buffer)
)
);
evt.initMouseEvent("dblclick", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
thisComlink.dispatchEvent(evt);
};
var gmXOptions = { method : 'GET'
, overrideMimeType : 'text/plain; charset=x-user-defined'
, onload : storeRetrievedFile
, url : e.target.innerHTML
};
chrome && (gmXOptions.responseType = 'arraybuffer');
console.log(1);
GM_xmlhttpRequest(gmXOptions);
}
In the console, I get only "1" on Firefox. In Chrome, I get "1", "2", it rewrites the innerHTML, fires the event, and off we go.
I have also checked to make sure that Firefox has everything correct, with a dir of the gmXOptions at the same spot as the log(1) call:
Firefox:
method "GET"
overrideMimeType "text/plain; charset=x-user-defined"
url "http://www.home...e-and-land-packages.jpg"
onload storeRetrievedFile(response)
EDIT to explain the answer; maybe this'll help someone else in the future:
Firefox's GM has an annoying behaviour/bug:
1) Write a userscript which attaches an event listener. In that event listener function, such as getUri() above, use a GM_ function.
2) Now invoke that event's trigger from any other javascript context except for the one which just created the listener. For example, use the common Chrome-friendly "inject jquery, callback to main(), continue" pattern.
3) But doing that, you lose access to GM functions in main(). So you have to put them right at the start of the script, outside of main(), before you inject jQuery, then "communicate" between those GM-using (a GM context) functions and the functions in main (an injected, non-GM context), in this case w/events.
Result) In GM terms, unsafeWindow is calling GM_xmlhttpRequest. That triggers the "security" in Firefox Greasemonkey, and it silently blocks the call to GM_xmlhttpRequest. You have to use the workaround to get the stack "cleaned up" enough to make Firefox GM's "security" happy. Then it will call the GM_xmlhttpRequest.
Upvotes: 2
Views: 2454
Reputation: 7454
I finally found the problem, though Firefox Greasemonkey makes it REALLY hard to find, and for whatever reason, it wasn't throwing any error/warning/etc messages at all, which might have helped solve this faster.
Anyhow, this was the problem: http://wiki.greasespot.net/0.7.20080121.0_compatibility
Add
setTimeout(function() {
and
}, 0);
around the GM_xhr call, and all now works as it should.
Upvotes: 2