<commit_before>/*--------------------------------------------------------
 * Copyright (c) 2011, The Dojo Foundation
 * This software is distributed under the "Simplified BSD license",
 * the text of which is available at http://www.winktoolkit.org/licence.txt
 * or see the "license.txt" file for more details.
 *--------------------------------------------------------*/

/**
 * @fileOverview Implements the window component that captures resize and scroll events and warns listeners of changes.
 * It Handles these properties: screenWidth, screenHeight, fullWidth, fullHeight, width, height, orientation
 *
 * @author Sylvain LALANDE
 */

/**
 * Raised when window is resized
 *
 * @name wink.ux.window#/window/events/resize
 * @event
 * @param {object} param The parameters object
 * @param {integer} param.height The height of the visible area
 * @param {integer} param.width The width of the visible area
 * @param {string} param.orientation The orientation of the window ("horizontal" or "vertical")
 */

/**
 * Raised when orientation changed
 *
 * @name wink.ux.window#/window/events/orientationchange
 * @event
 * @param {object} param The parameters object
 * @param {integer} param.height The height of the visible area
 * @param {integer} param.width The width of the visible area
 * @param {string} param.orientation The orientation of the window ("horizontal" or "vertical")
 */

define(['../../../_amd/core'], function(wink)
{
	/**
	 * @namespace Implements the window component that captures resize and scroll events and warns listeners of changes.
	 * It Handles these properties: screenWidth, screenHeight, fullWidth, fullHeight, width, height, orientation
	 *
	 * @example
	 *
	 * var handleOrientation = function(properties)
	 * {
	 *   alert("Orientation: " + properties.orientation);
	 * };
	 * wink.subscribe('/window/events/orientationchange', { context: window, method: 'handleOrientation' });
	 *
	 * @compatibility Iphone OS2, Iphone OS3, Iphone OS4, Android 1.1, Android 1.5, Android 2.1, Android 2.2, Android 2.3, Android 3.0, Android 3.1, Android 4.0, BlackBerry 6, BlackBerry 7, Bada 1.0, Windows Phone 7.5
	 *
	 * @see Test page
	 */
	wink.ux.window =
	{
		/**
		 * The height of the visible area
		 *
		 * @property height
		 * @type integer
		 */
		height: null,

		/**
		 * The width of the visible area
		 *
		 * @property width
		 * @type integer
		 */
		width: null,

		/**
		 * The height of the content
		 *
		 * @property fullHeight
		 * @type integer
		 */
		fullHeight: null,

		/**
		 * The width of the content
		 *
		 * @property fullWidth
		 * @type integer
		 */
		fullWidth: null,

		/**
		 * The height of the screen
		 *
		 * @property screenHeight
		 * @type integer
		 */
		screenHeight: screen.height,

		/**
		 * The width of the screen
		 *
		 * @property screenHeight
		 * @type integer
		 */
		screenWidth: screen.width,

		/**
		 * The orientation of the window ("horizontal" or "vertical")
		 *
		 * @property orientation
		 * @type string
		 */
		orientation: null,

		/**
		 * @private
		 */
		_i: null,
		/**
		 * @private
		 */
		_V: "vertical",
		/**
		 * @private
		 */
		_H: "horizontal",

		/**
		 * Initialize the component
		 */
		_init: function()
		{
			var h = wink.bind(this._updateData, this);

			if ( "onorientationchange" in window )
			{
				window.addEventListener("orientationchange", h, true);
			} else
			{
				window.addEventListener("resize", h, true);
			}

			if ( wink.ua.isAndroid )
			{
				scrollTo(0, 1, 0);
				this._i = setInterval(h, 1000);
			} else
			{
				window.addEventListener("scroll", h, true);
			}

			h();
		},

		/**
		 * Watch for changes
		 */
		_updateData: function()
		{
			var w = window.innerWidth;
			var h = window.innerHeight;

			var b = false;

			if ( (this.width+2 < w || this.width-2 > w) || (this.height+2 < h || this.height-2 > h ) )
			{
				b = true;
			}

			this._updateSize();
			this._updateOrientation();

			if ( b )
			{
				wink.publish("/window/events/resize", {height: h, width: w, orientation: this.orientation});
			}
		},

		/**
		 * Update the window size
		 */
		_updateSize: function()
		{
			this.height = window.innerHeight;
			this.width 	= window.innerWidth;

			try
			{
				this.fullHeight = document.body.scrollHeight;
				this.fullWidth = document.body.scrollWidth;
			} catch(e)
			{
				// document.body does not exist
			}
		},

		/**
		 * Update the orientation
		 */
		_updateOrientation: function()
		{
			var o;

			if ( wink.isSet(window.orientation) && wink.ua.isIOS )
			{
				if ( Math.abs(window.orientation) == 90 )
				{
					o = this._H;
				} else
				{
					o = this._V;
				}
			} else
			{
				if ( this.width > this.height )
				{
					o = this._H;
				} else
				{
					o = this._V;
				}
			}

			if ( o != this.orientation )
			{
				this.orientation = o;
				wink.publish("/window/events/orientationchange", {height: this.height, width: this.width, orientation: o});
			}
		}
	};

	window.addEventListener("DOMContentLoaded", function(){wink.ux.window._init();}, false);

	/**
	 * @deprecated
	 * @since 1.3.0
	 */
	wink.ux.Window = function()
	{
		wink.log('[Deprecated] use wink.ux.window instead');

		/**
		 * @deprecated
		 * @since 1.3.0
		 */
		this.getProperties = function()
		{
			wink.log('[Deprecated] use wink.ux.window properties instead');

			var p =
			{
				screenWidth: wink.ux.window.screenWidth,
				screenHeight: wink.ux.window.screenHeight,
				width: wink.ux.window.width,
				height:  wink.ux.window.height,
				orientation:  wink.ux.window.orientation
			};

			return p;
		};
	};

	return wink.ux.window;
});<commit_msg>Removed deprecated wink.ux.window<commit_after>/*--------------------------------------------------------
 * Copyright (c) 2011, The Dojo Foundation
 * This software is distributed under the "Simplified BSD license",
 * the text of which is available at http://www.winktoolkit.org/licence.txt
 * or see the "license.txt" file for more details.
 *--------------------------------------------------------*/

/**
 * @fileOverview Implements the window component that captures resize and scroll events and warns listeners of changes.
 * It Handles these properties: screenWidth, screenHeight, fullWidth, fullHeight, width, height, orientation
 *
 * @author Sylvain LALANDE
 */

/**
 * Raised when window is resized
 *
 * @name wink.ux.window#/window/events/resize
 * @event
 * @param {object} param The parameters object
 * @param {integer} param.height The height of the visible area
 * @param {integer} param.width The width of the visible area
 * @param {string} param.orientation The orientation of the window ("horizontal" or "vertical")
 */

/**
 * Raised when orientation changed
 *
 * @name wink.ux.window#/window/events/orientationchange
 * @event
 * @param {object} param The parameters object
 * @param {integer} param.height The height of the visible area
 * @param {integer} param.width The width of the visible area
 * @param {string} param.orientation The orientation of the window ("horizontal" or "vertical")
 */

define(['../../../_amd/core'], function(wink)
{
	/**
	 * @namespace Implements the window component that captures resize and scroll events and warns listeners of changes.
	 * It Handles these properties: screenWidth, screenHeight, fullWidth, fullHeight, width, height, orientation
	 *
	 * @example
	 *
	 * var handleOrientation = function(properties)
	 * {
	 *   alert("Orientation: " + properties.orientation);
	 * };
	 * wink.subscribe('/window/events/orientationchange', { context: window, method: 'handleOrientation' });
	 *
	 * @compatibility Iphone OS2, Iphone OS3, Iphone OS4, Android 1.1, Android 1.5, Android 2.1, Android 2.2, Android 2.3, Android 3.0, Android 3.1, Android 4.0, BlackBerry 6, BlackBerry 7, Bada 1.0, Windows Phone 7.5
	 *
	 * @see Test page
	 */
	wink.ux.window =
	{
		/**
		 * The height of the visible area
		 *
		 * @property height
		 * @type integer
		 */
		height: null,

		/**
		 * The width of the visible area
		 *
		 * @property width
		 * @type integer
		 */
		width: null,

		/**
		 * The height of the content
		 *
		 * @property fullHeight
		 * @type integer
		 */
		fullHeight: null,

		/**
		 * The width of the content
		 *
		 * @property fullWidth
		 * @type integer
		 */
		fullWidth: null,

		/**
		 * The height of the screen
		 *
		 * @property screenHeight
		 * @type integer
		 */
		screenHeight: screen.height,

		/**
		 * The width of the screen
		 *
		 * @property screenHeight
		 * @type integer
		 */
		screenWidth: screen.width,

		/**
		 * The orientation of the window ("horizontal" or "vertical")
		 *
		 * @property orientation
		 * @type string
		 */
		orientation: null,

		/**
		 * @private
		 */
		_i: null,
		/**
		 * @private
		 */
		_V: "vertical",
		/**
		 * @private
		 */
		_H: "horizontal",

		/**
		 * Initialize the component
		 */
		_init: function()
		{
			var h = wink.bind(this._updateData, this);

			if ( "onorientationchange" in window )
			{
				window.addEventListener("orientationchange", h, true);
			} else
			{
				window.addEventListener("resize", h, true);
			}

			if ( wink.ua.isAndroid )
			{
				scrollTo(0, 1, 0);
				this._i = setInterval(h, 1000);
			} else
			{
				window.addEventListener("scroll", h, true);
			}

			h();
		},

		/**
		 * Watch for changes
		 */
		_updateData: function()
		{
			var w = window.innerWidth;
			var h = window.innerHeight;

			var b = false;

			if ( (this.width+2 < w || this.width-2 > w) || (this.height+2 < h || this.height-2 > h ) )
			{
				b = true;
			}

			this._updateSize();
			this._updateOrientation();

			if ( b )
			{
				wink.publish("/window/events/resize", {height: h, width: w, orientation: this.orientation});
			}
		},

		/**
		 * Update the window size
		 */
		_updateSize: function()
		{
			this.height = window.innerHeight;
			this.width 	= window.innerWidth;

			try
			{
				this.fullHeight = document.body.scrollHeight;
				this.fullWidth = document.body.scrollWidth;
			} catch(e)
			{
				// document.body does not exist
			}
		},

		/**
		 * Update the orientation
		 */
		_updateOrientation: function()
		{
			var o;

			if ( wink.isSet(window.orientation) && wink.ua.isIOS )
			{
				if ( Math.abs(window.orientation) == 90 )
				{
					o = this._H;
				} else
				{
					o = this._V;
				}
			} else
			{
				if ( this.width > this.height )
				{
					o = this._H;
				} else
				{
					o = this._V;
				}
			}

			if ( o != this.orientation )
			{
				this.orientation = o;
				wink.publish("/window/events/orientationchange", {height: this.height, width: this.width, orientation: o});
			}
		}
	};

	window.addEventListener("DOMContentLoaded", function(){wink.ux.window._init();}, false);

	return wink.ux.window;
});<|endoftext|>


