Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
hipchat4 / opt / HipChat4 / share / localweb / vendor / defer-1.1.0.js
Size: Mime:
// ==ClosureCompiler==
// @output_file_name defer.min.js
// @compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==

/** @license
 * "defer.js" is a trademark of Ian J. Wessman
 *
 * Copyright 2011-2012 Ian J. Wessman
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * v.1.1
 */

/*  // This error struct exists for developer documentation,
    // and needn't be included for production purposes.
	errors
	enum {string}

var deferErrors =
{
	"defer:01" : "defer: invalid predicate (must be a function)" ,
	"defer:02" : "defer: handler must be a function" ,
	"defer:03" : "defer: an interval of less than 10ms is inadvisable" ,
	"defer:04" : "defer: execution of handler instance failed" ,
};*/


/**
	@define {boolean}
*/
var _debug = false;

/**
	@define {boolean}
*/
var _robustIEReady = true;

(function(window,deferQueue){
	/**
		@const 
		@type {boolean}
	*/
	var YES = true;
	
	/**
		@const 
		@type {boolean}
	*/
	var NO = false;
	
	/**
		@const 
		@type {undefined}
	*/
	var undefined;
	
	/**
		@const 
		@type {string}
	*/
	var kVersion = "1.1";
	
	/**
		@const 
		@type {string}
	*/
	var kErrorPrefix = "defer:";

	
	
	// CLOSURE VARS
	
	/** @type {Object} */
	var _deferences = {};				// hash for active _deferInstances.
	
	/** @type {number} */
	var _deferenceCounter = 100;		// for generating non-conflicting _deferInstance IDs
	
	/** @type {boolean} */
	var _isReady = NO;				// is the DOM in a ready/usable state?
	
	/** @type {boolean} */
	var _isIE = (!!window.document.detachEvent);
	
	// CONSTANTS
	
	/** @const @type {string} */
	var kDOMContentLoaded = "DOMContentLoaded";
	
	/** @const @type {string} */
	var kReadyStateChange = "readystatechange";
	
	/** @const @type {string} */
	var kOnReadyStateChange = "on"+kReadyStateChange;
	
	/** @const @type {string} */
	var kComplete = "complete";
	
	/** @const @type {string} */
	var kLoad = "load";
	
	/** @const @type {string} */
	var kType = "type";
	
	/** @const @type {string} */
	var kReady = "ready";
	
	/** @const @type {string} */
	var kP = "p";
	
	/** @const @type {string} */
	var kPredicate = "predicate";
	
	/** @const @type {string} */
	var kH = "h";
	
	/** @const @type {string} */
	var kHandler = "handler";
	
	/** @const @type {string} */
	var kO = "o";
	
	/** @const @type {string} */
	var kOptions = "options";
	
	/*#pragma mark utility functions */
	
	/**
		@param {*} item
		@return {boolean}
	*/
	var isNil = function isNil( item )
	{
		return item === undefined || item === null;
	};
	
	/**
		@param {*} func
		@return {boolean}
	*/
	function isFunction( func )
	{
		// instanceof Function ???
		return !isNil( func ) && ( func instanceof Object ) && ( isNil( func.__proto__ ) ? !isNil( func.call ) : !isNil( func.__proto__.call ) );
	};
	
	/**
		@param {string} message
		@param {*=} obj opt_argument
	*/
	function log( message , obj )
	{
		if( _debug === YES )
		{
			var console = window.console;
			if( !isNil(console) && isFunction(console.log) )
			{
				if( isNil(obj) )
				{
					console.log( message );
				} else {
					console.log( message , obj );
				};
				
				//if( _debug === YES && !isNil(console["trace"] ) ) console["trace"]();
			};
		};
	};
	
	/**
		@param {*} context
		@param {Object} dictionary
		@param {*} handler
	*/
	function forIn( context , dictionary , handler )
	{
		for( var key in dictionary )
		{
			if( Object.prototype.hasOwnProperty.call( dictionary , key ) === YES )
			{
				handler.call( context , key , dictionary[key] );
			};
		};
	};
	
	/**
		@param {*} obj
		@param {string} type
		@param {*} listener
		@param {boolean} capture
		@return {boolean}
	*/
	function addEventListener( obj , type , listener , capture )
	{
		var useCapture = !!capture;
	
		if( !isNil( obj.addEventListener ) )
		{
			// WebKit, Moz, etc.
			obj.addEventListener( type , listener , useCapture );
		} else if (_isIE) {
			useCapture = NO;
			obj.attachEvent( type , listener );
		};
		
		return useCapture;
	};
	
	
	/**
		@param {*} obj
		@param {string} type
		@param {*} listener
		@param {boolean} capture
		@return {boolean}
	*/
	function removeEventListener( obj , type , listener , capture )
	{	
		var useCapture = !!capture;
		
		if( !isNil( obj.removeEventListener ) )
		{
			// WebKit, Moz, etc.
			obj.addEventListener( type , listener , useCapture );
		} else if (_isIE) {
			useCapture = NO;
			obj.detachEvent( type , listener );
		};
		
		return useCapture;
	};
	
	/**
		@param {string} src
		@param {string} async
	*/
	function appendScript( src , async )
	{
		var script	= document.createElement( "script" );
		
		if( !!script )
		{
			script.type	= "text/javascript";
			script.src	= src;
			
			if( !isNil( async ) && ( async === "async" || async === "defer" ) )
			{
				script[async] = async;
			};
			
			document.body.appendChild( script );
		} else {
			log( "Unable to append script" );
		};
	};
	
	/*#pragma mark objects & methods */
	
	/** 
		@param {Object|string} predicate
		@param {Object} handler
		@param {Object} options
		@return {number} The defer instance id
	*/
	function defer( predicate , handler , options )
	{
		/** @type {_deferInstance} */
		var newDefer = new _deferInstance( predicate , handler , options );
		
		if( newDefer.completed === YES  )
		{
			// if we're already good, no need to defer
			return 0;
		} else {	// nope, defer.
			_deferences[newDefer.id] = newDefer;
			return newDefer.id;
		};
	};
	
	/**
		@protected
		@param {number} deferID
		@return {boolean}
	*/
	function cancelInstance( deferID )
	{
		log("defer.cancel");
		
		var success = NO;
		
		var instance = _deferences[deferID];
		
		if( !isNil( instance ) )
		{
			instance.completed = YES;
			success = YES;
		};
		
		return success;
	};
	
	/** 
		@protected 
		@param {number} id
	*/
	function destroyInstance( id )
	{
		window.setTimeout( 	function destroyInstanceImmediately(){_deferences[id]=null; delete _deferences[id];} , 0 );
	};
	
	/**
		@protected
		@return {boolean}
	*/
	function returnTrue()
	{
		return true;
	};
	
	/**
		@protected
		@param {Object} func
		@param {Object} context
		@param {boolean} shouldThrowError
		@param {string} errorText
	*/
	function safeCall( func , context , shouldThrowError , errorText )
	{
		var result = NO;
		
		if( isNil(context) ) context = window;
	
		try
		{
			result = func.call(context);
		} catch(e) {
			if( _debug === YES )
			{
				log( e );
			};
		
			if( shouldThrowError === YES )
			{
				//log( func.toString() , e );
				var err = new Error(errorText);
				err.originalError = e;
				//log( func.toString() , e , func );
				//throw err;
				throw e;
			};
		};
		
		return result;
	};
	
	/** 
		@constructor 
		@protected
		@param {Object|string} thePredicate
		@param {Object} theHandler
		@param {Object} theOptions
	*/
	function _deferInstance( thePredicate , theHandler, theOptions ){

		if( thePredicate === kReady )
		{
			thePredicate = returnTrue;
		} else if( !isFunction(thePredicate) ) {
			throw new Error( kErrorPrefix+"01" );
		};
		if( !isFunction(theHandler) ) throw new Error( kErrorPrefix+"02" );

		var self = this, timeoutValue = null, selfOptions = theOptions || {};
		
		/** protected */
		self.id				= _deferenceCounter++;
		/** protected */
		self.predicate		= thePredicate;
		/** protected */
		self.handler		= theHandler;
		
		//OPTIONS
		
		/** protected */
		selfOptions.interval = theOptions["interval"] || 50;//ms
		if( selfOptions.interval < 10 ) log( kErrorPrefix+"03" );
		//log( "interval: " + self.options.interval );
		/** protected */
		selfOptions.timeout = theOptions["timeout"] || 15000;//ms
		//log( "timeout: " + self.options.timeout );
		
		self.options = selfOptions;
		
		
		/** protected */
		self.testDOMReady	= isNil(theOptions["testDOMReady"]) ? YES : !!theOptions["testDOMReady"];	// defaults to YES
		/** protected */
		self.timeoutID		= null;
		/** protected */
		self.timeoutMS		= null;
		/** protected */
		self.completed		= NO;
		/** protected */
		self.readyBlocked	= NO;

		var firstTest;

		if( self.testDOMReady === YES && _isReady === YES )		// check DOM state first
		{
			firstTest = self.test();
		};
		
		if( firstTest === YES )
		{	// no need to defer
			log( "firstTest, not deferred" );
			self.resultHandler(firstTest);
		} else {
			self.setTimeout();
		};
		delete firstTest;

	};
	
	/*
		@protected
		@return {boolean}
	*/
	_deferInstance.prototype.test = function _deferInstance_test()
	{
		return safeCall( this.predicate , null , NO , "" );
	};
	
	/**
		@protected
		@param {boolean} result
	*/
	_deferInstance.prototype.resultHandler = function _deferInstance_resultHandler(result)
	{
		var self = this;
		if( result === YES )
		{			
			//clear settimeout (if any)
			self.clearTimeout();
			
			//execute handler

			try
			{
				safeCall( self.handler , self.options["handlerContext"] , YES , kErrorPrefix+"04:" + self.id );
			} catch(e) {
				// bubble up
				throw e;
			};

			self.completed = YES;
			
			//remove self from deferences
			destroyInstance( self.id );
		} else {
			// clear old timeout
			self.clearTimeout();
			// wind up again
			self.timeoutID = self.setTimeout();
		};
	};
	
	/** @protected */
	_deferInstance.prototype.setTimeout = function _deferInstance_setTimeout()
	{
	
		var self = this , timeout = self.options["timeout"];
		if( timeout != undefined && !isNaN(timeout) )
		{
			//log( "hastimeout" );						
			if( self.timeoutMS === null )
			{
				// set this on first run
				self.timeoutMS = (+new Date())+timeout;
			};
			
			if( self.timeoutMS > (+new Date()) )
			{
				if( self.completed === NO )
				{
					// do it again				
					self.timeoutID = window.setTimeout( function _deferInstance_setTimeout_impl_set(){self.resultHandler(self.test());} , self.options.interval );
					
					log( "setTimeout" );
				};
			} else {
				log("timed out" , this);
				
				var failedHandler = self.options["onFail"];
				
				if( isFunction(failedHandler) )
				{
					safeCall( failedHandler , null , NO , "" );
				};

				destroyInstance( self.id );
			};
		};
		
	};
	
	/** @protected */
	_deferInstance.prototype.clearTimeout = function()
	{
		if( !isNaN(this.timeoutID) ) window.clearTimeout(this.timeoutID);
	};
	
	defer["isFunction"]			= isFunction;
	defer["isNil"]				= isNil;
	defer["log"]				= log;
	defer["forOwnIn"]			= forIn;
	defer["cancel"]				= cancelInstance;
	defer["appendScript"]		= appendScript;
	defer["addEventListener"]	= addEventListener;
	defer["removeEventListener"]= removeEventListener;
	
	
	/*#pragma mark readystate */

	/**
		@protected
	*/
	function runReadyBlocked()
	{
		log("runReadyBlocked, remaining:" ,_deferences );
		
		forIn( this , _deferences , function enumerateDeferences(key,instance){
				if( !isNil(instance) && instance.completed === NO && instance.readyBlocked === YES )
				{	log( "readyBlocked:continue",instance );
					instance.setTimeout();
				};
			} );
			
		log( "runReadyBlocked completed:" , _deferences );
	};
	
	/**
		@protected
		@param {Object=} ev opt_argument
		@return {boolean}
	*/
	var isReady = function isReady( ev )
	{
		return ( _isReady === YES ) ? YES : setReady(handleReady(ev));
	};
	defer["isReady"] = isReady;
	
	/**
		@protected
		@return {string}
	*/
	function defer_version(){
		return kVersion;
	};
	defer["version"] = defer_version;
	
	/**
		@protected
		@param {boolean} value
	*/
	function setReady(value)
	{
		var oldReady = !!_isReady;
		if( value === YES )
		{
			_isReady = YES;
			
			if( oldReady != _isReady )		// if ready state changed
			{
				//assert( oldReady === NO );
				//assert( _isReady === YES );
				
				//restart all _deferInstances, if they're ready-blocked
				runReadyBlocked();
			};
		};
		
		delete oldReady;
		return _isReady;
	};
	
	/**
		@protected
		@param {Object=} ev opt_argument
	*/
	function handleReady( ev )
	{	//log(ev);
		// insubstantial portions of ready code inspired by jQuery, under the MIT license
		// <https://github.com/jquery/jquery/blob/master/src/core.js>
		
		var doc = window.document;
    		
		if( _isReady === YES || doc.readyState === kComplete )
		{	//log("DOM Ready");
			return YES;
		};
        
        
		
		if( !isNil(ev) && !isNil(ev[kType]) )
		{
			var returnValue = NO;
			switch( ev[kType] )
			{
				case	kDOMContentLoaded:
				case	kLoad :
						returnValue = ( ev.returnValue === YES ); break;
				case	kReadyStateChange :
						if( ev.readyState === kComplete ) returnValue = YES;
						break;
			};
			
			if( returnValue === YES )
			{
				// clean up event handlers
				
				removeEventListener( doc , ( !!_isIE ? kDOMContentLoaded : kOnReadyStateChange ) , handleReady , NO );
				removeEventListener( window , kLoad , handleReady , NO );
			};
				
			return returnValue;
		} else {	// add event handlers
		
			// A fallback to window.onload, that will always work
			addEventListener( window , kLoad , handleReady , NO );
		
			// Mozilla, Opera and webkit nightlies currently support this event
			if ( !!(doc.addEventListener) ) {
				// Use the handy event callback
				addEventListener( doc , kDOMContentLoaded , handleReady , NO );
	
			// If IE event model is used
			} else if ( _isIE ) {
				// ensure firing before onload,
				// maybe late but safe also for iframes
				addEventListener( doc , kOnReadyStateChange , handleReady , NO );
				
				if( _robustIEReady === YES )
				{
					// If IE and not a frame
					// continually check to see if the document is ready
					var toplevel = NO;
		
					try {
						toplevel = window.frameElement === null;
					} catch(e) {;}
					
					// IE Scroll hack
					if( toplevel === YES )
					{
						defer( 
							function IEScrollHackPredicate(){
								doc.documentElement.doScroll("left");
								/* failure of the line above will result in a failed predicate test */
								return YES;
							} , 
							function IEScrollHackHandler(){ setReady(YES); } , 
							{ testDOMReady:NO }
						);
					};
				};
			};
		};
		
		return NO;
	};
	
	//#pragma init
	
	defer( function DOMReadyDeference(){ return !!window.document } , isReady , { interval:10 , testDOMReady:NO } );
	
	//#pragma deferQueue
	
		/**
			@type {Array}
		*/
		deferQueue = deferQueue || [];
		
		/** 
			@protected
		*/
		function acceptDeferQueue()
		{		
			for( var i=0 ; i < deferQueue.length ; i++ )
			{
				processDeferQueueItem( deferQueue.shift() );
			};
		};
		
		/** 
			@protected
			@return {boolean}
		*/
		function processDeferQueueItem( item )
		{
			/** @type {boolean} */
			var success = NO;
		
			/** @type {Object|string} */
			var predicate;
			/** @type {Object} */
			var handler;
			/** @type {Object} */
			var options;
			
			if( item[kPredicate] === kReady || item[kP] === kReady )
			{
				// pass-through so we don't have to do extraneous isFunction tests later
				predicate = kReady;
			}
			else if( !isNil(item[kPredicate]) )
			{
				predicate = item[kPredicate];
			} else if( !isNil( item[kP] ) ) {
				predicate = item[kP]
			} else {
				//todo: assert !isNil(predicate);
				return success;
			};
			
			if( !isNil(item[kHandler]) )
			{
				handler = item[kHandler];
			} else if( !isNil( item[kH] ) ) {
				handler = item[kH]
			} else {
				//todo: assert !isNil(predicate);
				return success;
			};
			
			if( !isNil(item[kOptions]) )
			{
				options = item[kOptions];
			} else if( !isNil( item[kO] ) ) {
				options = item[kO]
			} else {
				//todo: assert !isNil(predicate);
				return success;
			};
			
			defer( predicate , handler , options );
			
			success = YES;			
			log( "successful processDeferQueueItem" );
			return success;
		};

		log("begin first accept");
		while( deferQueue.length > 0)	//process in batches, until we're sure no one gets forgotten. necessary when we're loading defer.js itself asynchronously
		{
			acceptDeferQueue();
		};
		log("end first accept");
		
		if( _debug === YES && deferQueue.length > 0 )
		{
				alert( "leftover:\t" + deferQueue.length );
				log( "leftover:\t" + deferQueue.length , deferQueue );
		};
		
		defer.push = processDeferQueueItem;
		
	window["defer"]		= defer;
})(window,window["defer"]);