<commit_before>define(["dojo/_base/lang", "dojo/_base/declare", "dojo/has", "dojo/on", "dojo/Deferred",
	"dojo/when", "dojox/css3/transit", "../Controller", "../utils/constraints"],
	function(lang, declare, has, on, Deferred, when, transit, Controller, constraints){
	// module:
	//		dojox/app/controllers/transition
	//		Bind "transition" event on dojox/app application instance.
	//		Do transition from one view to another view.
	return declare("dojox.app.controllers.Transition", Controller, {

		proceeding: false,

		waitingQueue:[],

		constructor: function(app, events){
			// summary:
			//		bind "transition" event on application instance.
			//
			// app:
			//		dojox/app application instance.
			// events:
			//		{event : handler}
			this.events = {
				"transition": this.transition,
				"domNode": this.onDomNodeChange
			};
			if(this.app.domNode){
				this.onDomNodeChange({oldNode: null, newNode: this.app.domNode});
			}
		},

		transition: function(event){
			// summary:
			//		Response to dojox/app "transition" event.
			//
			// example:
			//		Use trigger() to trigger "transition" event, and this function will response to the event. For example:
			//		|	this.trigger("transition", {"viewId":viewId, "opts":opts});
			//
			// event: Object
			//		"transition" event parameter. It should be like this: {"viewId":viewId, "opts":opts}

			this.proceeding = (event.opts && event.opts.params && event.opts.params.waitToProceed); // waitToProceed passed when visible is true to delay processing.

			var viewsId = event.viewId || "";
			this.proceedingSaved = this.proceeding;
			var parts = viewsId.split('+');
			if(parts.length > 0){
				while(parts.length > 1){
					var viewId = parts.shift();
					var newEvent = lang.clone(event);
					newEvent.viewId = viewId;
					this.proceeding = true;
					this.proceedTransition(newEvent);
				}
				this.proceeding = this.proceedingSaved;
				var viewId = parts.shift();
				event.viewId = viewId;
				event._doResize = true; // at the end of the last transition call resize
				this.proceedTransition(event);
			}else{
				event._doResize = true; // at the end of the last transition call resize
				this.proceedTransition(event);
			}
		},

		onDomNodeChange: function(evt){
			if(evt.oldNode != null){
				this.unbind(evt.oldNode, "startTransition");
			}
			this.bind(evt.newNode, "startTransition", lang.hitch(this, this.onStartTransition));
		},

		onStartTransition: function(evt){
			// summary:
			//		Response to dojox/app "startTransition" event.
			//
			// example:
			//		Use "dojox/mobile/TransitionEvent" to trigger "startTransition" event, and this function will response the event. For example:
			//		|	var transOpts = {
			//		|		title:"List",
			//		|		target:"items,list",
			//		|		url: "#items,list"
			//		|	};
			//		|	new TransitionEvent(domNode, transOpts, e).dispatch();
			//
			// evt: Object
			//		transition options parameter

			// prevent event from bubbling to window and being
			// processed by dojox/mobile/ViewController
			if(evt.preventDefault){
				evt.preventDefault();
			}
			evt.cancelBubble = true;
			if(evt.stopPropagation){
				evt.stopPropagation();
			}

			var target = evt.detail.target;
			var regex = /#(.+)/;
			if(!target && regex.test(evt.detail.href)){
				target = evt.detail.href.match(regex)[1];
			}

			// transition to the target view
			this.transition({"viewId":target, opts: lang.mixin({},evt.detail)});
		},

		proceedTransition: function(transitionEvt){
			// summary:
			//		Proceed transition queue by FIFO by default.
			//		If transition is in proceeding, add the next transition to waiting queue.
			//
			// transitionEvt: Object
			//		"transition" event parameter. It should be like this: {"viewId":viewId, "opts":opts}

			if(this.proceeding){
				this.app.log("in app/controllers/Transition proceedTransition push event", transitionEvt);
				this.waitingQueue.push(transitionEvt);
				this.processingQueue = false;
				return;
			}
			// If there are events waiting, needed to have the last in be the last processed, so add it to waitingQueue
			// process the events in order.
			if(this.waitingQueue.length > 0 && !this.processingQueue){
				this.processingQueue = true;
				this.waitingQueue.push(transitionEvt);
				transitionEvt = this.waitingQueue.shift();
			}

			this.proceeding = true;

			this.app.log("in app/controllers/Transition proceedTransition calling trigger load", transitionEvt);
			var params;
			if(transitionEvt.opts && transitionEvt.opts.params){
				params = transitionEvt.opts.params;
			}
			this.app.emit("load", {
				"viewId": transitionEvt.viewId,
				"params": params,
				"callback": lang.hitch(this, function(){
					var transitionDef = this._doTransition(transitionEvt.viewId, transitionEvt.opts, params, this.app, transitionEvt._doResize);
					when(transitionDef, lang.hitch(this, function(){
						this.proceeding = false;
						var nextEvt = this.waitingQueue.shift();
						if(nextEvt){
							this.proceedTransition(nextEvt);
						}
					}));
				})
			});
		},

		_getDefaultTransition: function(parent){
			// summary:
			//		Get view's default transition type from parent view.
			//		Retrieve the parent chain and get the latest ancestor's default transition type.
			//
			// parent: Object
			//		view's parent
			//
			// returns:
			//		transition type like "slide", "fade", "flip" or undefined.
			var parentView = parent;
			var defaultTransition = parentView.defaultTransition;
			while(!defaultTransition && parentView.parent){
				parentView = parentView.parent;
				defaultTransition = parentView.defaultTransition;
			}
			return defaultTransition;
		},

		_doTransition: function(transitionTo, opts, params, parent, doResize){
			// summary:
			//		Transitions from the currently visible scene to the defined scene.
			//		It should determine what would be the best transition unless
			//		an override in opts tells it to use a specific transitioning methodology
			//		the transitionTo is a string in the form of [view]@[scene].  If
			//		view is left of, the current scene will be transitioned to the default
			//		view of the specified scene (eg @scene2), if the scene is left off
			//		the app controller will instruct the active scene to the view (eg view1).  If both
			//		are supplied (view1@scene2), then the application should transition to the scene,
			//		and instruct the scene to navigate to the view.
			//
			// transitionTo: Object
			//		transition to view id. It looks like #tabScene,tab1
			// opts: Object
			//		transition options
			// params: Object
			//		params
			// parent: Object
			//		view's parent
			// doResize: Boolean
			//		emit a resize event
			//
			// returns:
			//		transit dojo/DeferredList object.

			//TODO: Can this be called with a viewId which includes multiple views with a "+"?  Need to handle that!
			this.app.log("in app/controllers/Transition._doTransition transitionTo=[",transitionTo,"], parent.name=[",parent.name,"], opts=",opts);

			if(!parent){
				throw Error("view parent not found in transition.");
			}
			var parts, toId, subIds, next, params;
			if(transitionTo){
				parts = transitionTo.split(",");
			}else{
				// If parent.defaultView is like "main,main", we also need to split it and set the value to toId and subIds.
				// Or cannot get the next view by "parent.children[parent.id + '_' + toId]"
				parts = parent.defaultView.split(",");
			}
			toId = parts.shift();
			subIds = parts.join(',');

			// next is loaded and ready for transition
			next = parent.children[parent.id + '_' + toId];
			if(!next){
				throw Error("child view must be loaded before transition.");
			}

			var current = constraints.getSelectedChild(parent, next.constraint);

			// set params on next view.
			next.params = params || next.params;

			// if no subIds and next has default view,
			// set the subIds to the default view and transition to default view.
			if(!subIds && next.defaultView){
				subIds = next.defaultView;
			}

			// next is not a Deferred object, so Deferred.when is no needed.
			if(next !== current){
				//When clicking fast, history module will cache the transition request que
				//and prevent the transition conflicts.
				//Originally when we conduct transition, selectedChild will not be the
				//view we want to start transition. For example, during transition 1 -> 2
				//if user click button to transition to 3 and then transition to 1. After
				//1->2 completes, it will perform transition 2 -> 3 and 2 -> 1 because
				//selectedChild is always point to 2 during 1 -> 2 transition and transition
				//will record 2->3 and 2->1 right after the button is clicked.

				//assume next is already loaded so that this.set(...) will not return
				//a promise object. this.set(...) will handles the this.selectedChild,
				//activate or deactivate views and refresh layout.

				// deactivate sub child of current view, then deactivate current view
				// TODO: ELC NEED A LOOP HERE TO deactivate all children
				var subChild = constraints.getSelectedChild(current, "center");
				while(subChild){
					this.app.log("< in Transition._doTransition calling subChild.beforeDeactivate subChild name=[",subChild.name,"], parent.name=[",subChild.parent.name,"], next!==current path");
					subChild.beforeDeactivate();
					subChild = constraints.getSelectedChild(subChild, "center");
				}
				if(current){
					this.app.log("< in Transition._doTransition calling current.beforeDeactivate current name=[",current.name,"], parent.name=[",current.parent.name,"], next!==current path");
					current.beforeDeactivate();
				}
				this.app.log("> in Transition._doTransition calling next.beforeActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next!==current path");
				next.beforeActivate();
				this.app.log("> in Transition._doTransition calling app.triggger layoutView view next name=[",next.name,"], parent.name=[",next.parent.name,"], next!==current path");
				this.app.emit("layoutView", {"parent":parent, "view":next});
				if(doResize){
					this.app.emit("resize"); // after last layoutView call resize
				}

				var result = true;
				if(!has("ie") || has("ie") >= 10){
					// if we are on IE CSS3 transitions are not supported (yet). So just skip the transition itself.
					var mergedOpts = lang.mixin({}, opts); // handle reverse from mergedOpts or transitionDir
					mergedOpts = lang.mixin({}, mergedOpts, {
						reverse: (mergedOpts.reverse || mergedOpts.transitionDir===-1)?true:false,
						transition: mergedOpts.transition || this._getDefaultTransition(parent) || "none"
					});
					result = transit(current && current.domNode, next.domNode, mergedOpts);
				}
				when(result, lang.hitch(this, function(){
					// deactivate sub child of current view, then deactivate current view
					subChild = constraints.getSelectedChild(current, "center");

					while(subChild){
						this.app.log("  < in Transition._doTransition calling subChild.afterDeactivate subChild name=[",subChild.name,"], parent.name=[",subChild.parent.name,"], next!==current path");
						subChild.afterDeactivate();
						subChild = constraints.getSelectedChild(subChild, "center");
					}
					if(current){
						this.app.log("  < in Transition._doTransition calling current.afterDeactivate current name=[",current.name,"], parent.name=[",current.parent.name,"], next!==current path");
						current.afterDeactivate();
					}
					this.app.log("  > in Transition._doTransition calling next.afterActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next!==current path");
					next.afterActivate();

					if(subIds){
						this._doTransition(subIds, opts, params, next, doResize);
					}
				}));
				return result; // dojo/DeferredList
			}else{
				// next view == current view, refresh current view
				// deactivate next view
				this.app.log("< in Transition._doTransition calling next.beforeDeactivate refresh current view next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.beforeDeactivate();
				this.app.log("  < in Transition._doTransition calling next.afterDeactivate refresh current view next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.afterDeactivate();
				// activate next view
				this.app.log("> in Transition._doTransition calling next.beforeActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.beforeActivate();
				this.app.log("  > in Transition._doTransition calling next.afterActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.afterActivate();
				// layout current view
				this.app.log("> in Transition._doTransition calling app.triggger layoutView view next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				this.app.emit("layoutView", {"parent":parent, "view":next});
				if(doResize){
					this.app.emit("resize"); // after last layoutView call resize
				}

			}

			// do sub transition like transition from "tabScene,tab1" to "tabScene,tab2"
			if(subIds){
				return this._doTransition(subIds, opts, params, next); //dojo.DeferredList
			}
		}
	});
});
<commit_msg>Fix issue when transiting from a top view that is animated an nested view. Some transition happen also on the nested view giving weird effects. We want to avoid that.<commit_after>define(["dojo/_base/lang", "dojo/_base/declare", "dojo/has", "dojo/on", "dojo/Deferred",
	"dojo/when", "dojox/css3/transit", "../Controller", "../utils/constraints"],
	function(lang, declare, has, on, Deferred, when, transit, Controller, constraints){
	// module:
	//		dojox/app/controllers/transition
	//		Bind "transition" event on dojox/app application instance.
	//		Do transition from one view to another view.
	return declare("dojox.app.controllers.Transition", Controller, {

		proceeding: false,

		waitingQueue:[],

		constructor: function(app, events){
			// summary:
			//		bind "transition" event on application instance.
			//
			// app:
			//		dojox/app application instance.
			// events:
			//		{event : handler}
			this.events = {
				"transition": this.transition,
				"domNode": this.onDomNodeChange
			};
			if(this.app.domNode){
				this.onDomNodeChange({oldNode: null, newNode: this.app.domNode});
			}
		},

		transition: function(event){
			// summary:
			//		Response to dojox/app "transition" event.
			//
			// example:
			//		Use trigger() to trigger "transition" event, and this function will response to the event. For example:
			//		|	this.trigger("transition", {"viewId":viewId, "opts":opts});
			//
			// event: Object
			//		"transition" event parameter. It should be like this: {"viewId":viewId, "opts":opts}

			this.proceeding = (event.opts && event.opts.params && event.opts.params.waitToProceed); // waitToProceed passed when visible is true to delay processing.

			var viewsId = event.viewId || "";
			this.proceedingSaved = this.proceeding;
			var parts = viewsId.split('+');
			if(parts.length > 0){
				while(parts.length > 1){
					var viewId = parts.shift();
					var newEvent = lang.clone(event);
					newEvent.viewId = viewId;
					this.proceeding = true;
					this.proceedTransition(newEvent);
				}
				this.proceeding = this.proceedingSaved;
				var viewId = parts.shift();
				event.viewId = viewId;
				event._doResize = true; // at the end of the last transition call resize
				this.proceedTransition(event);
			}else{
				event._doResize = true; // at the end of the last transition call resize
				this.proceedTransition(event);
			}
		},

		onDomNodeChange: function(evt){
			if(evt.oldNode != null){
				this.unbind(evt.oldNode, "startTransition");
			}
			this.bind(evt.newNode, "startTransition", lang.hitch(this, this.onStartTransition));
		},

		onStartTransition: function(evt){
			// summary:
			//		Response to dojox/app "startTransition" event.
			//
			// example:
			//		Use "dojox/mobile/TransitionEvent" to trigger "startTransition" event, and this function will response the event. For example:
			//		|	var transOpts = {
			//		|		title:"List",
			//		|		target:"items,list",
			//		|		url: "#items,list"
			//		|	};
			//		|	new TransitionEvent(domNode, transOpts, e).dispatch();
			//
			// evt: Object
			//		transition options parameter

			// prevent event from bubbling to window and being
			// processed by dojox/mobile/ViewController
			if(evt.preventDefault){
				evt.preventDefault();
			}
			evt.cancelBubble = true;
			if(evt.stopPropagation){
				evt.stopPropagation();
			}

			var target = evt.detail.target;
			var regex = /#(.+)/;
			if(!target && regex.test(evt.detail.href)){
				target = evt.detail.href.match(regex)[1];
			}

			// transition to the target view
			this.transition({"viewId":target, opts: lang.mixin({},evt.detail)});
		},

		proceedTransition: function(transitionEvt){
			// summary:
			//		Proceed transition queue by FIFO by default.
			//		If transition is in proceeding, add the next transition to waiting queue.
			//
			// transitionEvt: Object
			//		"transition" event parameter. It should be like this: {"viewId":viewId, "opts":opts}

			if(this.proceeding){
				this.app.log("in app/controllers/Transition proceedTransition push event", transitionEvt);
				this.waitingQueue.push(transitionEvt);
				this.processingQueue = false;
				return;
			}
			// If there are events waiting, needed to have the last in be the last processed, so add it to waitingQueue
			// process the events in order.
			if(this.waitingQueue.length > 0 && !this.processingQueue){
				this.processingQueue = true;
				this.waitingQueue.push(transitionEvt);
				transitionEvt = this.waitingQueue.shift();
			}

			this.proceeding = true;

			this.app.log("in app/controllers/Transition proceedTransition calling trigger load", transitionEvt);
			var params;
			if(transitionEvt.opts && transitionEvt.opts.params){
				params = transitionEvt.opts.params;
			}
			this.app.emit("load", {
				"viewId": transitionEvt.viewId,
				"params": params,
				"callback": lang.hitch(this, function(){
					var transitionDef = this._doTransition(transitionEvt.viewId, transitionEvt.opts, params, this.app, transitionEvt._doResize);
					when(transitionDef, lang.hitch(this, function(){
						this.proceeding = false;
						var nextEvt = this.waitingQueue.shift();
						if(nextEvt){
							this.proceedTransition(nextEvt);
						}
					}));
				})
			});
		},

		_getDefaultTransition: function(parent){
			// summary:
			//		Get view's default transition type from parent view.
			//		Retrieve the parent chain and get the latest ancestor's default transition type.
			//
			// parent: Object
			//		view's parent
			//
			// returns:
			//		transition type like "slide", "fade", "flip" or undefined.
			var parentView = parent;
			var defaultTransition = parentView.defaultTransition;
			while(!defaultTransition && parentView.parent){
				parentView = parentView.parent;
				defaultTransition = parentView.defaultTransition;
			}
			return defaultTransition;
		},

		_doTransition: function(transitionTo, opts, params, parent, doResize, nested){
			// summary:
			//		Transitions from the currently visible scene to the defined scene.
			//		It should determine what would be the best transition unless
			//		an override in opts tells it to use a specific transitioning methodology
			//		the transitionTo is a string in the form of [view]@[scene].  If
			//		view is left of, the current scene will be transitioned to the default
			//		view of the specified scene (eg @scene2), if the scene is left off
			//		the app controller will instruct the active scene to the view (eg view1).  If both
			//		are supplied (view1@scene2), then the application should transition to the scene,
			//		and instruct the scene to navigate to the view.
			//
			// transitionTo: Object
			//		transition to view id. It looks like #tabScene,tab1
			// opts: Object
			//		transition options
			// params: Object
			//		params
			// parent: Object
			//		view's parent
			// doResize: Boolean
			//		emit a resize event
			//	nested: Boolean
			//		whether the method is called from the transitioning of a parent view
			//
			// returns:
			//		transit dojo/promise/all object.

			//TODO: Can this be called with a viewId which includes multiple views with a "+"?  Need to handle that!
			this.app.log("in app/controllers/Transition._doTransition transitionTo=[",transitionTo,"], parent.name=[",parent.name,"], opts=",opts);

			if(!parent){
				throw Error("view parent not found in transition.");
			}
			var parts, toId, subIds, next, params;
			if(transitionTo){
				parts = transitionTo.split(",");
			}else{
				// If parent.defaultView is like "main,main", we also need to split it and set the value to toId and subIds.
				// Or cannot get the next view by "parent.children[parent.id + '_' + toId]"
				parts = parent.defaultView.split(",");
			}
			toId = parts.shift();
			subIds = parts.join(',');

			// next is loaded and ready for transition
			next = parent.children[parent.id + '_' + toId];
			if(!next){
				throw Error("child view must be loaded before transition.");
			}

			var current = constraints.getSelectedChild(parent, next.constraint);

			// set params on next view.
			next.params = params || next.params;

			// if no subIds and next has default view,
			// set the subIds to the default view and transition to default view.
			if(!subIds && next.defaultView){
				subIds = next.defaultView;
			}

			// next is not a Deferred object, so Deferred.when is no needed.
			if(next !== current){
				//When clicking fast, history module will cache the transition request que
				//and prevent the transition conflicts.
				//Originally when we conduct transition, selectedChild will not be the
				//view we want to start transition. For example, during transition 1 -> 2
				//if user click button to transition to 3 and then transition to 1. After
				//1->2 completes, it will perform transition 2 -> 3 and 2 -> 1 because
				//selectedChild is always point to 2 during 1 -> 2 transition and transition
				//will record 2->3 and 2->1 right after the button is clicked.

				//assume next is already loaded so that this.set(...) will not return
				//a promise object. this.set(...) will handles the this.selectedChild,
				//activate or deactivate views and refresh layout.

				// deactivate sub child of current view, then deactivate current view
				// TODO: ELC NEED A LOOP HERE TO deactivate all children
				var subChild = constraints.getSelectedChild(current, "center");
				while(subChild){
					this.app.log("< in Transition._doTransition calling subChild.beforeDeactivate subChild name=[",subChild.name,"], parent.name=[",subChild.parent.name,"], next!==current path");
					subChild.beforeDeactivate();
					subChild = constraints.getSelectedChild(subChild, "center");
				}
				if(current){
					this.app.log("< in Transition._doTransition calling current.beforeDeactivate current name=[",current.name,"], parent.name=[",current.parent.name,"], next!==current path");
					current.beforeDeactivate();
				}
				this.app.log("> in Transition._doTransition calling next.beforeActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next!==current path");
				next.beforeActivate();
				this.app.log("> in Transition._doTransition calling app.triggger layoutView view next name=[",next.name,"], parent.name=[",next.parent.name,"], next!==current path");
				this.app.emit("layoutView", {"parent":parent, "view":next});
				if(doResize){
					this.app.emit("resize"); // after last layoutView call resize
				}

				var result = true;
				if((!has("ie") || has("ie") >= 10) && (!nested || current != null)){
					// if we are on IE CSS3 transitions are not supported (yet). So just skip the transition itself.
					// we also skip in we are transitioning to a nested view from a parent view and that nested view
					// did not have any current
					var mergedOpts = lang.mixin({}, opts); // handle reverse from mergedOpts or transitionDir
					mergedOpts = lang.mixin({}, mergedOpts, {
						reverse: (mergedOpts.reverse || mergedOpts.transitionDir===-1)?true:false,
						transition: this._getDefaultTransition(parent) || "none"
					});
					result = transit(current && current.domNode, next.domNode, mergedOpts);
				}
				when(result, lang.hitch(this, function(){
					// deactivate sub child of current view, then deactivate current view
					subChild = constraints.getSelectedChild(current, "center");

					while(subChild){
						this.app.log("  < in Transition._doTransition calling subChild.afterDeactivate subChild name=[",subChild.name,"], parent.name=[",subChild.parent.name,"], next!==current path");
						subChild.afterDeactivate();
						subChild = constraints.getSelectedChild(subChild, "center");
					}
					if(current){
						this.app.log("  < in Transition._doTransition calling current.afterDeactivate current name=[",current.name,"], parent.name=[",current.parent.name,"], next!==current path");
						current.afterDeactivate();
					}
					this.app.log("  > in Transition._doTransition calling next.afterActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next!==current path");
					next.afterActivate();

					if(subIds){
						this._doTransition(subIds, opts, params, next, doResize, true);
					}
				}));
				return result; // dojo/promise/all
			}else{
				// next view == current view, refresh current view
				// deactivate next view
				this.app.log("< in Transition._doTransition calling next.beforeDeactivate refresh current view next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.beforeDeactivate();
				this.app.log("  < in Transition._doTransition calling next.afterDeactivate refresh current view next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.afterDeactivate();
				// activate next view
				this.app.log("> in Transition._doTransition calling next.beforeActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.beforeActivate();
				this.app.log("  > in Transition._doTransition calling next.afterActivate next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				next.afterActivate();
				// layout current view
				this.app.log("> in Transition._doTransition calling app.triggger layoutView view next name=[",next.name,"], parent.name=[",next.parent.name,"], next==current path");
				this.app.emit("layoutView", {"parent":parent, "view":next});
				if(doResize){
					this.app.emit("resize"); // after last layoutView call resize
				}
				// do sub transition like transition from "tabScene,tab1" to "tabScene,tab2"
				if(subIds){
					return this._doTransition(subIds, opts, params, next); // dojo/promise/all
				}
			}
		}
	});
});
<|endoftext|>


<commit_before>// requires: Api_Utils
// METHODS HERE RETURN PROMISES
// for test server
try{
  var fetch = require('node-fetch');
}catch(e){
  var b;
}
/**
* converts an object into a string of url components
* @param {object} obj - keys and values
* @returns the url encoded string
**/
function objToParamStr(obj) {
    var parts = [];
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            if (Array.isArray(obj[i])) {
                // arrays are a list of strings with escaped quotes, surrounded by []
                parts.push(encodeURIComponent(i) + "=" + encodeURIComponent("[" + obj[i].map((x) => '\"' + x + '\"').toString() + "]"));
            } else {
                parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
            }
        }
    }
    return parts.join("&");
}
/**
 * @constructor
* Storage interpreter for camicroscope, uses same auth as origin
* @param base - base url for data
* @param [config] - configuration options, unused so far
**/
class Store{
  constructor(base, config){
    this.base = base || "./data/";
    this.config = config;
  }
  /**
   * errorHandler: handle the error response
   * @param  {Response} response
   * @return {object}
   */
  errorHandler(response){
    if (!response.ok) return {
      error:!response.ok,
      text:response.statusText,
      url:response.url
    };
    return response.json();
  }
  /**
  * find marks matching slide and/or marktype
  * @param {string} [name] - the associated slide name
  * @param {string} [slide] - the associated marktype name, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findMark(slide, name){
    var suffix = "Mark/find"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }

    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * find marks which contain a given point
  * @param {number} x - x position to search for
  * @param {number} y - y position to search for
  * @param {string} [name] - the associated slide name
  * @param {string} [slide] - the associated marktype name, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findMarkSpatial(x, y, name, slide){
    var suffix = "Mark/findPoint"
    var url = this.base + suffix;
    var query = {}
    query.x = x
    query.y = y
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  getMarkByIds(ids, slide){
    if(!Array.isArray(ids) || !slide){
      return {hasError:true,message:'args are illegal'}
    }
    var suffix = "Mark/multi"
    var url = this.base + suffix;
    var query = {}
    var stringifiedIds = ids.map(id=>`"${id}"`).join(',');
    query.name = `[${stringifiedIds}]`;
    console.log(query.name);
    query.slide = slide;
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
    }).then(this.errorHandler)
  }

  /**
  * get mark by id
  * @param {string} id - the mark id
  * @returns {promise} - promise which resolves with data
  **/
  getMark(id){
    var suffix = "Mark/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
  addMark(json){
    var suffix = "Mark/post"
    var url = this.base + suffix;
    // api key for bindaas?
    return fetch(url, {
            method:"POST",
            credentials: "same-origin",
            mode: "cors",
            headers: {
            "Content-Type": "application/json; charset=utf-8",
            // "Content-Type": "application/x-www-form-urlencoded",
            },
            body:JSON.stringify(json)
        }).then(this.errorHandler)
  }
  deleteMark(id,slide){
    var suffix = "Mark/delete"
    var url = this.base + suffix;
    var query = {
      id:id,
      slide:slide
    }
    return fetch(url + "?" + objToParamStr(query), {
            method:"DELETE",
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
  /**
  * find marktypes given slide and name
  * @param {string} [name] - the associated slide name
  * @param {string} [slide] - the marktype name, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findMarkTypes(name, slide){
    var suffix = "Mark/findTypes"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
  // NOTE there is no getMarktype method since markypes are not stored separately from marks

  /**
  * find overlays matching name and/or type
  * @param {string} [name] - the overlay, supporting regex match
  * @param {string} [slide] - the associated slide id
  * @returns {promise} - promise which resolves with data
  **/
  findOverlay(name, slide){
    var suffix = "Overlay/find"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * get overlay by id
  * @param {string} id - the overlay id
  * @returns {promise} - promise which resolves with data
  **/
  getOverlay(id){
    var suffix = "Overlay/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * find overlays matching name and/or type
  * @param {string} [name] - the slide name
  * @param {string} [location] - the slide location, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findSlide(slide, location){
    var suffix = "Slide/find"
    var url = this.base + suffix;
    var query = {}
    if (slide){
      query.slide = slide
    }
    if (location){
      query.location = location
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * get slide by id
  * @param {string} id - the slide id
  * @returns {promise} - promise which resolves with data
  **/
  getSlide(id){
    var suffix = "Slide/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * find templates matching name and/or type
  * @param {string} [name] - the template name, supporting regex match
  * @param {string} [type] - the template type, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findTemplate(name, type){
    var suffix = "Template/find"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (type){
      query.slide = slide
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * get template by id
  * @param {string} id - the template id
  * @returns {promise} - promise which resolves with data
  **/
  getTemplate(id){
    var suffix = "Template/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * post data
  * @param {string} type - the datatype to post
  * @param {object} data - the data to post
  * @param {object} [query] - the query of url parameters
  * @returns {promise} - promise which resolves with data
  **/
  post(type, query, data){
    var url = this.base + type + "/post";
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            method: "POST",
            mode: "cors",
            body: JSON.stringify(data),
            credentials: "same-origin",
            headers: {
              "Content-Type": "application/json; charset=utf-8"
            }
        }).then(this.errorHandler)
  }

  /**
  * update data
  * @param {string} type - the datatype to get
  * @param {object} query - the query of url parameters
  * @param {object} data - the data to update
  * @returns {promise} - promise which resolves with data
  **/
  update(type, query, data){
    var url = this.base + type + "/update";
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            method: "UPDATE",
            mode: "cors",
            body: JSON.stringify(data),
            credentials: "same-origin",
            headers: {
              "Content-Type": "application/json; charset=utf-8"
            }
        }).then(this.errorHandler)
  }

  /**
  * delete data
  * @param {string} type - the datatype to get
  * @param {object} query - the query of url parameters
  * @returns {promise} - promise which resolves with data
  **/
  delete(type, query){
    var url = this.base + type + "/delete";
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
}

try{
  module.exports = Store;
}
catch(e){
  var a
}
<commit_msg>update store to new findBound endpoint<commit_after>// requires: Api_Utils
// METHODS HERE RETURN PROMISES
// for test server
try{
  var fetch = require('node-fetch');
}catch(e){
  var b;
}
/**
* converts an object into a string of url components
* @param {object} obj - keys and values
* @returns the url encoded string
**/
function objToParamStr(obj) {
    var parts = [];
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            if (Array.isArray(obj[i])) {
                // arrays are a list of strings with escaped quotes, surrounded by []
                parts.push(encodeURIComponent(i) + "=" + encodeURIComponent("[" + obj[i].map((x) => '\"' + x + '\"').toString() + "]"));
            } else {
                parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
            }
        }
    }
    return parts.join("&");
}
/**
 * @constructor
* Storage interpreter for camicroscope, uses same auth as origin
* @param base - base url for data
* @param [config] - configuration options, unused so far
**/
class Store{
  constructor(base, config){
    this.base = base || "./data/";
    this.config = config;
  }
  /**
   * errorHandler: handle the error response
   * @param  {Response} response
   * @return {object}
   */
  errorHandler(response){
    if (!response.ok) return {
      error:!response.ok,
      text:response.statusText,
      url:response.url
    };
    return response.json();
  }
  /**
  * find marks matching slide and/or marktype
  * @param {string} [name] - the associated slide name
  * @param {string} [slide] - the associated marktype name, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findMark(slide, name){
    var suffix = "Mark/find"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }

    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * find marks which contain a given point
  * @param {number} x0 - x min position of rect to search
  * @param {number} y0 - y min position of rect to search
  * @param {number} x1 - x max position of rect to search
  * @param {number} y1 - y max position of rect to search
  * @param {string} [name] - the associated slide name
  * @param {string} [slide] - the associated marktype name, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findMarkSpatial(x0, y0, x1, y1, name, slide, key){
    var suffix = "Mark/findBound"
    var url = this.base + suffix;
    var query = {}
    query.x0 = x0
    query.y0 = y0
    query.x1 = x1
    query.y1 = y1
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }
    if (key){
      query.key = key
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  getMarkByIds(ids, slide){
    if(!Array.isArray(ids) || !slide){
      return {hasError:true,message:'args are illegal'}
    }
    var suffix = "Mark/multi"
    var url = this.base + suffix;
    var query = {}
    var stringifiedIds = ids.map(id=>`"${id}"`).join(',');
    query.name = `[${stringifiedIds}]`;
    console.log(query.name);
    query.slide = slide;
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
    }).then(this.errorHandler)
  }

  /**
  * get mark by id
  * @param {string} id - the mark id
  * @returns {promise} - promise which resolves with data
  **/
  getMark(id){
    var suffix = "Mark/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
  addMark(json){
    var suffix = "Mark/post"
    var url = this.base + suffix;
    // api key for bindaas?
    return fetch(url, {
            method:"POST",
            credentials: "same-origin",
            mode: "cors",
            headers: {
            "Content-Type": "application/json; charset=utf-8",
            // "Content-Type": "application/x-www-form-urlencoded",
            },
            body:JSON.stringify(json)
        }).then(this.errorHandler)
  }
  deleteMark(id,slide){
    var suffix = "Mark/delete"
    var url = this.base + suffix;
    var query = {
      id:id,
      slide:slide
    }
    return fetch(url + "?" + objToParamStr(query), {
            method:"DELETE",
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
  /**
  * find marktypes given slide and name
  * @param {string} [name] - the associated slide name
  * @param {string} [slide] - the marktype name, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findMarkTypes(name, slide){
    var suffix = "Mark/findTypes"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
  // NOTE there is no getMarktype method since markypes are not stored separately from marks

  /**
  * find overlays matching name and/or type
  * @param {string} [name] - the overlay, supporting regex match
  * @param {string} [slide] - the associated slide id
  * @returns {promise} - promise which resolves with data
  **/
  findOverlay(name, slide){
    var suffix = "Overlay/find"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (slide){
      query.slide = slide
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * get overlay by id
  * @param {string} id - the overlay id
  * @returns {promise} - promise which resolves with data
  **/
  getOverlay(id){
    var suffix = "Overlay/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * find overlays matching name and/or type
  * @param {string} [name] - the slide name
  * @param {string} [location] - the slide location, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findSlide(slide, location){
    var suffix = "Slide/find"
    var url = this.base + suffix;
    var query = {}
    if (slide){
      query.slide = slide
    }
    if (location){
      query.location = location
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * get slide by id
  * @param {string} id - the slide id
  * @returns {promise} - promise which resolves with data
  **/
  getSlide(id){
    var suffix = "Slide/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * find templates matching name and/or type
  * @param {string} [name] - the template name, supporting regex match
  * @param {string} [type] - the template type, supporting regex match
  * @returns {promise} - promise which resolves with data
  **/
  findTemplate(name, type){
    var suffix = "Template/find"
    var url = this.base + suffix;
    var query = {}
    if (name){
      query.name = name
    }
    if (type){
      query.slide = slide
    }
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * get template by id
  * @param {string} id - the template id
  * @returns {promise} - promise which resolves with data
  **/
  getTemplate(id){
    var suffix = "Template/get"
    var url = this.base + suffix;
    var query = {'id':id}
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }

  /**
  * post data
  * @param {string} type - the datatype to post
  * @param {object} data - the data to post
  * @param {object} [query] - the query of url parameters
  * @returns {promise} - promise which resolves with data
  **/
  post(type, query, data){
    var url = this.base + type + "/post";
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            method: "POST",
            mode: "cors",
            body: JSON.stringify(data),
            credentials: "same-origin",
            headers: {
              "Content-Type": "application/json; charset=utf-8"
            }
        }).then(this.errorHandler)
  }

  /**
  * update data
  * @param {string} type - the datatype to get
  * @param {object} query - the query of url parameters
  * @param {object} data - the data to update
  * @returns {promise} - promise which resolves with data
  **/
  update(type, query, data){
    var url = this.base + type + "/update";
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            method: "UPDATE",
            mode: "cors",
            body: JSON.stringify(data),
            credentials: "same-origin",
            headers: {
              "Content-Type": "application/json; charset=utf-8"
            }
        }).then(this.errorHandler)
  }

  /**
  * delete data
  * @param {string} type - the datatype to get
  * @param {object} query - the query of url parameters
  * @returns {promise} - promise which resolves with data
  **/
  delete(type, query){
    var url = this.base + type + "/delete";
    // api key for bindaas?
    return fetch(url + "?" + objToParamStr(query), {
            credentials: "same-origin",
            mode: "cors"
        }).then(this.errorHandler)
  }
}

try{
  module.exports = Store;
}
catch(e){
  var a
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import VisibilitySensor from 'react-visibility-sensor';

class VerticalTimelineElement extends Component {
  constructor(props) {
    super(props);
    this.onVisibilitySensorChange = this.onVisibilitySensorChange.bind(this);
    this.state = { visible: false };
  }

  onVisibilitySensorChange(isVisible) {
    if (isVisible) {
      this.setState({ visible: true });
    }
  }

  render() {
    const {
      id,
      children,
      icon,
      iconStyle,
      iconOnClick,
      date,
      position,
      style,
      className,
      visibilitySensorProps,
    } = this.props;

    const { visible } = this.state;

    return (

        <VisibilitySensor
          {...visibilitySensorProps}
          onChange={this.onVisibilitySensorChange}
        >

              {icon}

              {children}
              {date}

        </VisibilitySensor>

    );
  }
}

VerticalTimelineElement.propTypes = {
  id: PropTypes.string,
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]),
  className: PropTypes.string,
  icon: PropTypes.element,
  iconStyle: PropTypes.shape({}),
  iconOnClick: PropTypes.func,
  style: PropTypes.shape({}),
  date: PropTypes.node,
  position: PropTypes.string,
  visibilitySensorProps: PropTypes.shape({}),
};

VerticalTimelineElement.defaultProps = {
  id: '',
  children: '',
  className: '',
  icon: null,
  iconStyle: null,
  style: null,
  date: '',
  position: '',
  iconOnClick: null,
  visibilitySensorProps: { partialVisibility: true, offset: { bottom: 80 } },
};

export default VerticalTimelineElement;
<commit_msg>Add new props contentStyle<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import VisibilitySensor from 'react-visibility-sensor';

class VerticalTimelineElement extends Component {
  constructor(props) {
    super(props);
    this.onVisibilitySensorChange = this.onVisibilitySensorChange.bind(this);
    this.state = { visible: false };
  }

  onVisibilitySensorChange(isVisible) {
    if (isVisible) {
      this.setState({ visible: true });
    }
  }

  render() {
    const {
      id,
      children,
      contentStyle,
      icon,
      iconStyle,
      iconOnClick,
      date,
      position,
      style,
      className,
      visibilitySensorProps,
    } = this.props;

    const { visible } = this.state;

    return (

        <VisibilitySensor
          {...visibilitySensorProps}
          onChange={this.onVisibilitySensorChange}
        >

              {icon}

              {children}
              {date}

        </VisibilitySensor>

    );
  }
}

VerticalTimelineElement.propTypes = {
  id: PropTypes.string,
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]),
  className: PropTypes.string,
  contentStyle: PropTypes.shape({}),
  icon: PropTypes.element,
  iconStyle: PropTypes.shape({}),
  iconOnClick: PropTypes.func,
  style: PropTypes.shape({}),
  date: PropTypes.node,
  position: PropTypes.string,
  visibilitySensorProps: PropTypes.shape({}),
};

VerticalTimelineElement.defaultProps = {
  id: '',
  children: '',
  className: '',
  contentStyle: null,
  icon: null,
  iconStyle: null,
  style: null,
  date: '',
  position: '',
  iconOnClick: null,
  visibilitySensorProps: { partialVisibility: true, offset: { bottom: 80 } },
};

export default VerticalTimelineElement;
<|endoftext|>


<commit_before>/**
 * @file Dropdown component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import {findDOMNode} from 'react-dom';
import classNames from 'classnames';

import RaisedButton from '../RaisedButton';
import Popup from '../Popup';
import Theme from '../Theme';

import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import DropdownCalculation from '../_vendors/DropdownCalculation';

class Dropdown extends Component {

    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.dropdown = createRef();
        this.dropdownEl = null;
        this.trigger = createRef();
        this.triggerEl = null;
        this.pop = createRef();

        this.state = {
            popupVisible: false,
            isAbove: false
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.trigger && this.trigger.current && this.trigger.current.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.trigger && this.trigger.current && this.trigger.current.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.trigger && this.trigger.current && this.trigger.current.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.pop && this.pop.current && this.pop.current.resetPosition();
    };

    /**
     * public
     */
    openPopup = e => {
        this.setState({
            popupVisible: true
        }, () => {
            const {onOpenPopup, onFocus} = this.props;
            onOpenPopup && onOpenPopup(e);
            onFocus && onFocus(e);
        });
    };

    /**
     * public
     */
    closePopup = e => {

        this.setState({
            popupVisible: false
        }, () => {
            const {onClosePopup, onBlur} = this.props;
            onClosePopup && onClosePopup(e);
            onBlur && onBlur(e);
        });

    };

    handleRequestClose = e => {

        if (!this.props.isBlurClose) {
            return;
        }

        this.closePopup(e);

    };

    togglePopup = e => {

        const {onTriggerClick} = this.props,
            {popupVisible} = this.state;

        onTriggerClick && onTriggerClick(popupVisible, e);

        if (popupVisible) {
            this.closePopup(e);
        } else {
            this.openPopup(e);
        }

    };

    handlePopupRender = popupEl => {

        if (this.props.position) {
            return;
        }

        const isAbove = DropdownCalculation.isAbove(this.dropdownEl, this.triggerEl, findDOMNode(popupEl));
        if (isAbove !== this.state.isAbove) {
            this.setState({
                isAbove
            });
        }

    };

    componentDidMount() {
        this.dropdownEl = this.dropdown && this.dropdown.current;
        this.triggerEl = this.trigger && this.trigger.current && findDOMNode(this.trigger.current);
    }

    render() {

        const {

                children,

                className, triggerClassName, popupClassName, style, triggerStyle, popupStyle,
                theme, activatedTheme, popupTheme, position, iconCls, triggerValue, title, tip, tipPosition,
                rightIconCls, disabled, isLoading, disableTouchRipple, autoPopupWidth,
                resetPopPositionWait, parentEl, triggerEl,

                // events
                onMouseOver, onMouseOut,

                // not passing down these props
                autoClose, isBlurClose, placeholderClassName, onOpenPopup, onClosePopup,

                ...restProps

            } = this.props,
            {popupVisible, isAbove} = this.state,

            isAboveFinally = position === Position.TOP || position === Position.TOP_LEFT
                || position === Position.TOP_RIGHT || (!position && isAbove);

        return (
            <div {...restProps}
                 ref={this.dropdown}
                 className={classNames('dropdown', {
                     activated: popupVisible,
                     [className]: className
                 })}
                 style={style}>

                <RaisedButton ref={this.trigger}
                              className={classNames('dropdown-trigger', isAboveFinally ? 'above' : 'blow', {
                                  activated: popupVisible,
                                  [triggerClassName]: triggerClassName
                              })}
                              style={triggerStyle}
                              theme={popupVisible ? activatedTheme : theme}
                              value={triggerValue}
                              title={title}
                              tip={tip}
                              tipPosition={tipPosition}
                              triggerEl={triggerEl}
                              parentEl={parentEl}
                              iconCls={iconCls}
                              rightIconCls={`${rightIconCls} dropdown-trigger-icon`}
                              disabled={disabled}
                              isLoading={isLoading}
                              disableTouchRipple={disableTouchRipple}
                              onMouseOver={onMouseOver}
                              onMouseOut={onMouseOut}
                              onClick={this.togglePopup}/>

                <Popup ref={this.pop}
                       className={classNames('dropdown-popup', isAboveFinally ? 'above' : 'blow', {
                           [popupClassName]: popupClassName
                       })}
                       style={autoPopupWidth ?
                           Object.assign({
                               width: this.triggerEl && this.triggerEl.offsetWidth
                           }, popupStyle)
                           :
                           popupStyle}
                       theme={popupTheme}
                       visible={popupVisible}
                       triggerEl={this.triggerEl}
                       parentEl={parentEl}
                       hasTriangle={false}
                       position={position ? position : (isAboveFinally ? Position.TOP_LEFT : Position.BOTTOM_LEFT)}
                       resetPositionWait={resetPopPositionWait}
                       onRender={this.handlePopupRender}
                       onRequestClose={this.handleRequestClose}>
                    {children}
                </Popup>

            </div>
        );

    }
}

Dropdown.propTypes = {

    children: PropTypes.any,

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    placeholderClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the trigger element.
     */
    triggerStyle: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The theme.
     */
    activatedTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The popup theme.
     */
    popupTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    parentEl: PropTypes.object,
    triggerEl: PropTypes.object,

    /**
     * The value of the dropDown trigger.
     */
    triggerValue: PropTypes.any,

    iconCls: PropTypes.string,
    rightIconCls: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * If true, the dropDown will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true, the dropDown will be loading.
     */
    isLoading: PropTypes.bool,

    disableTouchRipple: PropTypes.bool,

    /**
     * Whether following the trigger width or not.
     */
    autoPopupWidth: PropTypes.bool,

    /**
     * If true, the dropdown box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    /**
     * If true, the dropdown box automatically closed when blur.
     */
    isBlurClose: PropTypes.bool,

    resetPopPositionWait: PropTypes.number,

    /**
     * Callback function fired when the popup is open.
     */
    onOpenPopup: PropTypes.func,

    /**
     * Callback function fired when the popup is close.
     */
    onClosePopup: PropTypes.func,

    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func,
    onTriggerClick: PropTypes.func

};

Dropdown.defaultProps = {

    parentEl: document.body,

    theme: Theme.DEFAULT,
    activatedTheme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    isLoading: false,
    disableTouchRipple: false,
    autoPopupWidth: true,
    autoClose: true,
    isBlurClose: true,
    tipPosition: Position.BOTTOM,

    resetPopPositionWait: 250

};

export default Dropdown;
<commit_msg>update Dropdown<commit_after>/**
 * @file Dropdown component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import {findDOMNode} from 'react-dom';
import classNames from 'classnames';

import RaisedButton from '../RaisedButton';
import Popup from '../Popup';
import Theme from '../Theme';

import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import DropdownCalculation from '../_vendors/DropdownCalculation';

class Dropdown extends Component {

    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.dropdown = createRef();
        this.dropdownEl = null;
        this.trigger = createRef();
        this.triggerEl = null;
        this.pop = createRef();

        this.state = {
            popupVisible: false,
            isAbove: false
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.trigger && this.trigger.current && this.trigger.current.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.trigger && this.trigger.current && this.trigger.current.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.trigger && this.trigger.current && this.trigger.current.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.pop && this.pop.current && this.pop.current.resetPosition();
    };

    /**
     * public
     */
    openPopup = e => {
        this.setState({
            popupVisible: true
        }, () => {
            const {onOpenPopup, onFocus} = this.props;
            onOpenPopup && onOpenPopup(e);
            onFocus && onFocus(e);
        });
    };

    /**
     * public
     */
    closePopup = e => {

        this.setState({
            popupVisible: false
        }, () => {
            const {onClosePopup, onBlur} = this.props;
            onClosePopup && onClosePopup(e);
            onBlur && onBlur(e);
        });

    };

    handleRequestClose = e => {

        if (!this.props.isBlurClose) {
            return;
        }

        this.closePopup(e);

    };

    togglePopup = e => {

        const {onTriggerClick} = this.props,
            {popupVisible} = this.state;

        onTriggerClick && onTriggerClick(popupVisible, e);

        if (popupVisible) {
            this.closePopup(e);
        } else {
            this.openPopup(e);
        }

    };

    handlePopupRender = popupEl => {

        if (this.props.position) {
            return;
        }

        const isAbove = DropdownCalculation.isAbove(this.dropdownEl, this.triggerEl, findDOMNode(popupEl));
        if (isAbove !== this.state.isAbove) {
            this.setState({
                isAbove
            });
        }

    };

    componentDidMount() {
        this.dropdownEl = this.dropdown && this.dropdown.current;
        this.triggerEl = this.trigger && this.trigger.current && findDOMNode(this.trigger.current);
    }

    render() {

        const {

                children,

                className, triggerClassName, popupClassName, style, triggerStyle, popupStyle,
                theme, activatedTheme, popupTheme, position, iconCls, triggerValue, title, tip, tipPosition,
                rightIconCls, disabled, isLoading, disableTouchRipple, autoPopupWidth,
                resetPopPositionWait, parentEl, triggerEl, shouldFollowScroll,

                // events
                onMouseOver, onMouseOut,

                // not passing down these props
                autoClose, isBlurClose, placeholderClassName, onOpenPopup, onClosePopup,

                ...restProps

            } = this.props,
            {popupVisible, isAbove} = this.state,

            isAboveFinally = position === Position.TOP || position === Position.TOP_LEFT
                || position === Position.TOP_RIGHT || (!position && isAbove);

        return (
            <div {...restProps}
                 ref={this.dropdown}
                 className={classNames('dropdown', {
                     activated: popupVisible,
                     [className]: className
                 })}
                 style={style}>

                <RaisedButton ref={this.trigger}
                              className={classNames('dropdown-trigger', isAboveFinally ? 'above' : 'blow', {
                                  activated: popupVisible,
                                  [triggerClassName]: triggerClassName
                              })}
                              style={triggerStyle}
                              theme={popupVisible ? activatedTheme : theme}
                              value={triggerValue}
                              title={title}
                              tip={tip}
                              tipPosition={tipPosition}
                              triggerEl={triggerEl}
                              parentEl={parentEl}
                              iconCls={iconCls}
                              rightIconCls={`${rightIconCls} dropdown-trigger-icon`}
                              disabled={disabled}
                              isLoading={isLoading}
                              disableTouchRipple={disableTouchRipple}
                              onMouseOver={onMouseOver}
                              onMouseOut={onMouseOut}
                              onClick={this.togglePopup}/>

                <Popup ref={this.pop}
                       className={classNames('dropdown-popup', isAboveFinally ? 'above' : 'blow', {
                           [popupClassName]: popupClassName
                       })}
                       style={autoPopupWidth ?
                           Object.assign({
                               width: this.triggerEl && this.triggerEl.offsetWidth
                           }, popupStyle)
                           :
                           popupStyle}
                       theme={popupTheme}
                       visible={popupVisible}
                       triggerEl={this.triggerEl}
                       parentEl={parentEl}
                       hasTriangle={false}
                       position={position ? position : (isAboveFinally ? Position.TOP_LEFT : Position.BOTTOM_LEFT)}
                       resetPositionWait={resetPopPositionWait}
                       shouldFollowScroll={shouldFollowScroll}
                       onRender={this.handlePopupRender}
                       onRequestClose={this.handleRequestClose}>
                    {children}
                </Popup>

            </div>
        );

    }
}

Dropdown.propTypes = {

    children: PropTypes.any,

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    placeholderClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the trigger element.
     */
    triggerStyle: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The theme.
     */
    activatedTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The popup theme.
     */
    popupTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    parentEl: PropTypes.object,
    triggerEl: PropTypes.object,

    /**
     * The value of the dropDown trigger.
     */
    triggerValue: PropTypes.any,

    iconCls: PropTypes.string,
    rightIconCls: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * If true, the dropDown will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true, the dropDown will be loading.
     */
    isLoading: PropTypes.bool,

    disableTouchRipple: PropTypes.bool,

    /**
     * Whether following the trigger width or not.
     */
    autoPopupWidth: PropTypes.bool,

    /**
     * If true, the dropdown box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    /**
     * If true, the dropdown box automatically closed when blur.
     */
    isBlurClose: PropTypes.bool,
    shouldFollowScroll: PropTypes.bool,
    resetPopPositionWait: PropTypes.number,

    /**
     * Callback function fired when the popup is open.
     */
    onOpenPopup: PropTypes.func,

    /**
     * Callback function fired when the popup is close.
     */
    onClosePopup: PropTypes.func,

    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func,
    onTriggerClick: PropTypes.func

};

Dropdown.defaultProps = {

    parentEl: document.body,

    theme: Theme.DEFAULT,
    activatedTheme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    isLoading: false,
    disableTouchRipple: false,
    autoPopupWidth: true,
    autoClose: true,
    isBlurClose: true,
    tipPosition: Position.BOTTOM,

    resetPopPositionWait: 250

};

export default Dropdown;
<|endoftext|>


<commit_before>// account.js

var org = {

	// added on script load
	config: {}

	// added on authentication
	,user: {}

	// called on script load
	,init: function() {
		_self = this;

		$('[data-toggle="tab"]').click(function(e) {
		//$('.nav-tabs a').click(function (e) {
    	// No e.preventDefault() here
    	//$(this).tab('show');

    	window.location.hash = $(this).attr('href');

    	//console.log( $(this).attr('href') );

		});

		this.initMyAccount();
	} // init()

, initMyAccount: function() {
		this.user = $('#spl-account-summary').data('account');
		//console.log(this.user);

		/*
		// this is the input field
		$('body').on('click', '#spl-update-email', function(e) {
			e.preventDefault();

			console.log( $(this).val() );
		});
		*/

  } // initMyAccount();

};
<commit_msg>delegate tab hashchange<commit_after>// account.js

var org = {

	// added on script load
	config: {}

	// added on authentication
	,user: {}

	// called on script load
	,init: function() {
		_self = this;

		// apply hashchange on tab event
		$('body').on('click', '[data-toggle="tab"]', function(e) {
			window.location.hash = $(this).attr('href');
		});

		this.initMyAccount();
	} // init()

, initMyAccount: function() {
		this.user = $('#spl-account-summary').data('account');
		//console.log(this.user);

		/*
		// this is the input field
		$('body').on('click', '#spl-update-email', function(e) {
			e.preventDefault();

			console.log( $(this).val() );
		});
		*/

  } // initMyAccount();

};
<|endoftext|>


<commit_before>/* eslint-disable promise/always-return */
import { runAuthenticatedQuery } from "schema/v2/test/utils"

describe("End sale mutation", () => {
  const sale = {
    id: "foo-foo",
    _id: "123",
    currency: "$",
    is_auction: true,
    increment_strategy: "default",
  }

  const query = `
  mutation {
    endSale(input: {sale_id: "123"}) {
      sale {
        id
      }
    }
  }
  `

  const context = {
    endSaleLoader: sinon.stub().returns(Promise.resolve(sale)),
  }

  it("ends the sale", async () => {
    return runAuthenticatedQuery(query, context).then(data => {
      expect(data).toEqual({
        endSale: {
          sale: {
            id: "foo-foo",
          },
        },
      })
    })
  })
})
<commit_msg>Fix v2 end_sale_mutation test<commit_after>/* eslint-disable promise/always-return */
import { runAuthenticatedQuery } from "schema/v2/test/utils"

describe("End sale mutation", () => {
  const sale = {
    id: "foo-foo",
    _id: "123",
    currency: "$",
    is_auction: true,
    increment_strategy: "default",
  }

  const query = `
  mutation {
    endSale(input: {saleID: "123"}) {
      sale {
        slug
      }
    }
  }
  `

  const context = {
    endSaleLoader: sinon.stub().returns(Promise.resolve(sale)),
  }

  it("ends the sale", async () => {
    return runAuthenticatedQuery(query, context).then(data => {
      expect(data).toEqual({
        endSale: {
          sale: {
            slug: "foo-foo",
          },
        },
      })
    })
  })
})
<|endoftext|>


<commit_before>var cf = require('../')
  , seaport = require('seaport')
  , pkg = require('../package.json')

seaport .connect.apply(seaport, process.argv.slice(2))
        .service(pkg.name + '@' + pkg.version, cf.listen)
<commit_msg>add seaport env support<commit_after>var cf = require('../')
  , seaport = require('seaport')
  , pkg = require('../package.json')

var ports

var args = []

if (process.env.SEAPORT_HOST && process.env.SEAPORT_PORT) {
  args.push(process.env.SEAPORT_HOST, process.env.SEAPORT_PORT)

} else if (process.env.SEAPORT_PORT) {
  args.push(process.env.SEAPORT_PORT)

} else if (process.env.SEAPORT) {
  args.push(process.env.SEAPORT)

}

if (args.length) {
  if (process.env.SEAPORT_SECRET) {
    args.push( { secret: process.env.SEAPORT_SECRET })
  }
} else {
  args = process.argv.slice(2)
}

if (!args.length) {
  console.error('Missing seaport connection details')
  return
}

seaport .connect.apply(seaport, args)
        .service(pkg.name + '@' + pkg.version, cf.listen)
<|endoftext|>


<commit_before>

/**
 * Constructor for a GameStartForm
 * @param {jQueryObject} formElement the jQuery element wrapping
 *     the form.
 * @param {jQueryObject} playButton the jQuery element wrapping
 *     the button that starts the game.
 * @constructor
 * @const
 */
othello.GameStartForm = function(formElement, playButton) {
  /** @const */ this.formElement = formElement;
  /** @const */ this.playButton = playButton;
};

/**
 * Attach this form to a parent element, presumably to add it to
 * the document being displayed
 * @param {jQueryObject} parentElement the parent for this form.
 * @const
 */
othello.GameStartForm.prototype.attachTo = function(parentElement) {
  parentElement.append(this.formElement);
};

othello.GameStartForm.prototype.addPlayButtonClickHandler =
    function(handler) {
  this.playButton.click(handler);
}

othello.GameStartForm.prototype.blackPlayerSelection = function() {
  /** @const */ var selected = $('input').filter(function() {
    /** @const */ var element = $(this);
    return element.attr('type') === 'radio' &&
           element.attr('name') === 'blackPlayer' &&
           element.attr('checked') === 'checked';
  });
  return selected.attr('id');
};

othello.GameStartForm.prototype.whitePlayerSelection = function() {
  /** @const */ var selected = $('input').filter(function() {
    /** @const */ var element = $(this);
    return element.attr('type') === 'radio' &&
           element.attr('name') === 'whitePlayer' &&
           element.attr('checked') === 'checked';
  });
  return selected.attr('id');
};

/**
 * Factory function to create a default form for Othello.
 * @return {othello.GameStartForm} a form asking who will play
 *     each side.
 * @const
 */
othello.GameStartForm.createDefaultStartForm = function() {
  return new othello.GameStartForm.Builder().
      whitePlayerFieldset().
      blackPlayerFieldset().
      playButton().
      build();
};

/**
 * Constructor for a Builder for GameStartForms. Using a Builder
 * instead of hard coding the elements makes the form more
 * flexible.
 * @constructor
 * @const
 */
othello.GameStartForm.Builder = function() {
  /** @const */ this.formElement = $('<form>');
  this.playButtonElement = othello.utils.None.instance;
};

/**
 * Add a fieldset to ask who will play white
 * @return {othello.GameStartForm.Builder} the Builder for chaining.
 * @const
 */
othello.GameStartForm.Builder.prototype.whitePlayerFieldset = function() {
  /** @const */ var whiteFieldset =
      othello.PlayerFieldset.createWhitePlayerFieldset();
  whiteFieldset.attachTo(this.formElement);
  return this;
};

/**
 * Add a fieldset to ask who will play black
 * @return {othello.GameStartForm.Builder} the Builder for chaining.
 * @const
 */
othello.GameStartForm.Builder.prototype.blackPlayerFieldset = function() {
  /** @const */ var blackFieldset =
      othello.PlayerFieldset.createBlackPlayerFieldset();
  blackFieldset.attachTo(this.formElement);
  return this;
};

/**
 * Add a button to start the game.
 * @return {othello.GameStartForm.Builder} the Builder for chaining.
 * @const
 */
othello.GameStartForm.Builder.prototype.playButton = function() {
  this.playButtonElement = $('<input>', {
    type: 'button',
    value: 'Play!'
  });
  this.formElement.append(this.playButtonElement);
  return this;
};

/**
 * Build the form
 * @return {othello.GameStartForm} the newly built form.
 * @const
 */
othello.GameStartForm.Builder.prototype.build = function() {
  /** @const */ var playButton = /** @type {jQueryObject} */
      (this.playButtonElement.getOrElse(null));
  if (!playButton) {
    throw new Error("Tried to build a start form without a play button");
  }
  return new othello.GameStartForm(this.formElement, playButton);
};

/**
 * Class to represent a fieldset to choose who will play a side.
 * @param {*} fieldsetElement the element containing the
 *     fieldset, as a jQuery object.
 * @constructor
 * @const
 */
othello.PlayerFieldset = function(fieldsetElement) {
  /** @const */ this.fieldsetElement = fieldsetElement;
};

/**
 * Attach this fieldset to a parent
 * @param {*} parentElement the parent for this fieldset.
 * @const
 */
othello.PlayerFieldset.prototype.attachTo = function(parentElement) {
  parentElement.append(this.fieldsetElement);
};

/**
 * Factory function to create a default fieldset for White
 * @return {othello.PlayerFieldset} a new fieldset.
 * @const
 */
othello.PlayerFieldset.createWhitePlayerFieldset = function() {
  return othello.PlayerFieldset.createPlayerFieldset('White Player', 'white');
};

/**
 * Factory function to create a default fieldset for Black
 * @return {othello.PlayerFieldset} a new fieldset.
 * @const
 */
othello.PlayerFieldset.createBlackPlayerFieldset = function() {
  return othello.PlayerFieldset.createPlayerFieldset('Black Player', 'black');
};

/**
 * Factory function to create an arbitrary player fieldset
 * @param {string} legendName the name for the legend element.
 * @param {string} color either 'white' or 'black'.
 * @return {othello.PlayerFieldset} the created Fieldset.
 * @const
 */
othello.PlayerFieldset.createPlayerFieldset = function(legendName, color) {
  return new othello.PlayerFieldset.Builder().id(color + 'Fieldset').
      legend(legendName).
      radioButtonSetNamed(color + 'Player').
          radioButton(color + 'Human').withLabel('Human').
          radioButton(color + 'EasyAi').withLabel('Easy AI').
          radioButton(color + 'MediumAi').withLabel('Medium AI').build();
};

/**
 * Initialize a PlayerFieldset Builder. Call the provided
 * methods to build the fieldset. Note that order does matter,
 * the order in which methods are called will be the order in
 * which elements are displayed in the resulting document.
 * @constructor
 * @const
 */
othello.PlayerFieldset.Builder = function() {
  /**
   * @const
   * @type {jQueryObject}
   */
  this.fieldsetElement = $('<fieldset>');
};

/**
 * Set the ID of this.fieldsetElement
 * @param {string} idForFieldset the value for the ID.
 * @return {othello.PlayerFieldset.Builder} the Builder for chaining.
 * @const
 */
othello.PlayerFieldset.Builder.prototype.id = function(idForFieldset) {
  this.fieldsetElement.attr('id', idForFieldset);
  return this;
};

/**
 * Add a legend to the top.
 * @param {string} legendName the name for the legend.
 * @return {othello.PlayerFieldset.Builder} this Builder for
 *     chaining.
 * @const
 */
othello.PlayerFieldset.Builder.prototype.legend = function(legendName) {
  /** @const */ var legendHtml = $('<legend>', {html: legendName});
  this.fieldsetElement.append(legendHtml);
  return this;
};

/**
 * Creates a set of radio buttons. Uses nested closures to provide
 * a more fluent interface. Usage:
 * builder.radioButtonSetNamed('whitePlayer').
 *     radioButton('whiteHuman').checked().withLabel('Human').
 *     radioButton('whiteEasyAi').withLabel('Easy AI').
 *     radioButton('whiteMediumAi').withLabel('Medium AI').build();
 * @param {string} buttonName the name of the button.
 * @return {*} an object supporting the functions from the given example.
 * @const
 */
othello.PlayerFieldset.Builder.prototype.radioButtonSetNamed =
    function(buttonName) {
  /** @const */ var fieldsetElement = this.fieldsetElement;
  var checked = false;
  /** @const */ var radioButtonBuilder = {
    radioButton: function(buttonId) {
      /** @const */ var buttonDetailBuilder = {
        checked: function() {
          checked = true;
          return buttonDetailBuilder;
        },

        withLabel: function(labelHtml) {
          /** @const */ var radioButtonAttributes = {
            type: 'radio',
            name: buttonName,
            id: buttonId
          };
          if (checked) {
            radioButtonAttributes['checked'] = 'checked';
            checked = false;
          }
          /** @const */ var radioElement = $('<input>',
              radioButtonAttributes);
          /** @const */ var labelElement = $('<label>', {
            'for': buttonId,
            html: labelHtml
          });
          fieldsetElement.append(radioElement).append(labelElement);
          return radioButtonBuilder;
        }
      };
      return buttonDetailBuilder;
    },

    build: function() {
      return new othello.PlayerFieldset(fieldsetElement);
    }
  };
  return radioButtonBuilder;
};
<commit_msg>Fixed runtime errors with the factory when running in a browser<commit_after>

/**
 * Constructor for a GameStartForm
 * @param {jQueryObject} formElement the jQuery element wrapping
 *     the form.
 * @param {jQueryObject} playButton the jQuery element wrapping
 *     the button that starts the game.
 * @constructor
 * @const
 */
othello.GameStartForm = function(formElement, playButton) {
  /** @const */ this.formElement = formElement;
  /** @const */ this.playButton = playButton;
};

/**
 * Attach this form to a parent element, presumably to add it to
 * the document being displayed
 * @param {jQueryObject} parentElement the parent for this form.
 * @const
 */
othello.GameStartForm.prototype.attachTo = function(parentElement) {
  parentElement.append(this.formElement);
};

othello.GameStartForm.prototype.addPlayButtonClickHandler =
    function(handler) {
  this.playButton.click(handler);
}

othello.GameStartForm.prototype.blackPlayerSelection = function() {
  /** @const */ var selected = $('input').filter(function() {
    /** @const */ var element = $(this);
    return element.attr('type') === 'radio' &&
           element.attr('name') === 'blackPlayer' &&
           element.attr('checked') === 'checked';
  });
  return selected.attr('id');
};

othello.GameStartForm.prototype.whitePlayerSelection = function() {
  /** @const */ var selected = $('input').filter(function() {
    /** @const */ var element = $(this);
    return element.attr('type') === 'radio' &&
           element.attr('name') === 'whitePlayer' &&
           element.attr('checked') === 'checked';
  });
  return selected.attr('id');
};

/**
 * Factory function to create a default form for Othello.
 * @return {othello.GameStartForm} a form asking who will play
 *     each side.
 * @const
 */
othello.GameStartForm.createDefaultStartForm = function() {
  return new othello.GameStartForm.Builder().
      whitePlayerFieldset().
      blackPlayerFieldset().
      playButton().
      build();
};

/**
 * Constructor for a Builder for GameStartForms. Using a Builder
 * instead of hard coding the elements makes the form more
 * flexible.
 * @constructor
 * @const
 */
othello.GameStartForm.Builder = function() {
  /** @const */ this.formElement = $('<form>');
  this.playButtonElement = othello.utils.None.instance;
};

/**
 * Add a fieldset to ask who will play white
 * @return {othello.GameStartForm.Builder} the Builder for chaining.
 * @const
 */
othello.GameStartForm.Builder.prototype.whitePlayerFieldset = function() {
  /** @const */ var whiteFieldset =
      othello.PlayerFieldset.createWhitePlayerFieldset();
  whiteFieldset.attachTo(this.formElement);
  return this;
};

/**
 * Add a fieldset to ask who will play black
 * @return {othello.GameStartForm.Builder} the Builder for chaining.
 * @const
 */
othello.GameStartForm.Builder.prototype.blackPlayerFieldset = function() {
  /** @const */ var blackFieldset =
      othello.PlayerFieldset.createBlackPlayerFieldset();
  blackFieldset.attachTo(this.formElement);
  return this;
};

/**
 * Add a button to start the game.
 * @return {othello.GameStartForm.Builder} the Builder for chaining.
 * @const
 */
othello.GameStartForm.Builder.prototype.playButton = function() {
  this.playButtonElement = new othello.utils.Some($('<input>', {
    type: 'button',
    value: 'Play!'
  }));
  this.formElement.append(this.playButtonElement.getOrElse(null));
  return this;
};

/**
 * Build the form
 * @return {othello.GameStartForm} the newly built form.
 * @const
 */
othello.GameStartForm.Builder.prototype.build = function() {
  /** @const */ var playButton = /** @type {jQueryObject} */
      (this.playButtonElement.getOrElse(null));
  if (!playButton) {
    throw new Error("Tried to build a start form without a play button");
  }
  return new othello.GameStartForm(this.formElement, playButton);
};

/**
 * Class to represent a fieldset to choose who will play a side.
 * @param {*} fieldsetElement the element containing the
 *     fieldset, as a jQuery object.
 * @constructor
 * @const
 */
othello.PlayerFieldset = function(fieldsetElement) {
  /** @const */ this.fieldsetElement = fieldsetElement;
};

/**
 * Attach this fieldset to a parent
 * @param {*} parentElement the parent for this fieldset.
 * @const
 */
othello.PlayerFieldset.prototype.attachTo = function(parentElement) {
  parentElement.append(this.fieldsetElement);
};

/**
 * Factory function to create a default fieldset for White
 * @return {othello.PlayerFieldset} a new fieldset.
 * @const
 */
othello.PlayerFieldset.createWhitePlayerFieldset = function() {
  return othello.PlayerFieldset.createPlayerFieldset('White Player', 'white');
};

/**
 * Factory function to create a default fieldset for Black
 * @return {othello.PlayerFieldset} a new fieldset.
 * @const
 */
othello.PlayerFieldset.createBlackPlayerFieldset = function() {
  return othello.PlayerFieldset.createPlayerFieldset('Black Player', 'black');
};

/**
 * Factory function to create an arbitrary player fieldset
 * @param {string} legendName the name for the legend element.
 * @param {string} color either 'white' or 'black'.
 * @return {othello.PlayerFieldset} the created Fieldset.
 * @const
 */
othello.PlayerFieldset.createPlayerFieldset = function(legendName, color) {
  return new othello.PlayerFieldset.Builder().id(color + 'Fieldset').
      legend(legendName).
      radioButtonSetNamed(color + 'Player').
          radioButton(color + 'Human').withLabel('Human').
          radioButton(color + 'EasyAi').withLabel('Easy AI').
          radioButton(color + 'MediumAi').withLabel('Medium AI').build();
};

/**
 * Initialize a PlayerFieldset Builder. Call the provided
 * methods to build the fieldset. Note that order does matter,
 * the order in which methods are called will be the order in
 * which elements are displayed in the resulting document.
 * @constructor
 * @const
 */
othello.PlayerFieldset.Builder = function() {
  /**
   * @const
   * @type {jQueryObject}
   */
  this.fieldsetElement = $('<fieldset>');
};

/**
 * Set the ID of this.fieldsetElement
 * @param {string} idForFieldset the value for the ID.
 * @return {othello.PlayerFieldset.Builder} the Builder for chaining.
 * @const
 */
othello.PlayerFieldset.Builder.prototype.id = function(idForFieldset) {
  this.fieldsetElement.attr('id', idForFieldset);
  return this;
};

/**
 * Add a legend to the top.
 * @param {string} legendName the name for the legend.
 * @return {othello.PlayerFieldset.Builder} this Builder for
 *     chaining.
 * @const
 */
othello.PlayerFieldset.Builder.prototype.legend = function(legendName) {
  /** @const */ var legendHtml = $('<legend>', {html: legendName});
  this.fieldsetElement.append(legendHtml);
  return this;
};

/**
 * Creates a set of radio buttons. Uses nested closures to provide
 * a more fluent interface. Usage:
 * builder.radioButtonSetNamed('whitePlayer').
 *     radioButton('whiteHuman').checked().withLabel('Human').
 *     radioButton('whiteEasyAi').withLabel('Easy AI').
 *     radioButton('whiteMediumAi').withLabel('Medium AI').build();
 * @param {string} buttonName the name of the button.
 * @return {*} an object supporting the functions from the given example.
 * @const
 */
othello.PlayerFieldset.Builder.prototype.radioButtonSetNamed =
    function(buttonName) {
  /** @const */ var fieldsetElement = this.fieldsetElement;
  var checked = false;
  /** @const */ var radioButtonBuilder = {
    radioButton: function(buttonId) {
      /** @const */ var buttonDetailBuilder = {
        checked: function() {
          checked = true;
          return buttonDetailBuilder;
        },

        withLabel: function(labelHtml) {
          /** @const */ var radioButtonAttributes = {
            type: 'radio',
            name: buttonName,
            id: buttonId
          };
          if (checked) {
            radioButtonAttributes['checked'] = 'checked';
            checked = false;
          }
          /** @const */ var radioElement = $('<input>',
              radioButtonAttributes);
          /** @const */ var labelElement = $('<label>', {
            'for': buttonId,
            html: labelHtml
          });
          fieldsetElement.append(radioElement).append(labelElement);
          return radioButtonBuilder;
        }
      };
      return buttonDetailBuilder;
    },

    build: function() {
      return new othello.PlayerFieldset(fieldsetElement);
    }
  };
  return radioButtonBuilder;
};
<|endoftext|>


<commit_before>define(["Emitter"], function(Emitter) {
	"use strict";

	//TODO REFACTOR, invert control -> create cell array: cell[x][y] = {hasPlayer, hasBall, isPlayerSelected, isPosibility, isSelectedPosibility}

	var UserAreaController = function() {
		this.stateHelper = null;
		this.modifiedState = {};

		this.selectedPlayer = "";
		this.isPlayerInSelectActionState = false;

		this.seletecActions = {};
		this.cellChosen = {};
	};

	Emitter.mixInto(UserAreaController);

	UserAreaController.prototype.loadStaticContext = function() {
		this.trigger("load-static-state");
	};

	UserAreaController.prototype.loadState = function(stateHelper, isInitial) {
		this.stateHelper = stateHelper;

		this.trigger("load-state", this);
	};

	UserAreaController.prototype.cellClicked = function(x, y) {
		console.log("CEll {x: " + x + ", y: " + y + "} clicked");

		if (this.isPlayerInSelectActionState) {
			setChosenCell.call(this, x, y);
		} else {
			this.trigger("player-unselected", this);
			this.selectedPlayer = this.stateHelper.getPlayerIn(x, y);
			if (this.selectedPlayer) {
				this.trigger("player-selected", this);
			}
		}
	};

	UserAreaController.prototype.actionClicked = function(action) {
		console.log(this.selectedPlayer + " selected " + action);

		if (action !== "" && action !== "Card" && action !== "Shoot") {
			this.isPlayerInSelectActionState = true;
			this.seletecActions[this.selectedPlayer] = action;
			this.trigger("action-clicked", this);
		} else {
			delete this.cellChosen[this.selectedPlayer];
			this.isPlayerInSelectActionState = false;
		}
		this.trigger("action-state-changed", this);
	};

	UserAreaController.prototype.getDimensions = function() {
		return this.stateHelper.getDimensions();
	};

	UserAreaController.prototype.getUserPlayerPositions = function() {
		return this.stateHelper.getUserPlayerPositions();
	};

	UserAreaController.prototype.getRivalPlayerPositions = function() {
		return this.stateHelper.getRivalPlayerPositions();
	};

	UserAreaController.prototype.getSelectedPlayer = function() {
		return this.selectedPlayer;
	};

	UserAreaController.prototype.getPlayerImage = function() {
		return (this.stateHelper) ? this.stateHelper.getPlayerImage(this.selectedPlayer) : "";
	};

	UserAreaController.prototype.getPlayerStats = function() {
		return this.stateHelper.getPlayerStats(this.selectedPlayer);
	};

	UserAreaController.prototype.getPlayerActions = function() {
		return this.stateHelper.getPlayerActions(this.selectedPlayer);
	};

	UserAreaController.prototype.getSelectedAction = function() {
		return (this.seletecActions[this.selectedPlayer]) ? this.seletecActions[this.selectedPlayer] : "";
	};

	UserAreaController.prototype.getTeamScores = function() {
		return this.stateHelper.getTeamScores();
	};

	UserAreaController.prototype.getSelectedPlayerPosition = function() {
		return this.stateHelper.getPlayerPosition(this.selectedPlayer);
	};

	UserAreaController.prototype.getActionPosibilities = function() {
		var action = this.seletecActions[this.selectedPlayer];
		this.actionPosibilities = this.stateHelper["get" + action + "Posibilities"](this.selectedPlayer);
		return this.actionPosibilities;
	};

	UserAreaController.prototype.getSelectActionState = function() {
		return this.isPlayerInSelectActionState;
	};

	UserAreaController.prototype.getSelectedActionPosition = function() {
		return (this.cellChosen[this.selectedPlayer]) ? this.cellChosen[this.selectedPlayer] : null;
	};

	function setChosenCell(x, y) {
		for (var i = 0, len = this.actionPosibilities.length; i < len; i++) {
			if (this.actionPosibilities[i].x === x && this.actionPosibilities[i].y === y) {
				this.cellChosen[this.selectedPlayer] = {"x": x, "y": y};
				this.isPlayerInSelectActionState = false;
				this.trigger("action-state-changed", this);
				break;
			}
		}
	};

	return UserAreaController;

});<commit_msg>Fixing bug in which unselecting an action and going back to the player showed previously selected action<commit_after>define(["Emitter"], function(Emitter) {
	"use strict";

	//TODO REFACTOR, invert control -> create cell array: cell[x][y] = {hasPlayer, hasBall, isPlayerSelected, isPosibility, isSelectedPosibility}

	var UserAreaController = function() {
		this.stateHelper = null;
		this.modifiedState = {};

		this.selectedPlayer = "";
		this.isPlayerInSelectActionState = false;

		this.seletecActions = {};
		this.cellChosen = {};
	};

	Emitter.mixInto(UserAreaController);

	UserAreaController.prototype.loadStaticContext = function() {
		this.trigger("load-static-state");
	};

	UserAreaController.prototype.loadState = function(stateHelper, isInitial) {
		this.stateHelper = stateHelper;

		this.trigger("load-state", this);
	};

	UserAreaController.prototype.cellClicked = function(x, y) {
		console.log("CEll {x: " + x + ", y: " + y + "} clicked");

		if (this.isPlayerInSelectActionState) {
			setChosenCell.call(this, x, y);
		} else {
			this.trigger("player-unselected", this);
			this.selectedPlayer = this.stateHelper.getPlayerIn(x, y);
			if (this.selectedPlayer) {
				this.trigger("player-selected", this);
			}
		}
	};

	UserAreaController.prototype.actionClicked = function(action) {
		console.log(this.selectedPlayer + " selected " + action);
		this.seletecActions[this.selectedPlayer] = action;

		if (action !== "" && action !== "Card" && action !== "Shoot") {
			this.isPlayerInSelectActionState = true;
			this.trigger("action-clicked", this);
		} else {
			delete this.cellChosen[this.selectedPlayer];
			this.isPlayerInSelectActionState = false;
		}
		this.trigger("action-state-changed", this);
	};

	UserAreaController.prototype.getDimensions = function() {
		return this.stateHelper.getDimensions();
	};

	UserAreaController.prototype.getUserPlayerPositions = function() {
		return this.stateHelper.getUserPlayerPositions();
	};

	UserAreaController.prototype.getRivalPlayerPositions = function() {
		return this.stateHelper.getRivalPlayerPositions();
	};

	UserAreaController.prototype.getSelectedPlayer = function() {
		return this.selectedPlayer;
	};

	UserAreaController.prototype.getPlayerImage = function() {
		return (this.stateHelper) ? this.stateHelper.getPlayerImage(this.selectedPlayer) : "";
	};

	UserAreaController.prototype.getPlayerStats = function() {
		return this.stateHelper.getPlayerStats(this.selectedPlayer);
	};

	UserAreaController.prototype.getPlayerActions = function() {
		return this.stateHelper.getPlayerActions(this.selectedPlayer);
	};

	UserAreaController.prototype.getSelectedAction = function() {
		return (this.seletecActions[this.selectedPlayer]) ? this.seletecActions[this.selectedPlayer] : "";
	};

	UserAreaController.prototype.getTeamScores = function() {
		return this.stateHelper.getTeamScores();
	};

	UserAreaController.prototype.getSelectedPlayerPosition = function() {
		return this.stateHelper.getPlayerPosition(this.selectedPlayer);
	};

	UserAreaController.prototype.getActionPosibilities = function() {
		var action = this.seletecActions[this.selectedPlayer];
		this.actionPosibilities = this.stateHelper["get" + action + "Posibilities"](this.selectedPlayer);
		return this.actionPosibilities;
	};

	UserAreaController.prototype.getSelectActionState = function() {
		return this.isPlayerInSelectActionState;
	};

	UserAreaController.prototype.getSelectedActionPosition = function() {
		return (this.cellChosen[this.selectedPlayer]) ? this.cellChosen[this.selectedPlayer] : null;
	};

	function setChosenCell(x, y) {
		for (var i = 0, len = this.actionPosibilities.length; i < len; i++) {
			if (this.actionPosibilities[i].x === x && this.actionPosibilities[i].y === y) {
				this.cellChosen[this.selectedPlayer] = {"x": x, "y": y};
				this.isPlayerInSelectActionState = false;
				this.trigger("action-state-changed", this);
				break;
			}
		}
	};

	return UserAreaController;

});<|endoftext|>