<commit_before>suite("d3.layer", function() {
	"use strict";

	suite("constructor", function() {
		test("returns a reference to the selection", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.equal(inst, base);
		});
		test("extends the selection with a `draw` method", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.typeOf(inst.draw, "function");
		});
		test("extends the selection with an `on` method", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.typeOf(inst.on, "function");
		});
		test("extends the selection with an `off` method", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.typeOf(inst.off, "function");
		});
	});

	suite('#draw', function() {
		setup(function() {
			var dataBind = this.dataBind = sinon.spy(function(data) {
				var updating = this.data(data, function(d) { return d; });
				sinon.spy(updating, "enter");
				sinon.spy(updating, "transition");
				var exitSelection = updating.exit.bind(updating);
				sinon.stub(updating, "exit", function() {
					var exiting = exitSelection();
					sinon.spy(exiting, "transition");
					return exiting;
				});
				return updating;
			});
			var insert = this.insert = sinon.spy(function() {
				var entering = this.insert("g");
				sinon.spy(entering, "transition");
				return entering;
			});
			var base = this.base = d3.select("#test");

			this.layer = base.layer({
				dataBind: dataBind,
				insert: insert
			});
		});
		test("throws an error when `dataBind` does not return a selection", function() {
			var layer = this.base.layer({
				dataBind: function() {
					return {};
				},
				insert: this.insert
			});
			var draw = function() {
				layer.draw([]);
			};
			assert.throws(draw);
		});

		test("throws an error when `insert` does not return a selection", function() {
			var layer = this.base.layer({
				dataBind: this.dataBind,
				insert: function() { return {}; }
			});
			var draw = function() {
				layer.draw([]);
			};
			assert.throws(draw);
		});
		test("invokes the provided `dataBind` method exactly once", function() {
			assert.equal(this.dataBind.callCount, 0);
			this.layer.draw([]);
			assert.equal(this.dataBind.callCount, 1);
		});
		test("invokes the provided `dataBind` method in the context of the layer's selection", function() {
			assert.equal(this.dataBind.callCount, 0);
			this.layer.draw([]);
			assert(this.dataBind.calledOn(this.base));
		});
		test("invokes the provided `dataBind` method with the specified data", function() {
			var data = [];
			assert.equal(this.dataBind.callCount, 0);
			this.layer.draw(data);
			assert.equal(this.dataBind.args[0][0], data);
		});
		test("invokes the provided `insert` method exactly once", function() {
			assert.equal(this.insert.callCount, 0);
			this.layer.draw([]);
			assert.equal(this.insert.callCount, 1);
		});
		test("invokes the provided `insert` method in the context of the layer's bound 'enter' selection", function() {
			this.layer.draw([]);
			assert(this.insert.calledOn(this.dataBind.returnValues[0].enter.returnValues[0]));
		});

		suite("event triggering", function() {
			setup(function() {
				this.onEnter1 = sinon.spy();
				this.onUpdate1 = sinon.spy();
				this.onMerge1 = sinon.spy();
				this.onExit1 = sinon.spy();
				this.onEnterTrans1 = sinon.spy();
				this.onUpdateTrans1 = sinon.spy();
				this.onMergeTrans1 = sinon.spy();
				this.onExitTrans1 = sinon.spy();
			});

			suite("bound in constructor", function() {
				setup(function() {
					this.layer = this.base.layer({
						dataBind: this.dataBind,
						insert: this.insert,
						events: {
							"enter": this.onEnter1,
							"update": this.onUpdate1,
							"merge": this.onMerge1,
							"exit": this.onExit1,
							"enter:transition": this.onEnterTrans1,
							"update:transition": this.onUpdateTrans1,
							"merge:transition": this.onMergeTrans1,
							"exit:transition": this.onExitTrans1
						}
					});
				});
				test("invokes all event handlers exactly once", function() {
					this.layer.draw([]);

					assert.equal(this.onEnter1.callCount, 1);
					assert.equal(this.onUpdate1.callCount, 1);
					assert.equal(this.onMerge1.callCount, 1);
					assert.equal(this.onExit1.callCount, 1);
					assert.equal(this.onEnterTrans1.callCount, 1);
					assert.equal(this.onUpdateTrans1.callCount, 1);
					assert.equal(this.onMergeTrans1.callCount, 1);
					assert.equal(this.onExitTrans1.callCount, 1);
				});
				test("invokes all event handlers in the context of the corresponding 'lifecycle selection'", function() {
					var entering, updating, exiting;
					this.layer.draw([]);

					// Alias lifecycle selections
					entering = this.insert.returnValues[0];
					updating = this.dataBind.returnValues[0];
					exiting = updating.exit.returnValues[0];

					assert(this.onEnter1.calledOn(entering));
					assert(this.onUpdate1.calledOn(updating));
					assert(this.onMerge1.calledOn(updating));
					assert(this.onExit1.calledOn(exiting));
					assert(this.onEnterTrans1.calledOn(entering.transition.returnValues[0]));
					assert(this.onUpdateTrans1.calledOn(updating.transition.returnValues[0]));
					assert(this.onMergeTrans1.calledOn(updating.transition.returnValues[1]));
					assert(this.onExitTrans1.calledOn(exiting.transition.returnValues[0]));
				});

				test("invokes event handlers with the correct selection", function() {
					var layer = this.base.append("g").layer({
						insert: function() {
							return this.append("g");
						},
						dataBind: function(data) {
							return this.selectAll("g").data(data, function(d) { return d; });
						}
					});
					// Wrap each assertion in a spy so we can ensure that each actually
					// runs.
					var updateSpy = sinon.spy(function() {
						assert.sameMembers(this.data(), [3, 4]);
					});
					var enterSpy = sinon.spy(function() {
						assert.sameMembers(this.data(), [5, 6]);
					});
					var mergeSpy = sinon.spy(function() {
						assert.sameMembers(this.data(), [3, 4, 5, 6]);
					});
					var exitSpy = sinon.spy(function() {
						assert.sameMembers(this.data(), [1, 2]);
					});
					layer.draw([1, 2, 3, 4]);

					// Bind the spies
					layer.on("update", updateSpy);
					layer.on("enter", enterSpy);
					layer.on("merge", mergeSpy);
					layer.on("exit", exitSpy);

					layer.draw([3, 4, 5, 6]);

					assert.equal(updateSpy.callCount, 1);
					assert.equal(enterSpy.callCount, 1);
					assert.equal(mergeSpy.callCount, 1);
					assert.equal(exitSpy.callCount, 1);

					layer.remove();
				});

			});

			suite("bound with `on`", function() {
				setup(function() {

					this.onUpdate2 = sinon.spy();
					this.onMerge2 = sinon.spy();
					this.onExit2 = sinon.spy();
					this.onExit3 = sinon.spy();
					this.onEnterTrans2 = sinon.spy();
					this.onEnterTrans3 = sinon.spy();
					this.onUpdateTrans2 = sinon.spy();
					this.onMergeTrans2 = sinon.spy();
					this.onMergeTrans3 = sinon.spy();

					this.layer.on("enter", this.onEnter1);
					this.layer.on("update", this.onUpdate1);
					this.layer.on("update", this.onUpdate2);
					this.layer.on("merge", this.onMerge1);
					this.layer.on("merge", this.onMerge2);
					this.layer.on("exit", this.onExit1);
					this.layer.on("exit", this.onExit2);
					this.layer.on("exit", this.onExit3);
					this.layer.on("enter:transition", this.onEnterTrans1);
					this.layer.on("enter:transition", this.onEnterTrans2);
					this.layer.on("enter:transition", this.onEnterTrans3);
					this.layer.on("update:transition", this.onUpdateTrans1);
					this.layer.on("update:transition", this.onUpdateTrans2);
					this.layer.on("merge:transition", this.onMergeTrans1);
					this.layer.on("merge:transition", this.onMergeTrans2);
					this.layer.on("merge:transition", this.onMergeTrans3);
					this.layer.on("exit:transition", this.onExitTrans1);
				});
				test("invokes all event handlers exactly once", function() {
					this.layer.draw([]);

					assert.equal(this.onEnter1.callCount, 1);
					assert.equal(this.onUpdate1.callCount, 1);
					assert.equal(this.onUpdate2.callCount, 1);
					assert.equal(this.onMerge1.callCount, 1);
					assert.equal(this.onMerge2.callCount, 1);
					assert.equal(this.onExit1.callCount, 1);
					assert.equal(this.onExit2.callCount, 1);
					assert.equal(this.onExit3.callCount, 1);
					assert.equal(this.onEnterTrans1.callCount, 1);
					assert.equal(this.onEnterTrans2.callCount, 1);
					assert.equal(this.onEnterTrans3.callCount, 1);
					assert.equal(this.onUpdateTrans1.callCount, 1);
					assert.equal(this.onUpdateTrans2.callCount, 1);
					assert.equal(this.onMergeTrans1.callCount, 1);
					assert.equal(this.onMergeTrans2.callCount, 1);
					assert.equal(this.onMergeTrans3.callCount, 1);
					assert.equal(this.onExitTrans1.callCount, 1);
				});
				test("invokes all event handlers in the context of the corresponding 'lifecycle selection'", function() {
					var entering, updating, exiting;
					this.layer.draw([]);

					// Alias lifecycle selections
					entering = this.insert.returnValues[0];
					updating = this.dataBind.returnValues[0];
					exiting = updating.exit.returnValues[0];

					assert(this.onEnter1.calledOn(entering));
					assert(this.onUpdate1.calledOn(updating));
					assert(this.onMerge1.calledOn(updating));
					assert(this.onExit1.calledOn(exiting));
					assert(this.onEnterTrans1.calledOn(entering.transition.returnValues[0]));
					assert(this.onUpdateTrans1.calledOn(updating.transition.returnValues[0]));
					assert(this.onMergeTrans1.calledOn(updating.transition.returnValues[1]));
					assert(this.onExitTrans1.calledOn(exiting.transition.returnValues[0]));
				});

			});
		});
	});
});
<commit_msg>Reorganize tests<commit_after>suite("d3.layer", function() {
	"use strict";

	suite("constructor", function() {
		test("returns a reference to the selection", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.equal(inst, base);
		});
		test("extends the selection with a `draw` method", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.typeOf(inst.draw, "function");
		});
		test("extends the selection with an `on` method", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.typeOf(inst.on, "function");
		});
		test("extends the selection with an `off` method", function() {
			var base = d3.select("#test");
			var inst = base.layer({});
			assert.typeOf(inst.off, "function");
		});
	});

	suite('#draw', function() {
		setup(function() {
			var dataBind = this.dataBind = sinon.spy(function(data) {
				var updating = this.data(data, function(d) { return d; });
				sinon.spy(updating, "enter");
				sinon.spy(updating, "transition");
				var exitSelection = updating.exit.bind(updating);
				sinon.stub(updating, "exit", function() {
					var exiting = exitSelection();
					sinon.spy(exiting, "transition");
					return exiting;
				});
				return updating;
			});
			var insert = this.insert = sinon.spy(function() {
				var entering = this.insert("g");
				sinon.spy(entering, "transition");
				return entering;
			});
			var base = this.base = d3.select("#test");

			this.layer = base.layer({
				dataBind: dataBind,
				insert: insert
			});
		});
		test("throws an error when `dataBind` does not return a selection", function() {
			var layer = this.base.layer({
				dataBind: function() {
					return {};
				},
				insert: this.insert
			});
			var draw = function() {
				layer.draw([]);
			};
			assert.throws(draw);
		});

		test("throws an error when `insert` does not return a selection", function() {
			var layer = this.base.layer({
				dataBind: this.dataBind,
				insert: function() { return {}; }
			});
			var draw = function() {
				layer.draw([]);
			};
			assert.throws(draw);
		});
		test("invokes the provided `dataBind` method exactly once", function() {
			assert.equal(this.dataBind.callCount, 0);
			this.layer.draw([]);
			assert.equal(this.dataBind.callCount, 1);
		});
		test("invokes the provided `dataBind` method in the context of the layer's selection", function() {
			assert.equal(this.dataBind.callCount, 0);
			this.layer.draw([]);
			assert(this.dataBind.calledOn(this.base));
		});
		test("invokes the provided `dataBind` method with the specified data", function() {
			var data = [];
			assert.equal(this.dataBind.callCount, 0);
			this.layer.draw(data);
			assert.equal(this.dataBind.args[0][0], data);
		});
		test("invokes the provided `insert` method exactly once", function() {
			assert.equal(this.insert.callCount, 0);
			this.layer.draw([]);
			assert.equal(this.insert.callCount, 1);
		});
		test("invokes the provided `insert` method in the context of the layer's bound 'enter' selection", function() {
			this.layer.draw([]);
			assert(this.insert.calledOn(this.dataBind.returnValues[0].enter.returnValues[0]));
		});

		suite("event triggering", function() {
			setup(function() {
				this.onEnter1 = sinon.spy();
				this.onUpdate1 = sinon.spy();
				this.onMerge1 = sinon.spy();
				this.onExit1 = sinon.spy();
				this.onEnterTrans1 = sinon.spy();
				this.onUpdateTrans1 = sinon.spy();
				this.onMergeTrans1 = sinon.spy();
				this.onExitTrans1 = sinon.spy();
			});

			test("invokes event handlers with the correct selection", function() {
				var layer = this.base.append("g").layer({
					insert: function() {
						return this.append("g");
					},
					dataBind: function(data) {
						return this.selectAll("g").data(data, function(d) { return d; });
					}
				});
				// Wrap each assertion in a spy so we can ensure that each actually
				// runs.
				var updateSpy = sinon.spy(function() {
					assert.sameMembers(this.data(), [3, 4]);
				});
				var enterSpy = sinon.spy(function() {
					assert.sameMembers(this.data(), [5, 6]);
				});
				var mergeSpy = sinon.spy(function() {
					assert.sameMembers(this.data(), [3, 4, 5, 6]);
				});
				var exitSpy = sinon.spy(function() {
					assert.sameMembers(this.data(), [1, 2]);
				});
				layer.draw([1, 2, 3, 4]);

				// Bind the spies
				layer.on("update", updateSpy);
				layer.on("enter", enterSpy);
				layer.on("merge", mergeSpy);
				layer.on("exit", exitSpy);

				layer.draw([3, 4, 5, 6]);

				assert.equal(updateSpy.callCount, 1);
				assert.equal(enterSpy.callCount, 1);
				assert.equal(mergeSpy.callCount, 1);
				assert.equal(exitSpy.callCount, 1);

				layer.remove();
			});

			suite("bound in constructor", function() {
				setup(function() {
					this.layer = this.base.layer({
						dataBind: this.dataBind,
						insert: this.insert,
						events: {
							"enter": this.onEnter1,
							"update": this.onUpdate1,
							"merge": this.onMerge1,
							"exit": this.onExit1,
							"enter:transition": this.onEnterTrans1,
							"update:transition": this.onUpdateTrans1,
							"merge:transition": this.onMergeTrans1,
							"exit:transition": this.onExitTrans1
						}
					});
				});
				test("invokes all event handlers exactly once", function() {
					this.layer.draw([]);

					assert.equal(this.onEnter1.callCount, 1);
					assert.equal(this.onUpdate1.callCount, 1);
					assert.equal(this.onMerge1.callCount, 1);
					assert.equal(this.onExit1.callCount, 1);
					assert.equal(this.onEnterTrans1.callCount, 1);
					assert.equal(this.onUpdateTrans1.callCount, 1);
					assert.equal(this.onMergeTrans1.callCount, 1);
					assert.equal(this.onExitTrans1.callCount, 1);
				});
				test("invokes all event handlers in the context of the corresponding 'lifecycle selection'", function() {
					var entering, updating, exiting;
					this.layer.draw([]);

					// Alias lifecycle selections
					entering = this.insert.returnValues[0];
					updating = this.dataBind.returnValues[0];
					exiting = updating.exit.returnValues[0];

					assert(this.onEnter1.calledOn(entering));
					assert(this.onUpdate1.calledOn(updating));
					assert(this.onMerge1.calledOn(updating));
					assert(this.onExit1.calledOn(exiting));
					assert(this.onEnterTrans1.calledOn(entering.transition.returnValues[0]));
					assert(this.onUpdateTrans1.calledOn(updating.transition.returnValues[0]));
					assert(this.onMergeTrans1.calledOn(updating.transition.returnValues[1]));
					assert(this.onExitTrans1.calledOn(exiting.transition.returnValues[0]));
				});

			});

			suite("bound with `on`", function() {
				setup(function() {

					this.onUpdate2 = sinon.spy();
					this.onMerge2 = sinon.spy();
					this.onExit2 = sinon.spy();
					this.onExit3 = sinon.spy();
					this.onEnterTrans2 = sinon.spy();
					this.onEnterTrans3 = sinon.spy();
					this.onUpdateTrans2 = sinon.spy();
					this.onMergeTrans2 = sinon.spy();
					this.onMergeTrans3 = sinon.spy();

					this.layer.on("enter", this.onEnter1);
					this.layer.on("update", this.onUpdate1);
					this.layer.on("update", this.onUpdate2);
					this.layer.on("merge", this.onMerge1);
					this.layer.on("merge", this.onMerge2);
					this.layer.on("exit", this.onExit1);
					this.layer.on("exit", this.onExit2);
					this.layer.on("exit", this.onExit3);
					this.layer.on("enter:transition", this.onEnterTrans1);
					this.layer.on("enter:transition", this.onEnterTrans2);
					this.layer.on("enter:transition", this.onEnterTrans3);
					this.layer.on("update:transition", this.onUpdateTrans1);
					this.layer.on("update:transition", this.onUpdateTrans2);
					this.layer.on("merge:transition", this.onMergeTrans1);
					this.layer.on("merge:transition", this.onMergeTrans2);
					this.layer.on("merge:transition", this.onMergeTrans3);
					this.layer.on("exit:transition", this.onExitTrans1);
				});
				test("invokes all event handlers exactly once", function() {
					this.layer.draw([]);

					assert.equal(this.onEnter1.callCount, 1);
					assert.equal(this.onUpdate1.callCount, 1);
					assert.equal(this.onUpdate2.callCount, 1);
					assert.equal(this.onMerge1.callCount, 1);
					assert.equal(this.onMerge2.callCount, 1);
					assert.equal(this.onExit1.callCount, 1);
					assert.equal(this.onExit2.callCount, 1);
					assert.equal(this.onExit3.callCount, 1);
					assert.equal(this.onEnterTrans1.callCount, 1);
					assert.equal(this.onEnterTrans2.callCount, 1);
					assert.equal(this.onEnterTrans3.callCount, 1);
					assert.equal(this.onUpdateTrans1.callCount, 1);
					assert.equal(this.onUpdateTrans2.callCount, 1);
					assert.equal(this.onMergeTrans1.callCount, 1);
					assert.equal(this.onMergeTrans2.callCount, 1);
					assert.equal(this.onMergeTrans3.callCount, 1);
					assert.equal(this.onExitTrans1.callCount, 1);
				});
				test("invokes all event handlers in the context of the corresponding 'lifecycle selection'", function() {
					var entering, updating, exiting;
					this.layer.draw([]);

					// Alias lifecycle selections
					entering = this.insert.returnValues[0];
					updating = this.dataBind.returnValues[0];
					exiting = updating.exit.returnValues[0];

					assert(this.onEnter1.calledOn(entering));
					assert(this.onUpdate1.calledOn(updating));
					assert(this.onMerge1.calledOn(updating));
					assert(this.onExit1.calledOn(exiting));
					assert(this.onEnterTrans1.calledOn(entering.transition.returnValues[0]));
					assert(this.onUpdateTrans1.calledOn(updating.transition.returnValues[0]));
					assert(this.onMergeTrans1.calledOn(updating.transition.returnValues[1]));
					assert(this.onExitTrans1.calledOn(exiting.transition.returnValues[0]));
				});

			});
		});
	});
});
<|endoftext|>


