PDA

View Full Version : [JS] Import Script



Trinithis
05-23-2007, 04:56 AM
1) CODE TITLE: Import Script

2) AUTHOR NAME/NOTES: Trinithis

3) DESCRIPTION: Allows you to import external scripts using JS.


Example:
http://trinithis.awardspace.com/importScript/importScript.html


importScript source code:
http://trinithis.awardspace.com/importScript/importScript.js


function importScript(u) {
var s = document.createElement("script");
s.type = "text/javascript";
s.src = u;
document.getElementsByTagName("head")[0].appendChild(s);
}



I've tested on FF-1.0 and IE-6.0 and the head tag exists even in pages without a head tag explicitly defined. It should be noted that the imported script is evaluated after the current script tag, but before the following (if any) script tags.

Twey
05-23-2007, 01:06 PM
Works, but loading it synchronously via document.write() has its advantages too (using the DOM to load it asynchronously will break scripts using document.write(), for example).
function import(uri, callback, sync) {
if(sync)
document.write('<script type="text/javascript" src="' + encodeURI(uri) + '"></script>');
else {
var s = document.getElementsByTagName("head").appendChild(document.createElement("script"));
s.type = "text/javascript";
s.src = uri;
s.onload = callback;
}
}Synchronous loading won't work in XHTML pages, but that's OK, because none of the things for which synchronous loading would be required are either :p

Trinithis
05-23-2007, 04:24 PM
("import" is keyworded btw.)

Hmm, I'll try it, but when I've tried document.write()/close(), on some pages it will erase all the text before it. May I inquire about the callback paramater? And shouldn't the s.src uri be encoded as well (if it is, then I forgot to do that)?

Twey
05-23-2007, 04:58 PM
Oh, so it is.
Hmm, I'll try it, but when I've tried document.write()/close(), on some pages it will erase all the text before it.This happens when the page has already finished loading. It's only intended to be used inline while the page is loading.
May I inquire about the callback paramater?A function to call when the script has finished loading, if async.
And shouldn't the s.src uri be encoded as well (if it is, then I forgot to do that)?No, I don't think it's necessary. I could be wrong, but I think the DOM will do it automatically.

mwinter
05-23-2007, 06:01 PM
If I can interject for a moment with two words: feature detection.





May I inquire about the callback paramater?

This happens when the page has already finished loading.

It might be better for the included script to use a predefined function, rather than relying upon an event that may not fire; script objects don't (necessarily) dispatch load events.





And shouldn't the s.src uri be encoded as well (if it is, then I forgot to do that)?

No, I don't think it's necessary. I could be wrong, but I think the DOM will do it automatically.

The URI should be correct, but it's up to the user to ensure that. For instance, if the query string contains a hash character (#) that's not a fragment delimiter, it's up to the user to encode it (&#37;35): you cannot know which is always right.

Twey
05-23-2007, 06:46 PM
If I can interject for a moment with two words: feature detection.I don't much bother supporting DOM-2 incompliant browsers any more. I mostly just lump them in with non-JS browsers when I think about them at all. I think all the commonly-used browsers today are at least workably compliant with DOM-2? Excepting IE's events, of course.

Trinithis
05-23-2007, 08:12 PM
I noticed that the the callback only occurs if async, so I "combined" the two paramaters into an optional one. By default, it is asyncronized because of XHTML. I left the encoding in for the user's convenience.

Async: Import("xxx.js")==Import("xxx.js", false)==Import("xxx.js", 0)
Async w/callback: Import("xxx.js", function)
Sync: Import("xxx.js", true)==Import("xxx.js", 1)

(@mwinter: I can't fathom putting a .js file on the other side of a frag delimitor. It doesn't make sense, but perhaps some other non-encoded characters would make sense, but I would have to see one first to believe.)



function Import(uri, x) {
if(x==undefined) x = false;
if(x==true) {
document.write('<script type="text/javascript" src="' + encodeURI(uri) + '"><\/script>');
document.close();
}
else {
var s = document.getElementsByTagName("head")[0].appendChild(document.createElement("script"));
s.type = "text/javascript";
s.src = uri;
s.onload = x ? x : function(){};
}
}

Twey
05-23-2007, 08:42 PM
if(x==undefined) x = false;No need for this, undefined is falsy anyway.
if(x==true) {No need for the ==true, it's implied by the if.
document.close();Don't close the document, the user might not have finished writing to it.
s.src = uri;In light of what Mike said, let's encode it, eh?
s.onload = x ? x : function(){};This is pointless -- if the onload isn't a function, it won't be executed anyway.
function importScript(uri, x) {
if(x)
document.write('<script type="text/javascript" src="' + encodeURI(uri) + '"><\/script>');
else {
var s = document.getElementsByTagName("head")[0].appendChild(document.createElement("script"));
s.type = "text/javascript";
s.src = encodeURI(uri);
s.onload = x;
}
}
It might be better for the included script to use a predefined function, rather than relying upon an event that may not fire; script objects don't (necessarily) dispatch load events.Hmm, it's worked in all the browsers in which I've ever tried it... I think it might be cause for a warning message with the script, but probably not exclusion of the whole feature.

mwinter
05-23-2007, 10:32 PM
I don't much bother supporting DOM-2 incompliant browsers any more.

Shame, considering the level of "support" here is trivial to implement (though I didn't have time when I posted last).



I noticed that the the callback only occurs if async, so I "combined" the two paramaters into an optional one. By default, it is asyncronized because of XHTML.

What's special about XHTML? If you're referring to the DOM differences between HTML (and pseudo-XHTML) and XHTML, might I remind you that XHTML uses namespaces, therefore the namespace-aware methods would need to be used.

For many non-trivial scripts, one written for a HTML (or pseudo-XHTML) DOM cannot be used for a XHTML DOM.



I can't fathom putting a .js file on the other side of a frag delimitor.

The other side? No, I was referring to a hash character that was part of the query string. If included literally, it would be interpreted as fragment delimiter.



It doesn't make sense, but perhaps some other non-encoded characters would make sense, but I would have to see one first to believe.

The example of the fragment delimiter was the first to come to mind, and I was in a rush. Perhaps a more feasible, though still uncommon, example would be an ampersand (&) or equals (=) when the script is dynamically generated.

My point was that these details are for the user to resolve, not the include script.



In light of what Mike said, let's encode it, eh?

That wasn't the conclusion to be drawn.



Hmm, it's worked in all the browsers in which I've ever tried it...

The innerHTML property probably also worked in the majority of browsers you've tried, yet you were quite set against it, citing a lack of formal specification. The same applies to the load event in this context.



I think it might be cause for a warning message with the script, but probably not exclusion of the whole feature.

I didn't suggesting excluding the feature, just implementing it differently: at the end of the included script - let's call it utilities.js - there could be the following:



if (typeof utilitiesCallback == 'function') utilitiesCallback();

This is entirely reliable.



function include(uri, dynamic) {
if (dynamic) {
var head, script;
if (document.createElement && document.getElementsByTagName
&& (head = document.getElementsByTagName('head')[0]) && head.appendChild
&& (script = document.createElement('script'))) {
script.type = 'text/javascript';
script.src = uri;
head.appendChild(script);
} else return false;
} else document.write('<script type="text/javascript" src="' + uri + '"><\/script>');
return true;
}

Twey
05-24-2007, 05:59 PM
The innerHTML property probably also worked in the majority of browsers you've tried, yet you were quite set against it, citing a lack of formal specification. The same applies to the load event in this context.The difference was that there is an alternative to innerHTML. In light of your suggestion, I'll agree that the load event probably shouldn't be used.