Commits

Gary Chambers committed 70cdf46

Renamed Bootstrap module to Loader.

Comments (0)

Files changed (1)

src/addons/loader.js

+/**
+Loads external resources into the current environment.
+Handles nested dependencies and deferred resource loading.
+By default, resources will load after the window.onload event.
+
+@class Loader
+@constructor
+@category addon
+**/
+Jazz.ns.set("Loader", (function(window, document, undefined) {
+	"use strict";
+
+	var Loader,
+
+		_isLocal,
+		_load,
+		_queue;
+
+	/**
+	Determines whether the resource is local or remote
+
+	@method _isLocal
+	@private
+	@param {String} path The resource pathname
+	@return {Boolean}
+	**/
+	_isLocal = function _isLocal(path)
+	{
+		// TODO: add hostname checking for schemeless URIs
+		return !/^(?:https?:)?\/\//.test(path);
+	};
+
+	/**
+	Loads the defined dependency graph.
+	
+	@method _load
+	@private
+	@param {Object} loader An instance of Jazz.Loader
+	@param {Function} fn Callback to be invoked after all resources have loaded
+	@return {Undefined}
+	**/
+	_load = function _load(loader, fn)
+	{
+		if(!loader.dependencies)
+		{
+			fn();
+			return;
+		}
+
+		_load(loader.dependencies, function()
+		{
+			var counter;
+			counter = 0;
+
+			Jazz.iter.forEach(loader.resources, function(path)
+			{
+				var resolvedPath,
+					script;
+
+				if(Loader.Cache.get(path))
+				{
+					fn();
+					return;
+				}
+
+				script = document.createElement("script");
+
+				Jazz.event.on(script, Loader.Config.get("_loadEvent", "load"), function(e)
+				{
+					var complete;
+
+					complete =
+						!this.readyState
+							|| this.readyState === "complete"
+							|| this.readyState === "loaded";
+
+					if(complete)
+					{
+						counter++;
+
+						if(counter === loader.resources.length)
+						{
+							Loader.Cache.set(path, true);
+							fn();
+						}
+					}
+				});
+
+				resolvedPath = Loader.Alias.get(path, path);
+
+				if(Loader.Config.get("debug")
+					&& _isLocal(resolvedPath))
+				{
+					resolvedPath = resolvedPath + "?_tstamp=" + (new Date()).getTime();
+				}
+
+				script.setAttribute("src", resolvedPath);
+			});
+		});
+	};
+
+	/**
+	Queues the resource loader for execution.
+	Always fires a timeout - default 0ms - to push invocation down the execution stack.
+
+	@method _queue
+	@private
+	@param {Object} bootsrap An instance of Jazz.Loader
+	@return {Undefined}
+	**/
+	_queue = function _queue(loader)
+	{
+		var args;
+		args = [loader, function()
+		{
+			Jazz.iter.forEach(loader.callbacks, function(fn)
+			{
+				fn();
+			});
+		}];
+
+		window.setTimeout(function() {
+			_load.apply(null, args);
+		}, loader.wait);
+	};
+
+	Loader = Jazz.Class.create({
+
+		init: function init()
+		{
+			var args,
+				self;
+
+			self = this;
+
+			this.callbacks = [];
+			this.dependencies = null;
+			this.resources = [];
+			
+			this.event = Loader.Config.get("event", {});
+			
+			this.defer = false;
+			this.wait = 0;
+
+			args = Jazz.iter.toArray(arguments);
+			this.add.apply(this, args);
+
+			if(!this.defer)
+			{
+				if(this.event.hasOwnProperty("elem")
+					&& this.event.hasOwnProperty("type"))
+				{
+					Jazz.event.on(this.event.elem, this.event.type, function(e)
+					{
+						_queue(self);
+					});
+				}
+				else
+				{
+					_queue(self);
+				}
+			}
+		},
+
+		/**
+		Adds resources to the loader queue for parallel loading.
+
+		@method add
+		@param {String} path* One or more resource paths
+		@chainable
+		**/
+		add: function add()
+		{
+			this.resources = this.resource.concat(
+				Jazz.iter.toArray(arguments)
+			);
+
+			return this;
+		},
+
+		after: function after(fn)
+		{
+			this.callbacks.push(fn);
+		},
+
+		/**
+		Delays invocation for a specified number of milliseconds.
+		Used in combination with "Loader#on", this will delay invocation
+		for the specified time, *after* the event has fired.
+
+		@method delay
+		@param {Number} wait The number of milliseconds to delay invocation
+		@chainable
+		**/
+		delay: function(wait)
+		{
+			this.wait = wait;
+			return this;
+		},
+
+		/**
+		Defines the dependency tree for the queued resources
+
+		@method depends
+		@param {Mixed} path* One or more resource paths, or nested arrays indicating a tree structure
+		@chainable
+		**/
+		depends: function depends()
+		{
+			var args,
+				loader;
+
+			args = Jazz.iter.toArray(arguments);
+
+			loader = this.dependencies || new Loader();
+			loader.defer = true;
+
+			loader.add.apply(loader, args);
+			
+			return this;
+		},
+
+		/**
+		Marks the resource chain for immediate invocation.
+
+		@method now
+		@chainable
+		**/
+		now: function now()
+		{
+			this.event = {};
+			return this.delay(0);
+		},
+
+		/**
+		Binds the loader to a specified browser event.
+
+		@method on
+		@param {HTMLElement} elem The target element of the bound event
+		@param {String} eventType The specified event
+		@chainable
+		**/
+		on: function on(elem, eventType)
+		{
+			this.event = {
+				elem: elem,
+				type: eventType
+			};
+
+			return this;
+		}
+
+	});
+
+	Jazz.iter.forEach(["Alias", "Cache", "Config"], function(key)
+	{
+		Loader[ key ] = Jazz.Storage.load("loader:" + key.toLowerCase());
+	});
+
+	Loader.Config.set("_loadEvent",
+		"addEventListener" in window ?
+			"load" :
+			"readystatechange"
+	);
+
+	Loader.Config.set("event", {
+		elem: window,
+		type: "load"
+	});
+
+	return Loader;
+
+})(this, this.document));