<commit_before>if( typeof tilelogic === 'undefined' ) {
  var tilelogic = require('..')
}

describe('tilelogic', function(){

  it('x values convert to longitude', function(){
    expect( tilelogic.tile2lng(3368, 14) ).toBe(-105.99609375);
  })

  it('y values convert to latitude', function(){
    expect( tilelogic.tile2lat(6288, 14) ).toBe(38.54816542304658);
  })

})<commit_msg>use 6 decimal places in tests to prevent rounding issues form breaking tests<commit_after>if( typeof tilelogic === 'undefined' ) {
  var tilelogic = require('..')
}

describe('tilelogic', function(){

  it('x values convert to longitude', function(){
    expect( tilelogic.tile2lng(3368, 14).toFixed(6) ).toBe((-105.996094).toFixed(6));
  })

  it('y values convert to latitude', function(){
    expect( tilelogic.tile2lat(6288, 14).toFixed(6) ).toBe((38.548165).toFixed(6));
  })

})<|endoftext|>


<commit_before>var test = require('tap').test,
    wolfram = require('../')

test('valid response', function(t) {
  var client = wolfram.createClient(process.env.WOLFRAM_APPID)

  t.test("integrate 2x", function(t) {
    client.query("integrate 2x", function(err, result) {
      t.notOk(err, "err should be null")
      t.type(result, "object")
      t.ok(result.length)
      t.equal(result.length, 2, "result length should be 2")
      t.equal(result[0].primary, true, "first pod should be primary")
      t.equal(result[0].subpods[0].value, ' integral 2 x dx = x^2+constant', 'result should be constant')
      t.ok(result[0].subpods[0].image, "result should have an image representation")
      t.end()
    })
  })

  t.test("1+1", function(t) {
    client.query("1+1", function(err, result) {
      t.notOk(err, "err should be null")
      t.type(result, "object")
      t.ok(result.length)
      t.equal(result.length, 6)
      t.equal(result[1].primary, true)
      t.equal(result[1].subpods[0].value, '2')
      t.end()
    })
  })
})
<commit_msg>Commit<commit_after>var test = require('tap').test,
    wolfram = require('../')

