Return to Snippet

Revision: 35129
at February 26, 2011 07:31 by harikaram


Updated Code
/**
 * Parse the external scripts and append them to the document seperately.
 * 
 * Ensures external libs are fully loaded prior to any script on the supplied html
 * The callback is give the html minus the previously injected external script tags.
 * 
 * @param	html	Source HTML content or jquery object
 * @param	callback	Function to call passing the modifed jquery HTML reference 
 */
loadContentScripts: function ( html, callback )
{
	// Grab the external script tags and strip from the html
	var workingHtml = $(html);
	var scripts = workingHtml.filter( 'script[src$=".js"]' ).clone();
	var v = this;
	
	// If no scripts then just callback
	if ( scripts.length == 0 ){
		callback( html );
		return this;
	}
	
	// Otherwise strip the scripts from the HTML
	html = workingHtml.not( 'script[src$=".js"]' );
	
	// Gather the script names for later as .data doesnt seem to work well
	var scriptLoadMap = new Array();
	scripts.each( function ( i, ele ) {
		scriptLoadMap[ $(ele).attr( 'src' ) ] = false;
	});
	
	// Add them seperately and set the callback
	scripts.appendTo( 'body' );
	
	// Handler to check whether all scripts have been loaded
	var done = false;
	var handler = function ( e ){	
		var loadedSrc = $( e.currentTarget ).attr( 'src' );
		
		if ( typeof( scriptLoadMap[ loadedSrc ] ) == 'undefined' )
			return;
				
		// Set this one to true
		scriptLoadMap[ loadedSrc ] = true;
		
		// Check whether they've all loaded
		var allLoaded = true;
		scripts.each( function ( i, ele ) {
			src = $(ele).attr( 'src' );
			allLoaded = allLoaded && scriptLoadMap[ src ];
		})
		
		// Call the CB if all are loaded
		if ( allLoaded && !done ){
			callback( html );
			done = true;	//only call once
		}
	};
	
	// IE compat event checking for a script's load
	// This grabs all the pages scripts but thanks to our handler thats ok
	$('script[src$=".js"]').load( handler ).each( function(){
			var thisSrc = $( this ).attr( 'src' );
			 
			// Don't bother unless its in out list
			if ( typeof( scriptLoadMap[ thisSrc ] ) == 'undefined' )
				return;
		
			// In case already loaded (like by cache), trigger manually
			if ( this.complete )	
				$( this ).trigger( 'load' );
				
			// Special case for IE
			else if ( $.browser.msie ){
				this.onreadystatechange = function () {
					if ( this.readyState == "loaded" || this.readyState == 'complete' )	// ie8 = loaded.  'complete' just in case...
						$( this ).load(); 
				};
			}
			
			// HKS Hack
			// Set a timeout period before we force the load, in case browser is acting up (eg. IE)
			window.setTimeout( 
				$.proxy( function ()
				{
					if ( done ) return;		// see above
					
					// Tell GA
					v._tracker.trackEvent( 'Errors', 'Script Timeout', thisSrc );
					
					if ( CONFIG.DEBUG )
						console.log( 'Script Load has timed out (' + CONFIG.SCRIPT_LOAD_TIMEOUT+'ms) for file "' + $(this).attr('src') + '".  Triggering load manually...' );
					
					if ( $.browser.msie )
						this.onreadystatechange = null;
					
					$( this ).load();		// triggers event
				}, this ), 
				CONFIG.SCRIPT_LOAD_TIMEOUT
			);
	});
	
	return this;
}

// USAGE:
var CONFIG = { SCRIPT_LOAD_TIMEOUT: 5000, DEBUG: 0 }
var html = 'Some html containing external scripts <script src="..."';
var container = $( '#content' );
var newContent = $( '<DIV>'+html+'</DIV>' );
 
loadContentScripts( newContent, function ( resultHtml ){
	container.append( resultHtml  );
} );

Revision: 35128
at November 3, 2010 03:07 by harikaram


Initial Code
/**
 * Parse the external scripts and append them to the document seperately.
 * 
 * Ensures external libs are fully loaded prior to any script on the supplied html
 * The callback is give the html minus the previously injected external script tags.
 * 
 * @param	html	Source HTML content or jquery object
 * @param	callback	Function to call passing the modifed jquery HTML reference 
 */
function loadContentScripts( html, callback )
{
		// Grab the external script tags and strip from the html
		var workingHtml = $(html);
		var scripts = workingHtml.filter( 'script[src$=".js"]' ).clone();
		html = workingHtml.not( 'script[src$=".js"]' );
		
		// Add them seperately and set the callback
		scripts.appendTo( 'head' );
		
		$('script').load( function ( e ){			
			var allLoaded = true;
					
			scripts.each( function ( i, ele ) {
				ele = $(ele);
				console.log( ele.data( 'isLoaded' ) );
				if ( ele.attr( 'src' ) == $( e.currentTarget ).attr( 'src' ) )
					ele.data( 'isLoaded', true );
				
				allLoaded = allLoaded && ele.data( 'isLoaded' );
			})
			if ( allLoaded ){
				callback( html );
			}
		} );

		return this;
}


// USAGE:
var html = 'Some html containing external scripts <script src="..."';
var container = $( '#content' );
var newContent = $( '<DIV>'+html+'</DIV>' );
		
loadContentScripts( newContent, function ( resultHtml ){
	container.append( resultHtml  );
} );

Initial URL


Initial Description
When injecting via jQuery HTML content which contains script tags referencing external scripts, which are then referenced via scripting elsewhere in the injected HTML, some browsers (Chrome) will not wait for the external scripts to load causing the internal scripts to throw an error.  This code parses the external script tags, loads them seperately and then calls the callback function passing the given HTML minus the external script tags for you to inject.
---------
UPDATE:  I've made this considerably more complex after some IE problems (really!).  Hope it helps someone out...

Initial Title
Load external scripts FIRST for injected DOM HTML content

Initial Tags
ajax, js, DOM, jquery, load

Initial Language
jQuery