moularization of scripts
|
|
Hi, I wonder, if there is a possibility to modularize scripts. Some scripts contain hundred of lines of code which makes them difficult to read and understand and also more difficult to maintain. I am currently working on a script which gets bigger from day to day. Is there a possibility to organize userscripts in multiple files (for example one file for each definition of a class and seperate files for small library like sets of functions)? In a way that the definitions in one file will be visible to each other and that installation by the end user still can be done by one click? |
|
|
I believe it's possible to load the files from some url, like If you're doing something for exclusive personal use like me, it won't matter. |
|
|
You can only modify the HTML by adding script code to it as strings.
But really,
|
|
|
what userscript needs this much code?I'm sure some scripts have a helluvalot of lines of code. My longest script is my google extra script which I believe has almost 600 lines of code, and that's a relatively simple script. EDIT: looking at my script list again, it seems my facebook colour changer script is over 1000 lines of code, but a fair chunk of that is data URLs and some functions I used from elsewhere. |
|
|
>> a lot. BUT even short scripts would benefit from js libraries. |
|
|
Depending on how you want to use the included library, you might find this useful:
|
|
|
Here's a horrible nasty hack of a solution! Using GM_xmlhttpRequest it's possible to load the contents of an external javascript file and evaluate the resulting xml response as a javascript string. This doesn't work with a Ideally the GM_xmlhttpRequest call would be executed synchronously, but I'm not sure if that's possible. Consequently I've used a polling function to wait until all requested have been submitted and processed. Another issue is not being able to process the request in global scope, so the script code is stored in an array for evaluation within the scope you want to use it. That means you have to evaluate it every time you want it, which is a pain. In a way, this doesn't really help because the code's 150 lines long. You could condense it down and strip out the white space, and you only need to include one line in each userscript i suppose. There's got to be a more elegant way of doing this. Anybody?
var ScriptLibraries = {
scriptURLs: [],
scriptData: [],
onLoad: function(){},
// _submitXmlRequests
_submitXmlRequests: function()
{
for (var i = 0 ; i < ScriptLibraries.scriptURLs.length ; i++ )
{
GM_xmlhttpRequest
({
url: ScriptLibraries.scriptURLs[i],
onload: ScriptLibraries._processXmlResponse,
onerror: function(xmlhttpResponse) { ScriptLibraries.scriptData.push( new function() { this.src = ""; this.code = "error" + xmlhttpResponse.status + ": " + xmlhttpResponse.statusText; return this; } ); },
method:"GET"
});
}
},
// _processXmlResponse
_processXmlResponse: function(xmlhttpResponse)
{
var s = xmlhttpResponse.responseText;
if (s.substring(0, 55) == "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">")
{
s = "error" + xmlhttpResponse.status + ": " + xmlhttpResponse.statusText;
}
ScriptLibraries.scriptData.push( new function() { this.src = ""; this.code = s; return this; } );
},
// _waitUntilLoaded
_waitUntilLoaded: function()
{
if ((this.scriptURLs.length == this.scriptData.length) && (this.scriptData[this.scriptData.length-1].code != ""))
{
this._whenFinished();
}
else
{
window.setTimeout( function() { ScriptLibraries._waitUntilLoaded(); } , 250, false);
}
},
// _whenFinished
_whenFinished: function()
{
for (var i = 0 ; i < ScriptLibraries.scriptData.length ; i++ )
{
var sData = this.scriptData[i];
var sURL = this.scriptURLs[i];
sData.src = sURL.substring(( (sURL.indexOf("/") >= 0) ? sURL.lastIndexOf("/")+1 : 0 ), sURL.length-3);
if (sData.code.substring(0, 5) == "error")
{
sData.code = "alert(\"" +
"Error loading script file \\n\\\"" + sURL + "\\\"\\n\\n" +
sData.code.substring(5, sData.code.length) + "\\n " +
"\");";
}
}
ScriptLibraries.onLoad();
},
// loadLibraries
loadLibraries: function()
{
this._submitXmlRequests();
this._waitUntilLoaded();
},
// script
script: function(sScriptFile)
{
for (var i = 0 ; i < this.scriptData.length ; i++ )
{
if (sScriptFile == this.scriptData[i].src)
{
return this.scriptData[i].code;
}
}
return "alert(\"Script file \\\"" + sScriptFile + ".js\\\" not loaded.\");";
}
};
// doStuff
// function which will be fired after all libraries have been loaded.
// this is where the script should start performing it's processing.
function doStuff()
{
eval(ScriptLibraries.script("string"));
var s = new String("hello world");
alert(s.left(5));
}
with (ScriptLibraries)
{
// build the array of libraries you wish to import
scriptURLs = [
"http://localhost:6670/javascript/string.js"
];
// assign the on complete handler to run the "doStuff" function when libraries have finished being loaded
onLoad = doStuff;
// load the libraries
loadLibraries();
}
|
|
|
Wait for GM 0.8, it adds two new headers @require and @resource |
|
|
Thanks for your help.
Inclusion of librarys the user installed himself in his browser is ok. The most userfriendly solution seems still to put everything into a single script file (I did so, and the script I work on has now more than 800 lines...) |
|
|
I *thought* greasemonkey does something like wrap in an anonymous function, execute, and throw away? If that was the case, this wouldnt be possible. However, if you set your functions under a global namespace i.e. object, then you could access them in different scripts. |