test('valid response', function(t) {
  var client = wolfram.createClient(process.env.WOLFRAM_APPID)

  t.test("integrate 2x", function(t) {
    client.query("integrate 2x", function(err, result) {
      t.notOk(err, "err should be null")
      t.type(result, "object")
      t.ok(result.length)
      t.equal(result.length, 2, "result length should be 2")
      t.equal(result[0].primary, true, "first pod should be primary")
      t.equal(result[0].subpods[0].value, ' integral 2 x dx = x^2+constant', 'result should be constant')
      t.ok(result[0].subpods[0].image, "result should have an image representation")
      t.ok(result[0].title, "result should have a title of Indefinite integral")
      t.end()
    })
  })

  t.test("1+1", function(t) {
    client.query("1+1", function(err, result) {
      t.notOk(err, "err should be null")
      t.type(result, "object")
      t.ok(result.length)
      t.equal(result.length, 6)
      t.equal(result[1].primary, true)
      t.equal(result[1].subpods[0].value, '2')
      t.end()
    })
  })
})
<|endoftext|>


<commit_before>var Browser = require('./Browser');

var Audio = {

    // @property {boolean} audioData - Are Audio tags available?
    audioData: false,

    // @property {boolean} webAudio - Is the WebAudio API available?
    webAudio: false,

    // @property {boolean} ogg - Can this device play ogg files?
    ogg: false,

    // @property {boolean} opus - Can this device play opus files?
    opus: false,

    // @property {boolean} mp3 - Can this device play mp3 files?
    mp3: false,

    // @property {boolean} wav - Can this device play wav files?
    wav: false,

    // Can this device play m4a files?
    // @property {boolean} m4a - True if this device can play m4a files.
    m4a: false,

    // @property {boolean} webm - Can this device play webm files?
    webm: false,

    // @property {boolean} dolby - Can this device play EC-3 Dolby Digital Plus files?
    dolby: false

};

function init ()
{
    Audio.audioData = !!(window['Audio']);

    // TODO check if AudioContext is actually implemented
    // sometimes browsers have a stub object for AudioContext
    // which will falsely report Web Audio as available
    Audio.webAudio = !!(window['AudioContext'] || window['webkitAudioContext']);

    var audioElement = document.createElement('audio');

    var result = !!audioElement.canPlayType;

    try
    {
        if (result)
        {
            if (audioElement.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''))
            {
                Audio.ogg = true;
            }

            if (audioElement.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, '') || audioElement.canPlayType('audio/opus;').replace(/^no$/, ''))
            {
                Audio.opus = true;
            }

            if (audioElement.canPlayType('audio/mpeg;').replace(/^no$/, ''))
            {
                Audio.mp3 = true;
            }

            //  Mimetypes accepted:
            //  developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
            //  bit.ly/iphoneoscodecs
            if (audioElement.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''))
            {
                Audio.wav = true;
            }

            if (audioElement.canPlayType('audio/x-m4a;') || audioElement.canPlayType('audio/aac;').replace(/^no$/, ''))
            {
                Audio.m4a = true;
            }

            if (audioElement.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''))
            {
                Audio.webm = true;
            }

            if (audioElement.canPlayType('audio/mp4;codecs="ec-3"') !== '')
            {
                if (Browser.edge)
                {
                    Audio.dolby = true;
                }
                else if (Browser.safari && Browser.safariVersion >= 9)
                {
                    if ((/Mac OS X (\d+)_(\d+)/).test(navigator.userAgent))
                    {
                        var major = parseInt(RegExp.$1, 10);
                        var minor = parseInt(RegExp.$2, 10);

                        if ((major === 10 && minor >= 11) || major > 10)
                        {
                            Audio.dolby = true;
                        }
                    }
                }
            }
        }
    }
    catch (e)
    {
        //  Nothing to do here
    }

    return Audio;
}

module.exports = init();
<commit_msg>Removed a resolved TODO<commit_after>var Browser = require('./Browser');

var Audio = {

    // @property {boolean} audioData - Are Audio tags available?
    audioData: false,

    // @property {boolean} webAudio - Is the WebAudio API available?
    webAudio: false,

    // @property {boolean} ogg - Can this device play ogg files?
    ogg: false,

    // @property {boolean} opus - Can this device play opus files?
    opus: false,

    // @property {boolean} mp3 - Can this device play mp3 files?
    mp3: false,

    // @property {boolean} wav - Can this device play wav files?
    wav: false,

    // Can this device play m4a files?
    // @property {boolean} m4a - True if this device can play m4a files.
    m4a: false,

    // @property {boolean} webm - Can this device play webm files?
    webm: false,

    // @property {boolean} dolby - Can this device play EC-3 Dolby Digital Plus files?
    dolby: false

};

function init ()
{
    Audio.audioData = !!(window['Audio']);

    Audio.webAudio = !!(window['AudioContext'] || window['webkitAudioContext']);

    var audioElement = document.createElement('audio');

    var result = !!audioElement.canPlayType;

    try
    {
        if (result)
        {
            if (audioElement.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''))
            {
                Audio.ogg = true;
            }

            if (audioElement.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, '') || audioElement.canPlayType('audio/opus;').replace(/^no$/, ''))
            {
                Audio.opus = true;
            }

            if (audioElement.canPlayType('audio/mpeg;').replace(/^no$/, ''))
            {
                Audio.mp3 = true;
            }

            //  Mimetypes accepted:
            //  developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
            //  bit.ly/iphoneoscodecs
            if (audioElement.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''))
            {
                Audio.wav = true;
            }

            if (audioElement.canPlayType('audio/x-m4a;') || audioElement.canPlayType('audio/aac;').replace(/^no$/, ''))
            {
                Audio.m4a = true;
            }

            if (audioElement.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''))
            {
                Audio.webm = true;
            }

            if (audioElement.canPlayType('audio/mp4;codecs="ec-3"') !== '')
            {
                if (Browser.edge)
                {
                    Audio.dolby = true;
                }
                else if (Browser.safari && Browser.safariVersion >= 9)
                {
                    if ((/Mac OS X (\d+)_(\d+)/).test(navigator.userAgent))
                    {
                        var major = parseInt(RegExp.$1, 10);
                        var minor = parseInt(RegExp.$2, 10);

                        if ((major === 10 && minor >= 11) || major > 10)
                        {
                            Audio.dolby = true;
                        }
                    }
                }
            }
        }
    }
    catch (e)
    {
        //  Nothing to do here
    }

    return Audio;
}

module.exports = init();
<|endoftext|>


<commit_before>'use strict';

var Switcher = /** @type Switcher */ require('./router/Switcher');
var Connect = /** @type Connect */ require('./track/Connect');
var Tracker = /** @type Tracker */ require('./Tracker');

/**
 * @class Server
 * @extends Tracker
 * */
var Server = Tracker.extend(/** @lends Server.prototype */ {

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @constructs
     * */
    constructor: function () {
        Server.Parent.apply(this, arguments);

        /**
         * @public
         * @memberOf {Server}
         * @property {Switcher}
         * */
        this.router = this._createRouter(this.params.router);
    },

    /**
     * @public
     * @memberOf {Server}
     * @method
     *
     * @returns {Function}
     * */
    getHandler: function () {

        var self = this;

        return function (req, res) {

            var date = new Date();
            var track = self._createTrack(req, res);

            res.once('finish', function () {
                track.time = new Date() - date;
                self.emit('sys:response', track);
            });

            self.emit('sys:request', track);

            self._handle(track);
        };
    },

    /**
     * @public
     * @memberOf {Tracker}
     * @method
     *
     * @param {Connect} track
     * @param {String} path
     * @param {Function} done
     * */
    resolve: function (track, path, done) {

        function resolve () {

            if ( track.sent() ) {

                return;
            }

            done.apply(this, arguments);
        }

        return Server.parent.resolve.call(this, track, path, resolve);
    },

    /**
     * @public
     * @memberOf {Server}
     * @method
     *
     * */
    route: function () {
        this.router.addRoute.apply(this.router, arguments);

        return this;
    },

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @param {Track} track
     * @param {Array<String>|String} deps
     * @param {Function} done done(bundle)
     * */
    _bundle: function (track, deps, done) {

        var date = new Date();

        function resolve (bundle) {
            this.emit('sys:bundle', {
                time: new Date() - date,
                deps: deps,
                data: bundle
            });

            done.apply(this, arguments);
        }

        Server.parent._bundle.call(this, track, deps, resolve);
    },

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @param {*} [params]
     *
     * @returns {Switcher}
     * */
    _createRouter: function (params) {

        return new Switcher(params);
    },

    /**
     * @public
     * @memberOf {Server}
     * @method
     *
     * @returns {Connect}
     * */
    _createTrack: function (req, res) {

        return new Connect(this, req, res);
    },

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @param {Connect} track
     * */
    _handle: function (track) {

        var mdata;
        var rdata;

        if ( track.sent() ) {

            return;
        }

        mdata = this._findRoute(track);

        //  по сути такой роутер может сделать send
        //  если он сделал send то он конечно понимает что он сделал
        //  такой поступок не может быть необдуманным, мы прекращаем
        //  обработку запроса
        if ( track.sent() ) {

            return;
        }

        //  однозначно нет такого маршрута
        if ( null === mdata ) {
            this.emit('sys:ematch', track);
            track.send(404);

            return;
        }

        //  возвращен массив
        if ( Array.isArray(mdata) ) {
            //  это тоже значит что нет такого роута
            this.emit('sys:ematch', track);

            //  если массив пустой, то на сервере совсем нет ни одного
            //  маршрута отвечающего по такому методу запроса
            if ( 0 === mdata.length ) {
                //  Not Implemented
                track.send(501);

                return;
            }

            //  Иначе есть такие маршруты, но для них не
            // поддерживается такой метод
            track.header('Allow', mdata.join(', '));
            //  Method Not Allowed
            track.send(405);

            return;
        }

        this.emit('sys:match', track);

        track.match = mdata.match;
        track.route = mdata.route.name;

        rdata = mdata.route.data;

        if ( Object(rdata) === rdata ) {
            rdata = rdata.unit;
        }

        this.resolve(track, rdata || track.route, function (err, res) {

            if ( 2 > arguments.length ) {
                track.send(500, err);

                return;
            }

            track.send(200, res);
        });
    },

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @param {Connect} track
     *
     * @returns {*}
     * */
    _findRoute: function (track) {

        return this.router.find(track);
    }

});

