Source: widgets/transitions/kekule.widget.transMgr.js

/**
 * @fileoverview
 * A helper unit to control the universal transition style (especially show/hide animation) of widgets.
 * @author Partridge Jiang
 */

/*
 * requires /lan/classes.js
 * requires /core/kekule.common.js
 * requires /utils/kekule.utils.js
 * requires /utils/kekule.domUtils.js
 * requires /xbrowsers/kekule.x.js
 * requires /widget/kekule.widget.base.js
 * requires /widgets/transitions/kekule.widgert.transitions.js
 */


(function(){

/** @ignore */
SU = Kekule.StyleUtils;

/**
 * A singleton class to manage some global behavior of widgets show/hide process (especially with transitions).
 * User should not use this class directly.
 * @augments {ObjectEx}
 * @class
 *
 * @property {Kekule.Widget.ShowHideTransitionSelector} transitionSelector The helper object to select proper transition.
 * @property {Bool} enableTransition Whether use transition to show/hide widget.
 * @property {Int} showDuration Duration of appear transition, in ms.
 * @property {Int} hideDuration Duration of disappear transition, in ms.
 *
 * @private
 *
 */
Kekule.Widget.ShowHideManager = Class.create(ObjectEx,
/** @lends Kekule.Widget.ShowHideManager# */
{
	/** @private */
	CLASS_NAME: 'Kekule.Widget.ShowHideManager',
	/** @constructs */
	initialize: function($super)
	{
		$super();
		this.setEnableTransition(true);
		this.setShowDuration(450);
		this.setHideDuration(450);
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('enableTransition', {'dataType': DataType.BOOL});
		this.defineProp('transitionSelector', {'dataType': 'Kekule.Widget.ShowHideTransitionSelector', 'serializable': false});
		//this.defineProp('transitionExecutor', {'dataType': 'Kekule.Widget.BaseTransition', 'serializable': false});
		this.defineProp('showDuration', {'dataType': DataType.INT});
		this.defineProp('hideDuration', {'dataType': DataType.INT});
	},

	/** @private */
	_getCallerElement: function(caller)
	{
		if (!caller)
			return null;
		else
			return caller.getElement? caller.getElement():
				Kekule.DomUtils.isElement(caller)? caller:
				null;
	},

	/** @private */
	isUsingTransition: function()
	{
		return this.getEnableTransition() && this.getTransitionSelector();
	},
	/**
	 * Select a proper transition by transitionSelector.
	 * @private
	 */
	selectTransition: function(widget, caller, showHideType)
	{
		var selector = this.getTransitionSelector();
		if (!selector)
			return null;
		else
		{
			var result = selector.selectTransition(widget, caller, showHideType);
			if (result && caller)
				result.setCaller(/*caller.getElement()*/this._getCallerElement(caller));
		}
		return result;
	},
	/**
	 * Show the widget. When the show process is done, callback() will be called.
	 * @param {Kekule.Widget.BaseWidget} widget
	 * @param {Kekule.Widget.BaseWidget} caller Who calls the show method and make this widget visible.
	 * @param {Function} callback
	 * @param {Int} showType, value from {@link Kekule.Widget.ShowHideType).
	 * @param {Hash} extraOptions Extra options passed to transition executor.
	 */
	show: function(widget, caller, callback, showType, extraOptions)
	{
		// prepare transition
		/*
		if (this.getEnabledTransition())
			this.prepareShow(widget);

		widget.setVisible(true);
		widget.setDisplayed(true);
		*/
		var transOptions = Object.extend(extraOptions || {}, {
			'from': 0,
			'to': 1,
			'isAppear': true,
			'duration': this.getShowDuration()
		});
		var transExecutor = this.selectTransition(widget, caller, showType);

		if (transExecutor && this.isUsingTransition() && transExecutor.canExecute(widget.getElement(), transOptions))
		{
			var done = function(e)
			{
				//console.log('callback show');
				// ensure displayed
				// here call setDisplayed and setVisible with second param, avoid call widgetShowStateChanged multiple times
				widget.setVisible(true, true);
				widget.setDisplayed(true, true);
				if (callback)
					callback();
			};
			//console.log('do transition');
			// do transition
			return transExecutor.execute(widget.getElement(), /*caller && caller.getElement()*/this._getCallerElement(caller), done, transOptions);
		}
		else  // no transition, show directly
		{
			// here call setDisplayed and setVisible with second param, avoid call widgetShowStateChanged multiple times
			widget.setVisible(true, true);
			widget.setDisplayed(true, true);
			if (callback)
				callback();
		}
		return null;  // if no transition, return nothing
	},
	/**
	 * Hide the widget. When the hide process is done, callback() will be called.
	 * @param {Kekule.Widget.BaseWidget} widget
	 * @param {Function} callback
	 * @param {Kekule.Widget.BaseWidget} caller
	 * @param {Int} hideType, value from {@link Kekule.Widget.ShowHideType).
	 * @param {Bool} useVisible If true CSS visible property will be set to hidden finally to hide widget, otherwise display: none will be used.
	 * @param {Hash} extraOptions Extra options passed to transition executor, can include special field:
	 *   {
	 *     useVisible: If true CSS visible property will be set to hidden finally to hide widget, otherwise display: none will be used.
	 *     callerPageRect: Sometimes caller widget is hidden and the ref rect can not be calculated directly from caller,
	 *       if so, this value ,may be used by transition executor.
	 *   }
	 */
	hide: function(widget, caller, callback, hideType, useVisible, extraOptions)
	{
		var transOptions = Object.extend(extraOptions, {
			'from': 1,
			'to': 0,
			'isDisappear': true,
			'duration': this.getHideDuration()
		});
		var useVisible = !!extraOptions.useVisible;
		var transExecutor = this.selectTransition(widget, caller, hideType);

		if (transExecutor && this.isUsingTransition() && transExecutor.canExecute(widget.getElement(), transOptions))
		{
			// ensure hide
			// here call setDisplayed and setVisible with second param, avoid call widgetShowStateChanged multiple times
			var done = function()
			{
				if (widget)
				{
					if (useVisible)
						widget.setVisible(false, true);
					else
						widget.setDisplayed(false, true);
				}
				if (callback)
					callback();
			};
			// do transition
			return transExecutor.execute(widget.getElement(), /*caller && caller.getElement()*/this._getCallerElement(caller), done, transOptions);
		}
		else  // no transition, hide directly
		{
			// here call setDisplayed and setVisible with second param, avoid call widgetShowStateChanged multiple times
			if (useVisible)
				widget.setVisible(false, true);
			else
				widget.setDisplayed(false, true);
			if (callback)
				callback();
		}
		return null;  // if no transition, returns nothing
	}
});
Kekule.ClassUtils.makeSingleton(Kekule.Widget.ShowHideManager);
Kekule.Widget.showHideManager = Kekule.Widget.ShowHideManager.getInstance();


/**
 * A class select proper transition in show/hide widgets.
 * User should not use this class directly.
 * @augments {ObjectEx}
 * @class
 *
 * //@property {Class} defaultTransitionClass Transition in showing/hiding drop down widgets (e.g. dropDown button group).
 * //@property {Class} popupTransitionClass Transition in showing/hiding popup widgets (e.g., popup dialog).
 * //@property {Class} defaultTransitionClass Transition in showing/hiding other widgets.
 *
 * @private
 */
Kekule.Widget.ShowHideTransitionSelector = Class.create(ObjectEx,
/** @lends Kekule.Widget.ShowHideTransitionSelector# */
{
	/** @private */
	CLASS_NAME: 'Kekule.Widget.ShowHideTransitionSelector',
	/** @constructs */
	initialize: function($super)
	{
		$super();
		this.setTransitionClassMap({});
	},
	/** @private */
	initProperties: function()
	{
		/*
		this.defineProp('defaultTransitionClass', {'dataType': DataType.CLASS, 'serializable': false});
		this.defineProp('dropDownTransitionClass', {'dataType': DataType.CLASS, 'serializable': false});
		this.defineProp('popupTransitionClass', {'dataType': DataType.CLASS, 'serializable': false});
		*/
		this.defineProp('transitionClassMap', {'dataType': DataType.OBJECT, 'serializable': false});
	},

	/** @private */
	_getTransClassOfType: function(showHideType)
	{
		var map = this.getTransitionClassMap();
		return map[showHideType] || map[Kekule.Widget.ShowHideType.DEFAULT];
	},

	/**
	 * Add a transition class mapping on showHideType.
	 * @param {Int} showHideType
	 * @param {Class} transClass
	 */
	addTransitionClass: function(showHideType, transClass)
	{
		this.getTransitionClassMap()[showHideType] = transClass;
	},

	/**
	 * Select a proper transition by input conditions.
	 * @param {Kekule.Widget.BaseWidget} widget
	 * @param {Kekule.Widget.BaseWidget} caller
	 * @param {Int} showHideType
	 * @returns {Kekule.Widget.BaseTransition}
	 */
	selectTransition: function(widget, caller, showHideType)
	{
		var transClass;
		var ST = Kekule.Widget.ShowHideType;
		if (caller)
		{
			/*
			if (showHideType === ST.POPUP)
				transClass = this.getPopupTransitionClass();
			else if (showHideType === ST.DROPDOWN)
				transClass = this.getDropDownTransitionClass();
			else
				transClass = this.getDefaultTransitionClass();
			*/
			transClass = this._getTransClassOfType(showHideType);
		}
		else
			//transClass = this.getDefaultTransitionClass();
			transClass = this._getTransClassOfType(Kekule.Widget.ShowHideType.DEFAULT);

		//console.log(showHideType, transClass);

		if (transClass)
			return new transClass();
		else
			return null;
	}
});


// debug
// TODO: need a factory to manage transition executors
// TODO: need a more flexible way to control the duration and style of show/hide transitions
//  for instance, may we have a "near/far" property in invoking transition?
//  When near is at left and far to right, use slideRight, when near=top and far=right, use SlideDown.
//Kekule.Widget.showHideManager.setTransitionExecutor(new Kekule.Widget.Css3OpacityTrans());
//Kekule.Widget.showHideManager.setTransitionExecutor(new Kekule.Widget.Css3SlideTransition(Kekule.Widget.Direction.AUTO));
//Kekule.Widget.showHideManager.setTransitionExecutor(new Kekule.Widget.Css3GrowTransition());

var defSelector = new Kekule.Widget.ShowHideTransitionSelector();
/*
defSelector.setDefaultTransitionClass(Kekule.Widget.Css3OpacityTrans);
defSelector.setDropDownTransitionClass(Kekule.Widget.Css3SlideTransition);
defSelector.setPopupTransitionClass(Kekule.Widget.Css3GrowTransition);
*/
var SHT = Kekule.Widget.ShowHideType;
defSelector.addTransitionClass(SHT.DEFAULT, Kekule.Widget.Css3OpacityTrans);
defSelector.addTransitionClass(SHT.DROPDOWN, Kekule.Widget.Css3SlideTransition);

//defSelector.addTransitionClass(SHT.POPUP, Kekule.Widget.Css3GrowTransition);
//defSelector.addTransitionClass(SHT.DIALOG, Kekule.Widget.Css3GrowTransition);
defSelector.addTransitionClass(SHT.POPUP, Kekule.Widget.Css3TransformGrowTransition || Kekule.Widget.Css3GrowTransition);
defSelector.addTransitionClass(SHT.DIALOG, Kekule.Widget.Css3TransformGrowTransition || Kekule.Widget.Css3GrowTransition);

Kekule.Widget.showHideManager.setTransitionSelector(defSelector);

// debug
	//Kekule.Widget.showHideManager = null;


})();