0

I'm viewing this website that has a client side javascript error caused by the scripts being loaded in the wrong order. Problem is I don't own this source, but I really need to use the site ASAP.

Is there a way to do this with greasemonkey? The problem is that since this is loaded in the head element, if I modify the html the JS error has already occurred. But, if I refresh the changes (at least in chrome) my local modifications disappear.

Specifically, the html head element contains this:

<script 
    language="javascript" 
    src="/scripts/util.js" 
    type="text/javascript"></script>
<script 
    language="javascript" 
    src="/scripts/scriptaculous/prototype.js" 
    type="text/javascript"></script>
<script 
    language="javascript" 
    src="/scripts/scriptaculous/scriptaculous.js" 
    type="text/javascript"></script>

And to fix the bug, it would need to be like this:

<script 
    language="javascript" 
    src="/scripts/scriptaculous/prototype.js" 
    type="text/javascript"></script>
<script 
    language="javascript" 
    src="/scripts/scriptaculous/scriptaculous.js" 
    type="text/javascript"></script>
<script 
    language="javascript" 
    src="/scripts/util.js" 
    type="text/javascript"></script>

Notice how the util.js moved to the bottom.

I'm pretty close to doing this with a grease monkey script with this source:

// ==UserScript==
// @name        name
// @namespace   namespace
// @include     htmlfilewithbug
// @version     1
// @grant       none
// @run-at document-start
// ==/UserScript==

var loaded = false;

var loadScript = function(scriptName) {

    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = scriptName;
    head.appendChild(script);

};

window.onload = function() {
    loaded = true;
    loadScript('https://hostwithbug/scripts/scriptaculous/prototype.js');
    loadScript('https://hostwithbug/scripts/scriptaculous/scriptaculous.js');
    loadScript('https://hostwithbug/scripts/util.js');
};


document.onbeforescriptexecute = function() {   //control whether scripts get executed at all. FireFox feature
    return loaded;  
}

But I get this error that says this:

A call to document.write() from an asynchronously-loaded external script was ignored. @ https://hostwithbug/scripts/scriptaculous/scriptaculous.js:30

I don't know how to get around this. Perhaps there's some way for me to replace a head tag with one of my choosing? As far as I can tell, it would have to happen right before the head were to be rendered in order to avoid this error. I have not found any way to do this.

Regardless, I'm looking for a solution to the problem in my title: How can I change the order that the html's scripts are loaded?

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356

1 Answers1

1
// ==UserScript==
// @name        name
// @namespace   namespace
// @include     htmlfilewithbug
// @version     1
// @grant       none
// @run-at document-start
// ==/UserScript==

var countdown = 3;

var loadScript = function(scriptName) {

        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = scriptName;
        script.async = false;
        head.appendChild(script);

};

document.addEventListener('beforescriptexecute', function(e) {

        var src = e.target.src;
        if (src == '/scripts/util.js' || 
        src == '/scripts/scriptaculous/prototype.js' || 
        src == '/scripts/scriptaculous/scriptaculous.js') {
                e.preventDefault();
                e.stopPropagation();
                if(!--countdown) {
                        loadScript('https://hostwithbug/scripts/scriptaculous/prototype.js');
                        loadScript('https://hostwithbug/scripts/scriptaculous/scriptaculous.js');
                        loadScript('https://hostwithbug/scripts/util.js');
                }
        }

}, true);

Notes:

  1. I use countdown to monitor execution of scripts that we are concerned with, as I am not sure if the three script elements you mentioned are the only ones in the head element. Introducing countdown adds to robustness of my code. Also, countdown (along with script.async = false;) ensures we load, as early as possible, the three scripts in desired order.

  2. I am using addEventListener because it is the recommended form of usage on MDN.

References:

https://stackoverflow.com/a/3236373/735271

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#Attributes

Community
  • 1
  • 1
zanetu
  • 3,740
  • 1
  • 21
  • 17
  • Can you explain how this works? For example, what's the point of the `countdown`? Why are you using `addEventListener` instead of what I did? – Daniel Kaplan Dec 04 '13 at 17:31