module.exports = Server;
<commit_msg>rc-dev: remove bundle emitting<commit_after>'use strict';

var Switcher = /** @type Switcher */ require('./router/Switcher');
var Connect = /** @type Connect */ require('./track/Connect');
var Tracker = /** @type Tracker */ require('./Tracker');

/**
 * @class Server
 * @extends Tracker
 * */
var Server = Tracker.extend(/** @lends Server.prototype */ {

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @constructs
     * */
    constructor: function () {
        Server.Parent.apply(this, arguments);

        /**
         * @public
         * @memberOf {Server}
         * @property {Switcher}
         * */
        this.router = this._createRouter(this.params.router);
    },

    /**
     * @public
     * @memberOf {Server}
     * @method
     *
     * @returns {Function}
     * */
    getHandler: function () {

        var self = this;

        return function (req, res) {

            var date = new Date();
            var track = self._createTrack(req, res);

            res.once('finish', function () {
                track.time = new Date() - date;
                self.emit('sys:response', track);
            });

            self.emit('sys:request', track);

            self._handle(track);
        };
    },

    /**
     * @public
     * @memberOf {Tracker}
     * @method
     *
     * @param {Connect} track
     * @param {String} path
     * @param {Function} done
     * */
    resolve: function (track, path, done) {

        function resolve () {

            if ( track.sent() ) {

                return;
            }

            done.apply(this, arguments);
        }

        return Server.parent.resolve.call(this, track, path, resolve);
    },

    /**
     * @public
     * @memberOf {Server}
     * @method
     *
     * */
    route: function () {
        this.router.addRoute.apply(this.router, arguments);

        return this;
    },

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @param {*} [params]
     *
     * @returns {Switcher}
     * */
    _createRouter: function (params) {

        return new Switcher(params);
    },

    /**
     * @public
     * @memberOf {Server}
     * @method
     *
     * @returns {Connect}
     * */
    _createTrack: function (req, res) {

        return new Connect(this, req, res);
    },

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @param {Connect} track
     * */
    _handle: function (track) {

        var mdata;
        var rdata;

        if ( track.sent() ) {

            return;
        }

        mdata = this._findRoute(track);

        //  по сути такой роутер может сделать send
        //  если он сделал send то он конечно понимает что он сделал
        //  такой поступок не может быть необдуманным, мы прекращаем
        //  обработку запроса
        if ( track.sent() ) {

            return;
        }

        //  однозначно нет такого маршрута
        if ( null === mdata ) {
            this.emit('sys:ematch', track);
            track.send(404);

            return;
        }

        //  возвращен массив
        if ( Array.isArray(mdata) ) {
            //  это тоже значит что нет такого роута
            this.emit('sys:ematch', track);

            //  если массив пустой, то на сервере совсем нет ни одного
            //  маршрута отвечающего по такому методу запроса
            if ( 0 === mdata.length ) {
                //  Not Implemented
                track.send(501);

                return;
            }

            //  Иначе есть такие маршруты, но для них не
            // поддерживается такой метод
            track.header('Allow', mdata.join(', '));
            //  Method Not Allowed
            track.send(405);

            return;
        }

        this.emit('sys:match', track);

        track.match = mdata.match;
        track.route = mdata.route.name;

        rdata = mdata.route.data;

        if ( Object(rdata) === rdata ) {
            rdata = rdata.unit;
        }

        this.resolve(track, rdata || track.route, function (err, res) {

            if ( 2 > arguments.length ) {
                track.send(500, err);

                return;
            }

            track.send(200, res);
        });
    },

    /**
     * @protected
     * @memberOf {Server}
     * @method
     *
     * @param {Connect} track
     *
     * @returns {*}
     * */
    _findRoute: function (track) {

        return this.router.find(track);
    }

});

module.exports = Server;
<|endoftext|>


<commit_before>'use strict';

const { EngineError } = require('../../error');
const { isJsl } = require('../../jsl');

const { propertiesPlugin } = require('./properties');

// Plugin that adds who modified last each model:
//   created_by {User} - set on model creation
//   updated_by {User} - set on model creation, modification or deletion
// Are handled by the system, and cannot be overriden by users
// User is specified by opts:
//   [user="(user())"] {jsl} - current user
//   [model="user"] {string} - user's model name
const authorPlugin = function ({ idl, opts }) {
  const { user, model } = opts;

  if (user && !isJsl({ jsl: user })) {
    const message = 'In \'author\' plugin, \'user\' must be a JSL string';
    throw new EngineError(message, { reason: 'IDL_VALIDATION' });
  }

  const usedModel = model || 'user';

  if (typeof usedModel !== 'string') {
    const message = `In 'author' plugin, 'model' must be a string: ${usedModel}`;
    throw new EngineError(message, { reason: 'IDL_VALIDATION' });
  }

  if (!idl.models[usedModel]) {
    const message = `'author' plugin requires 'idl.models.${usedModel}'`;
    throw new EngineError(message, { reason: 'IDL_VALIDATION' });
  }

  return propertiesPlugin({ getProperties })({ idl, opts });
};

const getProperties = ({ user = '(user())', model = 'user' }) => ({
  created_by: {
    type: 'object',
    description: 'Who created this model',
    model,
    readOnly: true,
    transform: {
      value: `(${user}.id)`,
      test: '($COMMAND === "create")',
    },
  },
  updated_by: {
    type: 'object',
    description: 'Who last updated this model',
    model,
    readOnly: true,
    transform: `(${user}.id)`,
  },
});

module.exports = {
  authorPlugin,
};
<commit_msg>Small refactoring<commit_after>'use strict';

const { EngineError } = require('../../error');
const { isJsl } = require('../../jsl');

const { propertiesPlugin } = require('./properties');

// Plugin that adds who modified last each model:
//   created_by {User} - set on model creation
//   updated_by {User} - set on model creation, modification or deletion
// Are handled by the system, and cannot be overriden by users
// User is specified by opts:
//   [user="(user())"] {jsl} - current user
//   [model="user"] {string} - user's model name
const authorPlugin = function ({ idl, opts }) {
  validateConf({ idl, opts });
  return propertiesPlugin({ getProperties })({ idl, opts });
};

const validateConf = function ({ idl, opts: { user, model } }) {
  if (user && !isJsl({ jsl: user })) {
    const message = 'In \'author\' plugin, \'user\' must be a JSL string';
    throw new EngineError(message, { reason: 'IDL_VALIDATION' });
  }

  const usedModel = model || 'user';

  if (typeof usedModel !== 'string') {
    const message = `In 'author' plugin, 'model' must be a string: ${usedModel}`;
    throw new EngineError(message, { reason: 'IDL_VALIDATION' });
  }

  if (!idl.models[usedModel]) {
    const message = `'author' plugin requires 'idl.models.${usedModel}'`;
    throw new EngineError(message, { reason: 'IDL_VALIDATION' });
  }
};

const getProperties = ({ user = '(user())', model = 'user' }) => ({
  created_by: {
    type: 'object',
    description: 'Who created this model',
    model,
    readOnly: true,
    transform: {
      value: `(${user}.id)`,
      test: '($COMMAND === "create")',
    },
  },
  updated_by: {
    type: 'object',
    description: 'Who last updated this model',
    model,
    readOnly: true,
    transform: `(${user}.id)`,
  },
});

module.exports = {
  authorPlugin,
};
<|endoftext|>


<commit_before>/**
 * @name ProjectListController
 * @desc Controller for the project-list view
 */

(function() {
    'use strict';

    angular.module('cometApp')
           .controller('ProjectListController', ProjectListController);

        ProjectListController.$inject = ['$rootScope',
                                         '$state',
                                         'filterFilter',
                                         'ngToast',
                                         'constraints',
                                         'dialogService',
                                         'projectService',
                                         'userService',
                                         'projects'];

        function ProjectListController ($rootScope,
                                        $state,
                                        filterFilter,
                                        ngToast,
                                        constraints,
                                        dialogService,
                                        projectService,
                                        userService,
                                        projects) {

          var vm = this;
          vm.projects = null;
          vm.isEmpty = true;
          vm.closedProjects = null;
          vm.closedProjectsEmpty = true;
          vm.gotoCreateProject = gotoCreateProject;
          vm.hiddenMembersCount = hiddenMembersCount;

          activate();

          /**
           * @name activate
           * @desc controller activation logic
           */
          function activate () {
              vm.projects = filterFilter(projects, { state:'O' });
              vm.isEmpty = (vm.projects.length === 0);
              vm.closedProjects = filterFilter(projects, { state:'C' });
              vm.closedProjectsEmpty = (vm.closedProjects.length === 0);
          }

          /**
           * @name gotoCreateProject
           * @desc validates the user account and redirects to the
           *       create project page
           */
          function gotoCreateProject() {
            var canCreate = false,
                message = "";

            userService.getCurrentUser().then(function (user) {
              if (user && user.confirmed) {
                if (checkProjectCount()) {
                  canCreate = true;
                }
                else {
                  message = 'No puedes crear un proyecto, has llegado al límite de ' +
                            constraints.projectPerUser + '.
' +
                            'Cierra algún proyecto para continuar.';
                }
              }
              else {
                message = 'No puedes crear mas de ' + constraints.projectPerUser +
                          ' proyectos. Cierra algún proyecto para continuar';
              }

              if (canCreate) {
                $state.go('dashboard.project-create');
              }
              else {
                dialogService.showModalAlert('Crear proyecto', message);
              }
            });
          }

          /**
           * @name checkProjectCount
           * @desc returns if the user has reached the maximum project count
           */
          function checkProjectCount() {
            var total = vm.projects.length;
            console.log(total, constraints.projectPerUser);
            return (total < constraints.projectPerUser);
          }

          /**
           * @name hiddenMembersCount
           * @desc returns the number of members not displayed in the project card
           */
          function hiddenMembersCount(members, displayed) {
            return members.length - displayed.length;
          }
        }
})();
<commit_msg>Crear Proyecto - Fix en validacion para usuarios no confirmados<commit_after>/**
 * @name ProjectListController
 * @desc Controller for the project-list view
 */

