Thursday, February 01, 2007

Managing include files in Javascript

As I continue to write Javascript libraries for use on various projects, I decided it was time to write a simple include() function so that I don't have to manually add superfluous <script></script> tags that I may or may not need on any given page.

Using the XMLHttpRequestObject, I was able to create an asynchronous request to fetch the source of my .js file. Then I create a new script object and set the .text or .innerHTML attribute of that object (depending on browser - IE requires .text) to the fetched source. So far I've tested it in IE 6 and FF 1.5.

Usage for including "/script/myscript.js":
Note: in reality, the include() call would be done from inside another .js file.

<head>
<script language="Javascript" src="ScriptManager.js" type="text/javascript"></script>
<script language="Javascript" type="text/javascript">
ScriptManager.script_base_link = '/script'; //set up our base link
//ScriptManager.script_file_extension = '.js'; //defaults to .js
ScriptManager.ErrorHandler.silent = false; //set to true or remove in production

try {
ScriptManager.include( 'myscript' );
}
catch (e) {
ScriptManager.ErrorHandler.handle_error( e );
}

</head>

And that's all.
The code for ScriptManager.js is below.
Copy & paste this into ScriptManager.js:


function ErrorHandler() {


}

ErrorHandler.handle_error = function ( e ) {

try {
ErrorHandler.show_error( e.message );
}
catch(e) {
}

}

ErrorHandler.show_error = function( message ) {

try {
if ( !ErrorHandler.silent ) {
alert( message );
}
}
catch(e) {
}

}

function HTTPRequest() {

//
// Properties
//
this.request_object = null;
this.async = true;
this.onreadystatechange = null;

//
// Methods
//
this.get_request_object = get_request_object;
this.send = send;
this.is_busy = is_busy;
this.abort = abort;
this.get_readyState = get_readyState;
this.get_status = get_status;
this.get_responseText = get_responseText;

function get_request_object() {

try {

if ( !this.request_object ) {

var http_request;

if ( typeof(XMLHttpRequest) != 'undefined' ) {
http_request = new XMLHttpRequest();
}
else {

try {
http_request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch(inner_e) {

try {
http_request = new ActiveXObject('Microsoft.XMLHTTP');
}
catch(inner_e2) {
}
}
}

this.request_object = http_request;
}

return this.request_object;
}
catch(e) {
throw e;
}
}

function get_readyState() {

try {
if ( request_obj = this.get_request_object() ) {
return request_obj.readyState;
}

return null;
}
catch( e ) {
throw e;
}

}

function get_status() {

try {
if ( request_obj = this.get_request_object() ) {
return request_obj.status;
}

return null;
}
catch( e ) {
throw e;
}

}

function get_responseText() {

try {
if ( request_obj = this.get_request_object() ) {
return request_obj.responseText;
}

return null;
}
catch( e ) {
throw e;
}

}

function send( which_url ) {

try {
var http_request_obj;

if ( !(http_request_obj = this.get_request_object()) ) {
throw 'Your web browser does not support this function.';
}

if ( this.is_busy() ) {
this.abort();
}

if ( this.onreadystatechange ) {
http_request_obj.onreadystatechange = this.onreadystatechange;
}
http_request_obj.open("GET", which_url, this.async);
http_request_obj.send(null);

}
catch(e) {
throw e;
}


}

function is_busy() {

try {
if ( request_obj = this.get_request_object() ) {

switch ( request_obj.readyState ) {
case 1,2,3:
return true;
break;
default:
return 0;
break;
}
}

return 0;
}
catch(e) {
throw e;
}


}

function abort() {

try {
if ( this.request_object ) {
this.request_object.onreadystatechange = null;
this.request_object.abort();
}
}
catch(e) {
throw e;
}
}

}

HTTPRequest.READYSTATE_COMPLETED = 4;
HTTPRequest.STATUS_OK = 200;

////
//// ScriptManager
////
function ScriptManager() {

}

ScriptManager.include = function( file_name ) {

try {
var file_path;
var head;
var body;
var request = new HTTPRequest();
var script_obj;

script_obj = document.createElement('script');
script_obj.setAttribute('type', 'text/javascript');

if ( !ScriptManager.has_script_file_extension(file_name) ) {
file_name = file_name + ScriptManager.script_file_extension;
}

file_path = ScriptManager.script_base_link + '/' + file_name;

request.async = false;
request.send( file_path );

if ( typeof(script_obj.text) != 'undefined' ) {
script_obj.text = request.get_responseText();
}
else if ( typeof(script_obj.innerHTML) != 'undefined' ) {
script_obj.innerHTML = request.get_responseText();
}

if ( head = document.getElementsByTagName('head')[0] ) {
head.appendChild(script_obj);
}
else if ( body = document.getElementsByTagName('body')[0] ) {
body.appendChild(script_obj);
}
else {
throw 'ScriptManager::include requires a or tag';
}

}
catch ( e ) {
ScriptManager.ErrorHandler.handle_error(e);
}
}

ScriptManager.has_script_file_extension = function( file_name ) {

try {
var ext = ScriptManager.script_file_extension;

if ( ext ) {
if ( file_name.substring(file_name.length - ext.length, file_name.length) == ext ) {
return true;
}
}

return 0;
}
catch ( e ) {
throw e;
}

}

ScriptManager.script_base_link = '';
ScriptManager.script_file_extension = '.js';

ScriptManager.ErrorHandler = ErrorHandler;
ScriptManager.ErrorHandler.silent = true;




How to include files in javascript
javascript including files
javascript require file
javascript include()
javascript xmlhttprequest include
script object