(function() {
    'use strict';

    angular.module('cometApp')
           .controller('ProjectListController', ProjectListController);

        ProjectListController.$inject = ['$rootScope',
                                         '$state',
                                         'filterFilter',
                                         'ngToast',
                                         'constraints',
                                         'dialogService',
                                         'projectService',
                                         'userService',
                                         'projects'];

        function ProjectListController ($rootScope,
                                        $state,
                                        filterFilter,
                                        ngToast,
                                        constraints,
                                        dialogService,
                                        projectService,
                                        userService,
                                        projects) {

          var vm = this;
          vm.projects = null;
          vm.isEmpty = true;
          vm.closedProjects = null;
          vm.closedProjectsEmpty = true;
          vm.gotoCreateProject = gotoCreateProject;
          vm.hiddenMembersCount = hiddenMembersCount;

          activate();

          /**
           * @name activate
           * @desc controller activation logic
           */
          function activate () {
              vm.projects = filterFilter(projects, { state:'O' });
              vm.isEmpty = (vm.projects.length === 0);
              vm.closedProjects = filterFilter(projects, { state:'C' });
              vm.closedProjectsEmpty = (vm.closedProjects.length === 0);
          }

          /**
           * @name gotoCreateProject
           * @desc validates the user account and redirects to the
           *       create project page
           */
          function gotoCreateProject() {
            var canCreate = false,
                message = "";

            userService.getCurrentUser().then(function (user) {
              if (user && user.confirmed) {
                if (checkProjectCount()) {
                  canCreate = true;
                }
                else {
                  message = 'No puedes crear un proyecto, has llegado al límite de ' +
                            constraints.projectPerUser + '.
' +
                            'Cierra algún proyecto para continuar.';
                }
              }
              else {
                message = 'Debes confirmar tu cuenta para poder crear un proyecto';
              }

              if (canCreate) {
                $state.go('dashboard.project-create');
              }
              else {
                dialogService.showModalAlert('Crear proyecto', message);
              }
            });
          }

          /**
           * @name checkProjectCount
           * @desc returns if the user has reached the maximum project count
           */
          function checkProjectCount() {
            var total = vm.projects.length;
            console.log(total, constraints.projectPerUser);
            return (total < constraints.projectPerUser);
          }

          /**
           * @name hiddenMembersCount
           * @desc returns the number of members not displayed in the project card
           */
          function hiddenMembersCount(members, displayed) {
            return members.length - displayed.length;
          }
        }
})();
<|endoftext|>


<commit_before>/**
 * OpenEyes
 *
 * (C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011
 * (C) OpenEyes Foundation, 2011-2013
 * This file is part of OpenEyes.
 * OpenEyes is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * OpenEyes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with OpenEyes in a file titled COPYING. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package OpenEyes
 * @link http://www.openeyes.org.uk
 * @author OpenEyes <info@openeyes.org.uk>
 * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust
 * @copyright Copyright (c) 2011-2013, OpenEyes Foundation
 * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0
 */

$(document).ready(function(){
	$collapsed = true;

	$(document).keydown(function(event){
		if(event.keyCode == 13 && $(event.target).is(':not(textarea)')) {
			event.preventDefault();
			return false;
		}
	});

	$('label').die('click').live('click',function() {
		if ($(this).prev().is('input:radio')) {
			$(this).prev().click();
		}
	});

	$(this).undelegate('select.dropDownTextSelection','change').delegate('select.dropDownTextSelection','change',function() {
		if ($(this).val() != '') {
			var target = $('#' + $(this).attr('id').replace(/^dropDownTextSelection_/,''));
			var currentVal = target.val();

			if($(this).hasClass('delimited')) {
				var newText = $(this).val();
			} else {
				var newText = $(this).children('option:selected').text();
			}

			if (currentVal.length > 0 && !$(this).hasClass('delimited')) {
				if (newText.toUpperCase() == newText) {
					newText = ', ' + newText;
				} else {
					newText = ', ' + newText.charAt(0).toLowerCase() + newText.slice(1);
				}
			} else if (currentVal.length == 0 && $(this).hasClass('delimited')) {
				newText = newText.charAt(0).toUpperCase() + newText.slice(1);
			} else if ($(this).hasClass('delimited') && currentVal.slice(-1) != ' ') {
				newText = ' ' + newText;
			}

			target.val(currentVal + newText);
			target.trigger('autosize');

			$(this).val('');
		}
	});

	// Handle form fields that have linked fields to show/hide
	$(this).on('change', 'select.linked-fields', function() {

		var fields = $(this).data('linked-fields').split(',');
		var values = $(this).data('linked-values').split(',');

		if ($(this).hasClass('MultiSelectList')) {
			var element_name = $(this).parent().prev('input').attr('name').replace(/\[.*$/,'');
		} else {
			var element_name = $(this).attr('name').replace(/\[.*$/,'');

			for (var i in fields) {
				hide_linked_field(element_name,fields[i]);
			}
		}

		if (inArray($(this).children('option:selected').text(),values)) {
			var vi = arrayIndex($(this).children('option:selected').text(),values);

			for (var i in fields) {
				if (values.length == 1 || i == vi) {
					show_linked_field(element_name,fields[i],i==0);
				}
			}
		}
	});

	$(this).on('click', 'input[type="radio"].linked-fields', function() {
		var element_name = $(this).attr('name').replace(/\[.*$/,'');

		var fields = $(this).data('linked-fields').split(',');
		var values = $(this).data('linked-values').split(',');

		if (inArray($(this).parent().text().trim(),values)) {
			for (var i in fields) {
				show_linked_field(element_name,fields[i],i==0);
			}
		} else {
			for (var i in fields) {
				hide_linked_field(element_name,fields[i]);
			}
		}
	});

	$(this).on('click', 'input[type="checkbox"].linked-fields', function() {
		var element_name = $(this).attr('name').replace(/\[.*$/,'');

		var fields = $(this).data('linked-fields').split(',');

		if ($(this).is(':checked')) {
			for (var i in fields) {
				show_linked_field(element_name,fields[i],i==0);
			}
		} else {
			for (var i in fields) {
				hide_linked_field(element_name,fields[i]);
			}
		}
	});
});

function WidgetSlider() {if (this.init) this.init.apply(this, arguments); }

WidgetSlider.prototype = {
	init : function(params) {
		for (var i in params) {
			this[i] = params[i];
		}

		var thiz = this;

		$(document).ready(function() {
			thiz.bindElement();
		});
	},

	bindElement : function() {
		var thiz = this;

		$('#'+this.range_id).change(function() {
			thiz.handleChange($(this));
		});
	},

	handleChange : function(element) {
		var val = element.val();

		for (var value in this.remap) {
			if (val == value) {
				val = this.remap[value];
			}
		}

		if (this.null.length >0) {
			if (val.match(/\./)) {
				val = String(parseFloat(val) - 1);
			} else {
				val = String(parseInt(val) - 1);
			}
		}

		var min = $('#'+this.range_id).attr('min');

		if (min.match(/\./)) {
			min = parseFloat(min);
		} else {
			min = parseInt(min);
		}

		if (val < min && this.null.length >0) {
			val = this.null;
		} else {
			if (this.force_dp) {
				if (!val.match(/\./)) {
					val += '.';
					for (var i in this.force_dp) {
						val += '00';
					}
				} else {
					var dp = val.replace(/^.*?\./,'');

					while (dp.length < this.force_dp) {
						dp += '0';
						val += '0';
					}

					while (dp.length > this.force_dp) {
						dp = dp.replace(/.$/,'');
						val = val.replace(/.$/,'');
					}
				}
			}

			if (this.prefix_positive && parseFloat(val) >0) {
				var val = this.prefix_positive + val;
			}
		}

		$('#'+this.range_id+'_value_span').text(val+this.append);
	}
}

function WidgetSliderTable() {if (this.init) this.init.apply(this, arguments); }

WidgetSliderTable.prototype = {
	init : function(params) {
		for (var i in params) {
			this[i] = params[i];
		}

		var thiz = this;

		$(document).ready(function() {
			thiz.bindElement();
		});
	},

	bindElement : function() {
		var thiz = this;

		$('#'+this.range_id).change(function() {
			thiz.handleChange($(this));
		});
	},

	handleChange : function(element) {
		var val = element.val();

		$('#'+this.range_id+'_value_span').text(this.data[val]);
	}
}

function show_linked_field(element_name,field_name,focus)
{
	$('fieldset#'+element_name+'_'+field_name).show();
	$('#div_'+element_name+'_'+field_name).show();
	if (focus) {
		$('#'+element_name+'_'+field_name).focus();
	}
}

function hide_linked_field(element_name,field_name)
{
	$('fieldset#'+element_name+'_'+field_name).hide();
	$('#div_'+element_name+'_'+field_name).hide();

	$('input[name="'+element_name+'['+field_name+']"][type="radio"]').removeAttr('checked');
	$('input[name="'+element_name+'['+field_name+']"][type="text"]').val('');
	$('select[name="'+element_name+'['+field_name+']"]').val('');

	if ($('#'+field_name).hasClass('MultiSelectList')) {
		$('a.MultiSelectRemove[data-name="'+field_name+'[]"]').map(function() {
			$(this).click();
		});
	}
}

function scrollToElement(element) {
    $('html, body').animate({
        scrollTop: parseInt(element.offset().top - 100)
    }, 1000);
}
<commit_msg>reduce animation time for scroll<commit_after>/**
 * OpenEyes
 *
 * (C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011
 * (C) OpenEyes Foundation, 2011-2013
 * This file is part of OpenEyes.
 * OpenEyes is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * OpenEyes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with OpenEyes in a file titled COPYING. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package OpenEyes
 * @link http://www.openeyes.org.uk
 * @author OpenEyes <info@openeyes.org.uk>
 * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust
 * @copyright Copyright (c) 2011-2013, OpenEyes Foundation
 * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0
 */

$(document).ready(function(){
	$collapsed = true;

	$(document).keydown(function(event){
		if(event.keyCode == 13 && $(event.target).is(':not(textarea)')) {
			event.preventDefault();
			return false;
		}
	});

	$('label').die('click').live('click',function() {
		if ($(this).prev().is('input:radio')) {
			$(this).prev().click();
		}
	});

	$(this).undelegate('select.dropDownTextSelection','change').delegate('select.dropDownTextSelection','change',function() {
		if ($(this).val() != '') {
			var target = $('#' + $(this).attr('id').replace(/^dropDownTextSelection_/,''));
			var currentVal = target.val();

			if($(this).hasClass('delimited')) {
				var newText = $(this).val();
			} else {
				var newText = $(this).children('option:selected').text();
			}

			if (currentVal.length > 0 && !$(this).hasClass('delimited')) {
				if (newText.toUpperCase() == newText) {
					newText = ', ' + newText;
				} else {
					newText = ', ' + newText.charAt(0).toLowerCase() + newText.slice(1);
				}
			} else if (currentVal.length == 0 && $(this).hasClass('delimited')) {
				newText = newText.charAt(0).toUpperCase() + newText.slice(1);
			} else if ($(this).hasClass('delimited') && currentVal.slice(-1) != ' ') {
				newText = ' ' + newText;
			}

			target.val(currentVal + newText);
			target.trigger('autosize');

			$(this).val('');
		}
	});

	// Handle form fields that have linked fields to show/hide
	$(this).on('change', 'select.linked-fields', function() {

		var fields = $(this).data('linked-fields').split(',');
		var values = $(this).data('linked-values').split(',');

		if ($(this).hasClass('MultiSelectList')) {
			var element_name = $(this).parent().prev('input').attr('name').replace(/\[.*$/,'');
		} else {
			var element_name = $(this).attr('name').replace(/\[.*$/,'');

			for (var i in fields) {
				hide_linked_field(element_name,fields[i]);
			}
		}

		if (inArray($(this).children('option:selected').text(),values)) {
			var vi = arrayIndex($(this).children('option:selected').text(),values);

			for (var i in fields) {
				if (values.length == 1 || i == vi) {
					show_linked_field(element_name,fields[i],i==0);
				}
			}
		}
	});

	$(this).on('click', 'input[type="radio"].linked-fields', function() {
		var element_name = $(this).attr('name').replace(/\[.*$/,'');

		var fields = $(this).data('linked-fields').split(',');
		var values = $(this).data('linked-values').split(',');

		if (inArray($(this).parent().text().trim(),values)) {
			for (var i in fields) {
				show_linked_field(element_name,fields[i],i==0);
			}
		} else {
			for (var i in fields) {
				hide_linked_field(element_name,fields[i]);
			}
		}
	});

	$(this).on('click', 'input[type="checkbox"].linked-fields', function() {
		var element_name = $(this).attr('name').replace(/\[.*$/,'');

		var fields = $(this).data('linked-fields').split(',');

		if ($(this).is(':checked')) {
			for (var i in fields) {
				show_linked_field(element_name,fields[i],i==0);
			}
		} else {
			for (var i in fields) {
				hide_linked_field(element_name,fields[i]);
			}
		}
	});
});

function WidgetSlider() {if (this.init) this.init.apply(this, arguments); }

WidgetSlider.prototype = {
	init : function(params) {
		for (var i in params) {
			this[i] = params[i];
		}

		var thiz = this;

		$(document).ready(function() {
			thiz.bindElement();
		});
	},

	bindElement : function() {
		var thiz = this;

		$('#'+this.range_id).change(function() {
			thiz.handleChange($(this));
		});
	},

	handleChange : function(element) {
		var val = element.val();

		for (var value in this.remap) {
			if (val == value) {
				val = this.remap[value];
			}
		}

		if (this.null.length >0) {
			if (val.match(/\./)) {
				val = String(parseFloat(val) - 1);
			} else {
				val = String(parseInt(val) - 1);
			}
		}

		var min = $('#'+this.range_id).attr('min');

		if (min.match(/\./)) {
			min = parseFloat(min);
		} else {
			min = parseInt(min);
		}

		if (val < min && this.null.length >0) {
			val = this.null;
		} else {
			if (this.force_dp) {
				if (!val.match(/\./)) {
					val += '.';
					for (var i in this.force_dp) {
						val += '00';
					}
				} else {
					var dp = val.replace(/^.*?\./,'');

					while (dp.length < this.force_dp) {
						dp += '0';
						val += '0';
					}

					while (dp.length > this.force_dp) {
						dp = dp.replace(/.$/,'');
						val = val.replace(/.$/,'');
					}
				}
			}

			if (this.prefix_positive && parseFloat(val) >0) {
				var val = this.prefix_positive + val;
			}
		}

		$('#'+this.range_id+'_value_span').text(val+this.append);
	}
}

function WidgetSliderTable() {if (this.init) this.init.apply(this, arguments); }

WidgetSliderTable.prototype = {
	init : function(params) {
		for (var i in params) {
			this[i] = params[i];
		}

		var thiz = this;

		$(document).ready(function() {
			thiz.bindElement();
		});
	},

	bindElement : function() {
		var thiz = this;

		$('#'+this.range_id).change(function() {
			thiz.handleChange($(this));
		});
	},

	handleChange : function(element) {
		var val = element.val();

		$('#'+this.range_id+'_value_span').text(this.data[val]);
	}
}

function show_linked_field(element_name,field_name,focus)
{
	$('fieldset#'+element_name+'_'+field_name).show();
	$('#div_'+element_name+'_'+field_name).show();
	if (focus) {
		$('#'+element_name+'_'+field_name).focus();
	}
}

function hide_linked_field(element_name,field_name)
{
	$('fieldset#'+element_name+'_'+field_name).hide();
	$('#div_'+element_name+'_'+field_name).hide();

	$('input[name="'+element_name+'['+field_name+']"][type="radio"]').removeAttr('checked');
	$('input[name="'+element_name+'['+field_name+']"][type="text"]').val('');
	$('select[name="'+element_name+'['+field_name+']"]').val('');

	if ($('#'+field_name).hasClass('MultiSelectList')) {
		$('a.MultiSelectRemove[data-name="'+field_name+'[]"]').map(function() {
			$(this).click();
		});
	}
}

function scrollToElement(element) {
    $('html, body').animate({
        scrollTop: parseInt(element.offset().top - 100)
    }, 1);
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2009-2010 The Open Planning Project
 *
 * @requires GeoExplorer.js
 */

/** api: (define)
 *  module = GeoExplorer
 *  class = Embed
 *  base_link = GeoExplorer
 */
Ext.namespace("GeoExplorer");

/** api: constructor
 *  ..class:: GeoExplorer.Viewer(config)
 *
 *  Create a GeoExplorer application suitable for embedding in larger pages.
 */
GeoExplorer.Viewer = Ext.extend(GeoExplorer, {

    /** private: method[initPortal]
     * Create the various parts that compose the layout.
     */
    initPortal: function() {

        // TODO: make a proper component out of this
        if (this.useMapOverlay !== false) {
            this.mapPanel.add(this.createMapOverlay());
        }

        if(this.useToolbar !== false) {
            this.toolbar = new Ext.Toolbar({
                xtype: "toolbar",
                region: "north",
                autoHeight: true,
                disabled: true,
                items: this.createTools()
            });
            this.on("ready", function() {this.toolbar.enable();}, this);
        }

        this.mapPanelContainer = new Ext.Panel({
            layout: "card",
            region: "center",
            tbar: this.toolbar,
            defaults: {
                border: false
            },
            items: [
                this.mapPanel,
                new gxp.GoogleEarthPanel({
                    mapPanel: this.mapPanel,
                    listeners: {
                        beforeadd: function(record) {
                            return record.get("group") !== "background";
                        }
                    }
                })
            ],
            activeItem: 0
        });

        this.portalItems = [
            this.mapPanelContainer
        ];

        GeoExplorer.superclass.initPortal.apply(this, arguments);

    },

    /**
     * private: method[addLayerSource]
     */
    addLayerSource: function(options) {
        // use super's super instead of super - we don't want to issue
        // DescribeLayer requests because we neither need to style layers
        // nor to show a capabilities grid.
        var source = GeoExplorer.superclass.addLayerSource.apply(this, arguments);
    },

    /**
     * api: method[createTools]
     * Create the various parts that compose the layout.
     */
    createTools: function() {
        var tools = GeoExplorer.Viewer.superclass.createTools.apply(this, arguments);

        var layerChooser = new Ext.Button({
            tooltip: 'Layer Switcher',
            iconCls: 'icon-layer-switcher',
            menu: new gxp.menu.LayerMenu({
                layers: this.mapPanel.layers
            })
        });

        tools.unshift("-");
        tools.unshift(layerChooser);

        var aboutButton = new Ext.Button({
            tooltip: "About this map",
            iconCls: "icon-about",
            handler: this.displayAppInfo,
            scope: this
        });

        tools.push("->");
        tools.push(aboutButton);

        return tools;
    }
});
<commit_msg>create GoogleEarthPanel only when google earth resources are loaded<commit_after>/**
 * Copyright (c) 2009-2010 The Open Planning Project
 *
 * @requires GeoExplorer.js
 */

/** api: (define)
 *  module = GeoExplorer
 *  class = Embed
 *  base_link = GeoExplorer
 */
Ext.namespace("GeoExplorer");

/** api: constructor
 *  ..class:: GeoExplorer.Viewer(config)
 *
 *  Create a GeoExplorer application suitable for embedding in larger pages.
 */
GeoExplorer.Viewer = Ext.extend(GeoExplorer, {

    /** private: method[initPortal]
     * Create the various parts that compose the layout.
     */
    initPortal: function() {

        // TODO: make a proper component out of this
        if (this.useMapOverlay !== false) {
            this.mapPanel.add(this.createMapOverlay());
        }

        if(this.useToolbar !== false) {
            this.toolbar = new Ext.Toolbar({
                xtype: "toolbar",
                region: "north",
                autoHeight: true,
                disabled: true,
                items: this.createTools()
            });
            this.on("ready", function() {this.toolbar.enable();}, this);
        }

        this.mapPanelContainer = new Ext.Panel({
            layout: "card",
            region: "center",
            tbar: this.toolbar,
            defaults: {
                border: false
            },
            items: [
                this.mapPanel
            ],
            activeItem: 0
        });
        if (window.google && google.earth) {
            this.mapPanelContainer.add(
                new gxp.GoogleEarthPanel({
                    mapPanel: this.mapPanel,
                    listeners: {
                        beforeadd: function(record) {
                            return record.get("group") !== "background";
                        }
                    }
                })
            );
        }

        this.portalItems = [
            this.mapPanelContainer
        ];

        GeoExplorer.superclass.initPortal.apply(this, arguments);

    },

    /**
     * private: method[addLayerSource]
     */
    addLayerSource: function(options) {
        // use super's super instead of super - we don't want to issue
        // DescribeLayer requests because we neither need to style layers
        // nor to show a capabilities grid.
        var source = GeoExplorer.superclass.addLayerSource.apply(this, arguments);
    },

    /**
     * api: method[createTools]
     * Create the various parts that compose the layout.
     */
    createTools: function() {
        var tools = GeoExplorer.Viewer.superclass.createTools.apply(this, arguments);

        var layerChooser = new Ext.Button({
            tooltip: 'Layer Switcher',
            iconCls: 'icon-layer-switcher',
            menu: new gxp.menu.LayerMenu({
                layers: this.mapPanel.layers
            })
        });

        tools.unshift("-");
        tools.unshift(layerChooser);

        var aboutButton = new Ext.Button({
            tooltip: "About this map",
            iconCls: "icon-about",
            handler: this.displayAppInfo,
            scope: this
        });

        tools.push("->");
        tools.push(aboutButton);

        return tools;
    }
});
<|endoftext|>


<commit_before>import EVENTS from '../events.js';
import external from '../externalModules.js';
import { getBrowserInfo } from '../util/getMaxSimultaneousRequests.js';
import isMouseButtonEnabled from '../util/isMouseButtonEnabled.js';
import { setToolOptions, getToolOptions } from '../toolOptions.js';
import { clipToBox } from '../util/clip.js';
import { getNewContext, fillBox } from '../util/drawing.js';

const toolType = 'magnify';

let configuration = {
  magnifySize: 300,
  magnificationLevel: 5
};

let browserName;
let currentPoints;
let zoomCanvas;
let zoomElement;

/** Remove the magnifying glass when the mouse event ends */
function mouseUpCallback (e) {
  const eventData = e.detail;
  const element = eventData.element;

  element.removeEventListener(EVENTS.MOUSE_DRAG, dragCallback);
  element.removeEventListener(EVENTS.MOUSE_UP, mouseUpCallback);
  element.removeEventListener(EVENTS.MOUSE_CLICK, mouseUpCallback);
  hideTool(eventData);
}

function hideTool (eventData) {
  const element = eventData.element;

  element.querySelector('.magnifyTool').style.display = 'none';
  // Re-enable the mouse cursor
  document.body.style.cursor = 'default';
  removeZoomElement();
}

/** Draw the magnifying glass on mouseDown, and begin tracking mouse movements */
function mouseDownCallback (e) {
  const eventData = e.detail;
  const element = eventData.element;
  const options = getToolOptions(toolType, element);

  if (e.isTouchEvent || isMouseButtonEnabled(eventData.which, options.mouseButtonMask)) {
    element.addEventListener(EVENTS.MOUSE_DRAG, dragCallback);
    element.addEventListener(EVENTS.TOUCH_DRAG, dragCallback);
    element.addEventListener(EVENTS.MOUSE_UP, mouseUpCallback);
    element.addEventListener(EVENTS.TOUCH_END, mouseUpCallback);
    element.addEventListener(EVENTS.MOUSE_CLICK, mouseUpCallback);

    element.addEventListener(EVENTS.NEW_IMAGE, newImageCallback);

    // Ignore until next event
    drawZoomedElement(eventData);
    // On next frame
    window.requestAnimationFrame(() => drawMagnificationTool(eventData));

    e.preventDefault();
    e.stopPropagation();
  }
}

function newImageCallback (e) {
  const eventData = e.detail;

  eventData.currentPoints = currentPoints;
  drawMagnificationTool(eventData);
}

function dragEndCallback (e) {
  const eventData = e.detail;
  const element = eventData.element;

  element.removeEventListener(EVENTS.TOUCH_DRAG_END, dragEndCallback);
  element.removeEventListener(EVENTS.TOUCH_END, dragEndCallback);
  element.removeEventListener(EVENTS.NEW_IMAGE, newImageCallback);
  hideTool(eventData);
}

/** Drag callback is triggered by both the touch and mouse magnify tools */
function dragCallback (e) {
  const eventData = e.detail;
  const element = eventData.element;

  drawMagnificationTool(eventData);
  if (eventData.isTouchEvent === true) {
    element.addEventListener(EVENTS.TOUCH_DRAG_END, dragEndCallback);
    element.addEventListener(EVENTS.TOUCH_END, dragEndCallback);
  }

  e.preventDefault();
  e.stopPropagation();
}

function drawMagnificationTool (eventData) {
  const element = eventData.element;
  const magnifyCanvas = element.querySelector('.magnifyTool');

  if (!magnifyCanvas) {
    createMagnificationCanvas(eventData.element);
  }

  if (zoomCanvas === undefined) {
    return;
  }

  const config = magnify.getConfiguration();

  const magnifySize = config.magnifySize;
  const magnificationLevel = config.magnificationLevel;

  // The 'not' magnifyTool class here is necessary because cornerstone places
  // No classes of it's own on the canvas we want to select
  const canvas = element.querySelector('canvas:not(.magnifyTool)');
  const context = getNewContext(magnifyCanvas);

  const getSize = magnifySize;

  // Calculate the on-canvas location of the mouse pointer / touch
  const canvasLocation = external.cornerstone.pixelToCanvas(eventData.element, eventData.currentPoints.image);

  clipToBox(canvasLocation, canvas);

  // Clear the rectangle
  context.clearRect(0, 0, magnifySize, magnifySize);

  // Fill it with the pixels that the mouse is clicking on
  const boundingBox = {
    left: 0,
    top: 0,
    width: magnifySize,
    height: magnifySize
  };

  fillBox(context, boundingBox, 'transparent');

  const copyFrom = {
    x: canvasLocation.x * magnificationLevel - 0.5 * getSize,
    y: canvasLocation.y * magnificationLevel - 0.5 * getSize
  };

  if (browserName === 'Safari') {
    // Safari breaks when trying to copy pixels with negative indices
    // This prevents proper Magnify usage
    copyFrom.x = Math.max(copyFrom.x, 0);
    copyFrom.y = Math.max(copyFrom.y, 0);
  }

  copyFrom.x = Math.min(copyFrom.x, zoomCanvas.width);
  copyFrom.y = Math.min(copyFrom.y, zoomCanvas.height);

  context.drawImage(zoomCanvas, copyFrom.x, copyFrom.y, getSize, getSize, 0, 0, getSize, getSize);

  // Place the magnification tool at the same location as the pointer
  magnifyCanvas.style.top = `${canvasLocation.y - 0.5 * magnifySize}px`;
  magnifyCanvas.style.left = `${canvasLocation.x - 0.5 * magnifySize}px`;

  if (eventData.isTouchEvent) {
    magnifyCanvas.style.top = `${canvasLocation.y - 0.5 * magnifySize - 120}px`;
  }

  magnifyCanvas.style.display = 'block';

  // Hide the mouse cursor, so the user can see better
  document.body.style.cursor = 'none';
}

/** Creates the magnifying glass canvas */
function createMagnificationCanvas (element) {
  // If the magnifying glass canvas doesn't already exist
  if (element.querySelector('.magnifyTool') === null) {
    // Create a canvas and append it as a child to the element
    const magnifyCanvas = document.createElement('canvas');

    // The magnifyTool class is used to find the canvas later on
    magnifyCanvas.classList.add('magnifyTool');

    const config = magnify.getConfiguration();

    magnifyCanvas.width = config.magnifySize;
    magnifyCanvas.height = config.magnifySize;

    // Make sure position is absolute so the canvas can follow the mouse / touch
    magnifyCanvas.style.position = 'absolute';
    magnifyCanvas.style.display = 'none';
    element.appendChild(magnifyCanvas);
  }
}

/** Find the magnifying glass canvas and remove it */
function removeMagnificationCanvas (element) {
  const magnifyCanvas = element.querySelector('.magnifyTool');

  if (magnifyCanvas) {
    element.removeChild(magnifyCanvas);
  }
}

function drawZoomedElement (eventData) {
  removeZoomElement();
  let enabledElement = eventData.enabledElement;

  if (enabledElement === undefined) {
    enabledElement = external.cornerstone.getEnabledElement(eventData.element);
  }
  const config = magnify.getConfiguration();

  const magnificationLevel = config.magnificationLevel;
  const origCanvas = enabledElement.canvas;
  const image = enabledElement.image;

  zoomElement = document.createElement('div');

  zoomElement.width = origCanvas.width * magnificationLevel;
  zoomElement.height = origCanvas.height * magnificationLevel;
  external.cornerstone.enable(zoomElement);

  const zoomEnabledElement = external.cornerstone.getEnabledElement(zoomElement);
  const viewport = external.cornerstone.getViewport(enabledElement.element);

  zoomCanvas = zoomEnabledElement.canvas;
  zoomCanvas.width = origCanvas.width * magnificationLevel;
  zoomCanvas.height = origCanvas.height * magnificationLevel;

  zoomEnabledElement.viewport = Object.assign({}, viewport);

  viewport.scale *= magnificationLevel;
  external.cornerstone.displayImage(zoomElement, image);
  external.cornerstone.setViewport(zoomElement, viewport);
}

function removeZoomElement () {
  if (zoomElement !== undefined) {
    external.cornerstone.disable(zoomElement);
    zoomElement = undefined;
    zoomCanvas = undefined;
  }
}

// --- Mouse tool activate / disable --- //
function disable (element) {
  element.removeEventListener(EVENTS.MOUSE_DOWN, mouseDownCallback);
  removeMagnificationCanvas(element);
}

function enable (element) {
  const config = magnify.getConfiguration(config);

  if (!browserName) {
    const infoString = getBrowserInfo();
    const info = infoString.split(' ');

    browserName = info[0];
  }

  createMagnificationCanvas(element);
}

function activate (element, mouseButtonMask) {
  setToolOptions(toolType, element, { mouseButtonMask });

  element.removeEventListener(EVENTS.MOUSE_DOWN, mouseDownCallback);

  element.addEventListener(EVENTS.MOUSE_DOWN, mouseDownCallback);
  createMagnificationCanvas(element);
}

// --- Touch tool activate / disable --- //
function getConfiguration () {
  return configuration;
}

function setConfiguration (config) {
  configuration = config;
}

// Module exports
const magnify = {
  enable,
  activate,
  deactivate: disable,
  disable,
  getConfiguration,
  setConfiguration
};

function enableTouch (element) {
  element.removeEventListener(EVENTS.TOUCH_START, mouseDownCallback);
  element.addEventListener(EVENTS.TOUCH_START, mouseDownCallback);
}

// Disables the reference line tool for the given element
function disableTouch (element) {
  element.removeEventListener(EVENTS.TOUCH_START, mouseDownCallback);
}

const magnifyTouchDrag = {
  activate: enableTouch,
  deactivate: disableTouch,
  enable: enableTouch,
  disable: disableTouch
};

export {
  magnify,
  magnifyTouchDrag
};
<commit_msg>remove previous magnify tool<commit_after><|endoftext|>