<commit_before>/**
	MIT License

	Copyright (c) 2016 Daniel Budde

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
*/

//
//	Plugin Name:	windowMessenger
//	Author(s):		Daniel Budde
//	Created:		05/05/2016
//
//

// Verify jQuery is available and that the window supports messaging.
if (jQuery != undefined && window.postMessage != undefined)
{
	(
		function($, window, document, undefined)
		{
			/*************************/
			/*     Define Widget     */
			/*************************/
			var windowMessengerDefinition =
			{
				/*************************/
				/*    Default Options    */
				/*************************/
				options: {},

				/*************************/
				/*    Public Methods     */
				/*************************/
				addTrustedOrigin: function(origin)
				{
					if (this._isType(origin, "string"))
					{
						this._trustedOrigins[origin.toLowerCase()] = true;
					}
				},

				execute: function(method, args, windowName)
				{
					var message = {method: null, args: null, context: null};

					args = this._setDefault(args, []);
					windowName = this._setDefault(windowName, "default");

					if (this.isRegistered(windowName) && (this._isType(method, "string") || this._isType(method, "function")))
					{
						if (this._isType(method, "function"))
						{
							method = "" + method;
						}

						message.method = method;
						message.args = args;

						this._sendMessage("execute", message, "", windowName);
					}
				},

				getTrustedOrigins: function()
				{
					var key = null,
						trustedOrigins = [];

					for (key in this._trustedOrigins)
					{
						trustedOrigins.push(key);
					}

					return trustedOrigins;
				},

				getWindow: function(windowName, windowOnly)
				{
					var winObj = null;

					windowOnly = this._setDefault(windowOnly, true);

					winObj = this._getWindow(windowName);

					if (this._isType(winObj))
					{
						if (windowOnly)
						{
							return winObj.win;
						}
						else
						{
							return {origin: winObj.origin, win: winObj.win};
						}
					}
				},

				isRegistered: function(windowName)
				{
					if (!this._isType(windowName, "string") || !this._isType(this._windows[windowName]))
					{
						return false;
					}

					return true;
				},

				post: function(message, identifier, windowName)
				{
					windowName = this._setDefault(windowName, "default");
					identifier = this._setDefault(identifier, "");

					if (this.isRegistered(windowName))
					{
						this._sendMessage("post", message, identifier, windowName);
					}
				},

				registerWindow: function(windowName, win, origin, isDefault)
				{
					isDefault = this._setDefault(isDefault, false);
					origin = this._setDefault(origin, "*");

					if (this._isType(windowName, "string") && windowName != "default" && this._isType(win) && !this.isRegistered(windowName))
					{
						this.addTrustedOrigin(origin);

						this._windows[windowName] = {origin: origin, win: win};

						if (this._defaultWindow == null || isDefault)
						{
							this._defaultWindow = win;
							this._windows["default"] = this._windows[windowName];
						}
					}
				},

				/*************************/
				/*    Private Methods    */
				/*************************/
				_create: function()
				{
					var $scriptTag = $(scriptTag),
						autoRegister = null,
						i = 0,
						trustedOrigins = null;

					autoRegister = $scriptTag.data("autoregister");
					trustedOrigins = $scriptTag.data("trustedorigins");

					// Set widget auto-register setting from the script tag.
					if (this._isType(autoRegister))
					{
						this._autoRegister = Boolean(autoRegister);
					}

					// Add trusted origins loaded from the script tag.
					if (this._isType(trustedOrigins, "string"))
					{
						trustedOrigins = trustedOrigins.split(",");

						for (i = 0; i < trustedOrigins.length; i++)
						{
							this.addTrustedOrigin(trustedOrigins[i]);
						}
					}

					// Add this window's origin as a trusted origin.
					this.addTrustedOrigin(window.location.origin);

					this._initEvents();

					if (this._autoRegister)
					{
						this._registerParentWindow();
					}
				},

				_createID: function(length)
				{
					var i = 0,
						id = "",
						possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

					if (!this._isType(length, "number"))
					{
						length = 6;
					}

					for (i = 0; i < length; i++)
					{
						id += possible.charAt(Math.floor(Math.random() * possible.length));
					}

					return id;
				},

				_destroy: function()
				{

				},

				_discoverChildren: function()
				{
					var $plugin = this;

					$("iframe").each(
						function(index)
						{
							var name = "temp" + $plugin._createID(),
								success = false,
								win = this.contentWindow;

							if (this.id.length === 0)
							{
								this.id = "iFrame" + $plugin._createID();
							}

							$plugin._iFrames[this.id] = this;

							$plugin.registerWindow(name, win, "*");
							$plugin._pingChild(name, this.id);
							$plugin._unRegisterWindow(name);
						}
					);
				},

				_executeMethod: function(method, args)
				{
					var methodRef = null;

					// Parses a function out of text.  May not work well on poorly formated functions.
					if (method.length > 8 && method.substr(0, 8) == "function")
					{
						method = this._parseFunction(method);
					}

					// Handle a string path to a method.
					if (this._isType(method, "string"))
					{
						methodRef = eval(method);

						if (this._isType(methodRef, "function"))
						{
							methodRef.apply(undefined, args);
						}
					}

					// Handle a function being passed.
					else if (this._isType(method, "function"))
					{
						method.apply(undefined, args);
					}
				},

				_getWindow: function(windowName)
				{
					if (this.isRegistered(windowName))
					{
						return this._windows[windowName];
					}
				},

				_initEvents: function()
				{
					var $el = this.element,
						$plugin = this;

					// Add window listener to process received messages.
					$el.on(
						"message",
						function(ev)
						{
							var event = ev.originalEvent || ev;

							$plugin._processMessage.apply($plugin, [event]);
						}
					);

					if (this._autoRegister)
					{
						$el.on(
							"load",
							function(ev)
							{
								$plugin._discoverChildren.apply($plugin, []);
							}
						);
					}
				},

				_isTrustedOrigin: function(origin)
				{
					if (this._isType(this._trustedOrigins[origin]))
					{
						return true;
					}

					return false;
				},

				_isType: function(value, type)
				{
					if (value != undefined && value != null && (type === undefined || $.type(value) === type))
					{
						return true;
					}

					return false;
				},

				_parseFunction: function(method)
				{
					var args = [],
						argString = "",
						functionBody = "",
						i = 0,
						index = 0,
						m = method;

					m = m.substr(8, m.length - 8);

					// Stip out the function arguments.
					index = m.indexOf(")") + 1;

					argString = m.substr(0, index).replace(/\)/g, "").replace(/\(/g, "");
					m = m.substr(index, m.length - index);

					args = argString.split(",");

					for (i = 0; i < args.length; i++)
					{
						args[i] = this._trim(args[i]);
					}

					// Trim off first function bracket;
					index = m.indexOf("{") + 1;
					m = m.substr(index, m.length - index);

					index = m.lastIndexOf("}");
					m = m.substr(0, index);

					args.push(this._trim(m));

					return Function.apply(undefined, args);
				},

				_parseOriginDomain: function(origin)
				{
					var path = null,
						originDomain = origin.toLowerCase();

					if (originDomain.length > 4 && originDomain.substr(0, 4) === "http")
					{
						originDomain = originDomain.replace("http://", "");
						originDomain = originDomain.replace("https://", "");
					}

					path = originDomain.split("/");
					originDomain = path[0];

					return originDomain;
				},

				_pingChild: function(windowName, id)
				{
					windowName = this._setDefault(windowName, "default");

					if (this.isRegistered(windowName))
					{
						this._sendMessage("ping", {id: id, origin: window.location.origin}, "", windowName);
					}
				},

				_processMessage: function(ev)
				{
					// ev.data
					// ev.origin
					// ev.isTrusted
					// ev.type - 'message'

					var $el = this.element,
						action = ev.data.action,
						eventName = "messageReceived",
						identifier = ev.data.identifier,
						message = ev.data.message,
						originDomain = this._parseOriginDomain(ev.origin),
						parent = null;

					// * = Trust any
					// originDomain = Trust any coming from a specific domain.
					// origin = Trust with a specific origin.
					if (this._isTrustedOrigin("*") || this._isTrustedOrigin(originDomain) || this._isTrustedOrigin(ev.origin))
					{
						switch (ev.data.action)
						{
							case "execute":
								this._executeMethod(message.method, message.args);
								break;

							case "ping":

								// Correct origin for auto-registered parent.
								if (this._autoRegister)
								{
									parent = this._getWindow("parent");

									// Don't correct origin if it is the local file system.
									if (this._isType(parent) && message.origin.length >= 5 && message.origin.substr(0, 5) != "file:")
									{
										parent.origin = message.origin;
									}
								}

								this._sendMessage("pingResponse", {id: message.id, origin: window.location.origin}, "", "parent");
								break;

							case "pingResponse":
								if (this._isType(this._iFrames[message.id]))
								{
									this._registerChildWindow(this._iFrames[message.id].contentWindow, message.origin);

									delete this._iFrames[message.id];
								}
								break;

							case "registerChild":
								this._registerChildWindow(message.win, message.origin);
								break;

							default:
								$el.trigger(eventName, [message, identifier]);
						}
					}
				},

				_registerChildWindow: function(win, origin)
				{
					var name = "child",
						nextChild = this._childWindows.length + 1,
						winObj = null;

					name += nextChild;

					origin = this._setDefault(origin, "*");

					// Handle files ran on local file system.
					if (origin.length >= 5 && origin.substr(0, 5) === "file:")
					{
						origin = "*";
					}

					this.registerWindow(name, win, origin);

					winObj = this._getWindow(name);

					if (this._isType(winObj))
					{
						this._childWindows.push(winObj);
					}
				},

				_registerParentWindow: function()
				{
					// Register parent
					if (window != window.parent)
					{
						// This is only done for auto-register, since we don't know the parent's origin yet. Could be a security issue.
						this.registerWindow("parent", window.parent, "*");
					}

					// Register top
					if (window != window.top && window.parent != window.top)
					{
						// This is only done for auto-register, since we don't know the parent's origin yet. Could be a security issue.
						this.registerWindow("top", window.top, "*");
					}
				},

				_sendMessage: function(action, message, identifier, windowName)
				{
					var winObj = this._getWindow(windowName);

					identifier = this._setDefault(identifier, "");

					if (winObj != undefined)
					{
						winObj.win.postMessage({action: action, message: message, identifier: identifier}, winObj.origin);
					}
				},

				_setDefault: function(value, defaultValue)
				{
					if (this._isType(value))
					{
						return value;
					}

					return defaultValue;
				},

				_setOption: function(key, value)
				{
					var $plugin = this;

					switch (String(key).toLowerCase())
					{
						case "somevalue":
							// $plugin.options.someValue = doSomething(value);
							break;

						default:
							$plugin.options[key] = value;
							break;
					}

					$plugin._super("_setOption", key, value);
				},

				_trim: function(string)
				{
					return string.replace(/^\s*/, "").replace(/\s*$/, "");
				},

				_unRegisterWindow: function(windowName)
				{
					if (this._isType(this._windows[windowName]))
					{
						if (this._defaultWindow === this._windows[windowName].win)
						{
							this._defaultWindow = null;
						}

						if (this._windows["default"] === this._windows[windowName])
						{
							delete this._windows["default"];
						}

						delete this._windows[windowName];
					}
				},

				/*************************/
				/*    Private Values     */
				/*************************/
				_autoRegister: false,
				_childWindows: [],
				_defaultWindow: null,
				_iFrames: {},
				_trustedOrigins: {},
				_windows: {}
			};

			var scriptTag = document.currentScript;

			// Register widget definition with jQuery UI Widget factory
			$.widget("window.messenger", windowMessengerDefinition);

			// Load widget
			$(window).messenger();
		}
	)(jQuery, window, document);
}<commit_msg>Added 'enableExecute' option.<commit_after>/**
	MIT License

	Copyright (c) 2016 Daniel Budde

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
*/

//
//	Plugin Name:	windowMessenger
//	Author(s):		Daniel Budde
//	Created:		05/05/2016
//
//

// Verify jQuery is available and that the window supports messaging.
if (jQuery != undefined && window.postMessage != undefined)
{
	(
		function($, window, document, undefined)
		{
			/*************************/
			/*     Define Widget     */
			/*************************/
			var windowMessengerDefinition =
			{
				/*************************/
				/*    Default Options    */
				/*************************/
				options: {},

				/*************************/
				/*    Public Methods     */
				/*************************/
				addTrustedOrigin: function(origin)
				{
					if (this._isType(origin, "string"))
					{
						this._trustedOrigins[origin.toLowerCase()] = true;
					}
				},

				execute: function(method, args, windowName)
				{
					var message = {method: null, args: null, context: null};

					args = this._setDefault(args, []);
					windowName = this._setDefault(windowName, "default");

					if (this.isRegistered(windowName) && (this._isType(method, "string") || this._isType(method, "function")))
					{
						if (this._isType(method, "function"))
						{
							method = "" + method;
						}

						message.method = method;
						message.args = args;

						if (this._enableExecute)
						{
							this._sendMessage("execute", message, "", windowName);
						}
					}
				},

				getTrustedOrigins: function()
				{
					var key = null,
						trustedOrigins = [];

					for (key in this._trustedOrigins)
					{
						trustedOrigins.push(key);
					}

					return trustedOrigins;
				},

				getWindow: function(windowName, windowOnly)
				{
					var winObj = null;

					windowOnly = this._setDefault(windowOnly, true);

					winObj = this._getWindow(windowName);

					if (this._isType(winObj))
					{
						if (windowOnly)
						{
							return winObj.win;
						}
						else
						{
							return {origin: winObj.origin, win: winObj.win};
						}
					}
				},

				isRegistered: function(windowName)
				{
					if (!this._isType(windowName, "string") || !this._isType(this._windows[windowName]))
					{
						return false;
					}

					return true;
				},

				post: function(message, identifier, windowName)
				{
					windowName = this._setDefault(windowName, "default");
					identifier = this._setDefault(identifier, "");

					if (this.isRegistered(windowName))
					{
						this._sendMessage("post", message, identifier, windowName);
					}
				},

				registerWindow: function(windowName, win, origin, isDefault)
				{
					isDefault = this._setDefault(isDefault, false);
					origin = this._setDefault(origin, "*");

					if (this._isType(windowName, "string") && windowName != "default" && this._isType(win) && !this.isRegistered(windowName))
					{
						this.addTrustedOrigin(origin);

						this._windows[windowName] = {origin: origin, win: win};

						if (this._defaultWindow == null || isDefault)
						{
							this._defaultWindow = win;
							this._windows["default"] = this._windows[windowName];
						}
					}
				},

				/*************************/
				/*    Private Methods    */
				/*************************/
				_create: function()
				{
					var $scriptTag = $(scriptTag),
						enableExecute = null,
						autoRegister = null,
						i = 0,
						trustedOrigins = null;

					autoRegister = $scriptTag.data("autoregister");
					enableExecute = $scriptTag.data("enableexecute");
					trustedOrigins = $scriptTag.data("trustedorigins");

					// Set widget auto-register setting from the script tag.
					if (this._isType(autoRegister))
					{
						this._autoRegister = Boolean(autoRegister);
					}

					// Set widget enableExecute setting.
					if (this._isType(enableExecute))
					{
						this._enableExecute = Boolean(enableExecute);
					}

					// Add trusted origins loaded from the script tag.
					if (this._isType(trustedOrigins, "string"))
					{
						trustedOrigins = trustedOrigins.split(",");

						for (i = 0; i < trustedOrigins.length; i++)
						{
							this.addTrustedOrigin(trustedOrigins[i]);
						}
					}

					// Add this window's origin as a trusted origin.
					this.addTrustedOrigin(window.location.origin);

					this._initEvents();

					if (this._autoRegister)
					{
						this._registerParentWindow();
					}
				},

				_createID: function(length)
				{
					var i = 0,
						id = "",
						possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

					if (!this._isType(length, "number"))
					{
						length = 6;
					}

					for (i = 0; i < length; i++)
					{
						id += possible.charAt(Math.floor(Math.random() * possible.length));
					}

					return id;
				},

				_destroy: function()
				{

				},

				_discoverChildren: function()
				{
					var $plugin = this;

					$("iframe").each(
						function(index)
						{
							var name = "temp" + $plugin._createID(),
								success = false,
								win = this.contentWindow;

							if (this.id.length === 0)
							{
								this.id = "iFrame" + $plugin._createID();
							}

							$plugin._iFrames[this.id] = this;

							$plugin.registerWindow(name, win, "*");
							$plugin._pingChild(name, this.id);
							$plugin._unRegisterWindow(name);
						}
					);
				},

				_executeMethod: function(method, args)
				{
					var methodRef = null;

					// Parses a function out of text.  May not work well on poorly formated functions.
					if (method.length > 8 && method.substr(0, 8) == "function")
					{
						method = this._parseFunction(method);
					}

					// Handle a string path to a method.
					if (this._isType(method, "string"))
					{
						methodRef = eval(method);

						if (this._isType(methodRef, "function"))
						{
							methodRef.apply(undefined, args);
						}
					}

					// Handle a function being passed.
					else if (this._isType(method, "function"))
					{
						method.apply(undefined, args);
					}
				},

				_getWindow: function(windowName)
				{
					if (this.isRegistered(windowName))
					{
						return this._windows[windowName];
					}
				},

				_initEvents: function()
				{
					var $el = this.element,
						$plugin = this;

					// Add window listener to process received messages.
					$el.on(
						"message",
						function(ev)
						{
							var event = ev.originalEvent || ev;

							$plugin._processMessage.apply($plugin, [event]);
						}
					);

					if (this._autoRegister)
					{
						$el.on(
							"load",
							function(ev)
							{
								$plugin._discoverChildren.apply($plugin, []);
							}
						);
					}
				},

				_isTrustedOrigin: function(origin)
				{
					if (this._isType(this._trustedOrigins[origin]))
					{
						return true;
					}

					return false;
				},

				_isType: function(value, type)
				{
					if (value != undefined && value != null && (type === undefined || $.type(value) === type))
					{
						return true;
					}

					return false;
				},

				_parseFunction: function(method)
				{
					var args = [],
						argString = "",
						functionBody = "",
						i = 0,
						index = 0,
						m = method;

					m = m.substr(8, m.length - 8);

					// Stip out the function arguments.
					index = m.indexOf(")") + 1;

					argString = m.substr(0, index).replace(/\)/g, "").replace(/\(/g, "");
					m = m.substr(index, m.length - index);

					args = argString.split(",");

					for (i = 0; i < args.length; i++)
					{
						args[i] = this._trim(args[i]);
					}

					// Trim off first function bracket;
					index = m.indexOf("{") + 1;
					m = m.substr(index, m.length - index);

					index = m.lastIndexOf("}");
					m = m.substr(0, index);

					args.push(this._trim(m));

					return Function.apply(undefined, args);
				},

				_parseOriginDomain: function(origin)
				{
					var path = null,
						originDomain = origin.toLowerCase();

					if (originDomain.length > 4 && originDomain.substr(0, 4) === "http")
					{
						originDomain = originDomain.replace("http://", "");
						originDomain = originDomain.replace("https://", "");
					}

					path = originDomain.split("/");
					originDomain = path[0];

					return originDomain;
				},

				_pingChild: function(windowName, id)
				{
					windowName = this._setDefault(windowName, "default");

					if (this.isRegistered(windowName))
					{
						this._sendMessage("ping", {id: id, origin: window.location.origin}, "", windowName);
					}
				},

				_processMessage: function(ev)
				{
					// ev.data
					// ev.origin
					// ev.isTrusted
					// ev.type - 'message'

					var $el = this.element,
						action = ev.data.action,
						eventName = "messageReceived",
						identifier = ev.data.identifier,
						message = ev.data.message,
						originDomain = this._parseOriginDomain(ev.origin),
						parent = null;

					// * = Trust any
					// originDomain = Trust any coming from a specific domain.
					// origin = Trust with a specific origin.
					if (this._isTrustedOrigin("*") || this._isTrustedOrigin(originDomain) || this._isTrustedOrigin(ev.origin))
					{
						switch (ev.data.action)
						{
							case "execute":
								this._executeMethod(message.method, message.args);
								break;

							case "ping":

								// Correct origin for auto-registered parent.
								if (this._autoRegister)
								{
									parent = this._getWindow("parent");

									// Don't correct origin if it is the local file system.
									if (this._isType(parent) && message.origin.length >= 5 && message.origin.substr(0, 5) != "file:")
									{
										parent.origin = message.origin;
									}
								}

								this._sendMessage("pingResponse", {id: message.id, origin: window.location.origin}, "", "parent");
								break;

							case "pingResponse":
								if (this._isType(this._iFrames[message.id]))
								{
									this._registerChildWindow(this._iFrames[message.id].contentWindow, message.origin);

									delete this._iFrames[message.id];
								}
								break;

							case "registerChild":
								this._registerChildWindow(message.win, message.origin);
								break;

							default:
								$el.trigger(eventName, [message, identifier]);
						}
					}
				},

				_registerChildWindow: function(win, origin)
				{
					var name = "child",
						nextChild = this._childWindows.length + 1,
						winObj = null;

					name += nextChild;

					origin = this._setDefault(origin, "*");

					// Handle files ran on local file system.
					if (origin.length >= 5 && origin.substr(0, 5) === "file:")
					{
						origin = "*";
					}

					this.registerWindow(name, win, origin);

					winObj = this._getWindow(name);

					if (this._isType(winObj))
					{
						this._childWindows.push(winObj);
					}
				},

				_registerParentWindow: function()
				{
					// Register parent
					if (window != window.parent)
					{
						// This is only done for auto-register, since we don't know the parent's origin yet. Could be a security issue.
						this.registerWindow("parent", window.parent, "*");
					}

					// Register top
					if (window != window.top && window.parent != window.top)
					{
						// This is only done for auto-register, since we don't know the parent's origin yet. Could be a security issue.
						this.registerWindow("top", window.top, "*");
					}
				},

				_sendMessage: function(action, message, identifier, windowName)
				{
					var winObj = this._getWindow(windowName);

					identifier = this._setDefault(identifier, "");

					if (winObj != undefined)
					{
						winObj.win.postMessage({action: action, message: message, identifier: identifier}, winObj.origin);
					}
				},

				_setDefault: function(value, defaultValue)
				{
					if (this._isType(value))
					{
						return value;
					}

					return defaultValue;
				},

				_setOption: function(key, value)
				{
					var $plugin = this;

					switch (String(key).toLowerCase())
					{
						case "somevalue":
							// $plugin.options.someValue = doSomething(value);
							break;

						default:
							$plugin.options[key] = value;
							break;
					}

					$plugin._super("_setOption", key, value);
				},

				_trim: function(string)
				{
					return string.replace(/^\s*/, "").replace(/\s*$/, "");
				},

				_unRegisterWindow: function(windowName)
				{
					if (this._isType(this._windows[windowName]))
					{
						if (this._defaultWindow === this._windows[windowName].win)
						{
							this._defaultWindow = null;
						}

						if (this._windows["default"] === this._windows[windowName])
						{
							delete this._windows["default"];
						}

						delete this._windows[windowName];
					}
				},

				/*************************/
				/*    Private Values     */
				/*************************/
				_enableExecute: true,
				_autoRegister: false,
				_childWindows: [],
				_defaultWindow: null,
				_iFrames: {},
				_trustedOrigins: {},
				_windows: {}
			};

			var scriptTag = document.currentScript;

			// Register widget definition with jQuery UI Widget factory
			$.widget("window.messenger", windowMessengerDefinition);

			// Load widget
			$(window).messenger();
		}
	)(jQuery, window, document);
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Peter Kuma

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var Model = new Class({
    Implements: Events,

    defaults: {
	pk: 'id'
    },

    initialize: function(attributes) {
        for (var attr in this.defaults) {
            this[attr] = this.defaults[attr];
        }
	for (var attr in attributes) {
	    this[attr] = attributes[attr];
	}
    },

    set: function(attr, value) {
	if (this[attr] != value) {
	    this[attr] = value;
	    this.fireEvent('change');
	}
    },

    get: function(attr) {
        return this[attr];
    },

    update: function(json) {
        for (var attr in json) {
	    this[attr] = json[attr];
	}
	this.fireEvent('change');
    },

    remove: function() {
	this.fireEvent('remove');
    }
});

var Item = new Class({
    Extends: Model,

    defaults: {
	id: -1,
	type: 'complete', // 'pending', 'unfinished', 'stale', 'complete'.
        name: '',
	url: '',
        size: 0,
        size_total: 0,
        status: 'READY', // 'READY', 'UPLOADING', 'STALE'.
        created: new Date(),
        uploaded: new Date(),
        modified: new Date()
    },

    initialize: function(attributes) {
	this.parent(attributes);
	this.id = uuid();
    },

    update: function(json) {
	if (this.type == 'pending')
	    ; // Do nothing.
	else if (json.status == 'READY')
	    this.type = 'complete';
	else if (json.status == 'UPLOADING')
	    this.type = 'unfinished';
	else if (json.status == 'STALE')
	    this.type = 'stale';

	for (var attr in json) {
	    if (this.type == 'pending' && (attr == 'status' || attr == 'size'))
		continue;
	    this[attr] = json[attr];
	}
	this.modified = new Date().parse(json.modified);
	this.uploaded = new Date().parse(json.uploaded);
	this.created = new Date().parse(json.created);

	this.fireEvent('change');
    },

    remove: function() {
	if (this.xhr) this.xhr.abort();
	//this.parent();
	this.fireEvent('remove');
    },

    del: function() {
	if (this.xhr) this.xhr.abort();

	var xhr = new XMLHttpRequest();
	xhr.open('POST', 'delete/' + this.id + '/');
	xhr.setRequestHeader('X-CSRFToken', CSRF_TOKEN);

	var this_ = this;
	xhr.onreadystatechange = function(e) {
	    if (this.readyState == this.DONE) {
		this_.remove();
	    }
	};
	xhr.send('csrfmiddlewaretoken='+CSRF_TOKEN);

	this.remove();
    },

    upload: function(data, offset, len) {
	if (typeof offset == 'undefined') offset = this.size;
	if (typeof data == 'string') this.set('size_total', data.length);
	if (data.size) this.set('size_total', data.size);
	if (typeof len == 'undefined') len = CHUNK_SIZE;
	if (this.size + len > this.size_total)
	    len = this.size_total - this.size;

	this.set('type', 'pending');

	this.xhr = new XMLHttpRequest();
        this.xhr.open('POST', 'upload/' + this.id + '/');

	var this_ = this;
	var startTime = new Date().getTime();

	if (this.xhr.upload) {
	    this.xhr.upload.addEventListener('progress', function(e) {
		if (!this_.size_total) this_.set('size_total', e.total);
		if (!len) len = this_.size_total;
		this_.set('size', offset + e.position/e.total*len);
	    }, false);

	    this.xhr.upload.addEventListener('load', function(e) {
		if (typeof data == 'string') this_.set('size', offset + len);
	    }, false);
	}

	this.xhr.onreadystatechange = function(e) {
	    if (this.readyState == 4) {
		try {
		    var response = JSON.decode(this.responseText);
		} catch(e) {
		    this_.fireEvent('error', {
			label: 'Upload failed',
			message: 'The server responded with an invalid message',
			details: this.responseText
		    });
		}

		if (this.status == 200 && response.status == 'success') {
		    this_.size = offset + len;
		    this_.update(response.item);

		    if (this_.size < this_.size_total) {
			elapsedTime = new Date().getTime() - startTime;
			if (elapsedTime < CHUNK_UPLOAD_LOW*1000) {
			    len *= 2;
			    if (len > 64*1024*1024) len = 64*1024*1024;
			    //console.log('Doubling chunk size');
			}
			if (elapsedTime > CHUNK_UPLOAD_HIGH*1000) {
			    len /= 2;
			    if (len < 32*1024) len = 32*1024;
			    //console.log('Halving chunk size');
			}

			// Upload the next chunk.
			this_.upload(data, this_.size, len);
		    } else {
			// We are done.
			this_.set('type', 'complete');
		    }
		} else if (this.status == 403) {
		    this_.fireEvent('error', {
			label: 'Your session expired',
			message_html: 'Please log in again'
		    });
		} else if (this.status != 0) {
		    // Revert to the original size as the chunk upload failed.
		    this_.set('size', offset);
		    if (response) {
			this_.fireEvent('error', {
			    label: response.error_label,
			    message: response.error_message
			});
		    } else {
			this_.fireEvent('error', {
			    label: 'Application Error',
			    message: this.status+' '+this.statusText,
			    details: this.responseText
			});
		    }
		} else {
		    // Revert to the original size as the chunk upload failed.
		    this_.set('size', offset);
		    this_.fireEvent('error', {
			label: 'Upload failed',
			message: 'The upload was terminated before completion'
		    });
		}
	    }
	};

	if (typeof File != 'undefined' && data instanceof File && typeof FormData != 'undefined') {
	    if (data.mozSlice) var chunk = data.mozSlice(offset, offset + len);
	    else if (data.webkiteSlice) var chunk = data.webkitSlice(offset, offset + len);
	    else var chunk = data.slice(offset, offset + len);
	    var body = new FormData();
	    body.append('file', chunk);
	} else if(typeof data == 'string') {
	    var boundary = 'xxxxxxxxxxxxxxxxxxxx';
	    var body = '--' + boundary + '\r\n';
	    body += 'Content-Disposition: form-data; name="file"; filename="' + encodeURIComponent(this.name) + '"\r\n';
	    body += 'Content-Type: application/octet-stream\r\n';
	    body += '\r\n';
	    body += window.btoa(data.substring(offset, offset + len)) + '\r\n';
	    body += '--' + boundary + '--\r\n';
	    this.xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
	    this.xhr.setRequestHeader('X-File-Encoding', 'base64');
	} else {
	    var body = data;
	    len = this.size_total - offset;
	}

	if (this.size_total) this.xhr.setRequestHeader('X-File-Size', this.size_total);
	this.xhr.setRequestHeader('X-File-Offset', offset);
	this.xhr.setRequestHeader('X-File-Name', encodeURIComponent(this.name));
	this.xhr.setRequestHeader('X-CSRFToken', CSRF_TOKEN);
	this.xhr.send(body);
	body = null;
    }
});

var Watcher = new Class({
    Extends: Model,

    defaults: {
	pk: 'email',
	email: '',
	last_notification: new Date(),
	created: new Date()
    },

    save: function() {
	var this_ = this;

	var req = new Request.JSON({
	    url: 'watch/',
	    headers: { 'X-CSRFToken': CSRF_TOKEN },
	    data: {
		email: this.email,
	    },
	    onSuccess: function(response) {
		this_.update(response.watcher);
		this_.fireEvent('save');
	    },
	    onFailure: function(xhr) {
		if (xhr.status == 403) {
		    this_.fireEvent('error', {
			label: 'Session expired',
			message_html: 'Please log in again'
		    });
		} else if (xhr.status != 0) {
		    try {
			var response = JSON.decode(xhr.responseText);
			this_.fireEvent('error', response);
		    } catch(e) {
			this_.fireEvent('error', {
			    message: xhr.statusText,
			    details: xhr.responseText
			});
		    }
		} else {
		    this_.fireEvent('error', {
			message: 'Request failed'
		    });
		}
	    }
	});
	req.send();
    },

    del: function() {
	var this_ = this;
	var req = new Request.JSON({
	    url: 'unwatch/',
	    headers: { 'X-CSRFToken': CSRF_TOKEN },
	    data: { email: this.email },
	    onFailure: function(xhr) {
		if (xhr.status == 403) {
		    this_.fireEvent('error', {
			label: 'Session expired',
			message_html: 'Please log in again'
		    });
		} else if (xhr.status != 0) {
		    this_.fireEvent('error', {
			message: xhr.statusText,
			details: xhr.responseText
		    });
		} else {
		    this_.fireEvent('error', {
			message: 'Request failed'
		    });
		}
	    }
	}).send();

	this_.remove();
    }
});
<commit_msg>Allow chunks to be larger than 64MB.<commit_after>/*
 * Copyright (c) 2012 Peter Kuma

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var Model = new Class({
    Implements: Events,

    defaults: {
	pk: 'id'
    },

    initialize: function(attributes) {
        for (var attr in this.defaults) {
            this[attr] = this.defaults[attr];
        }
	for (var attr in attributes) {
	    this[attr] = attributes[attr];
	}
    },

    set: function(attr, value) {
	if (this[attr] != value) {
	    this[attr] = value;
	    this.fireEvent('change');
	}
    },

    get: function(attr) {
        return this[attr];
    },

    update: function(json) {
        for (var attr in json) {
	    this[attr] = json[attr];
	}
	this.fireEvent('change');
    },

    remove: function() {
	this.fireEvent('remove');
    }
});

var Item = new Class({
    Extends: Model,

    defaults: {
	id: -1,
	type: 'complete', // 'pending', 'unfinished', 'stale', 'complete'.
        name: '',
	url: '',
        size: 0,
        size_total: 0,
        status: 'READY', // 'READY', 'UPLOADING', 'STALE'.
        created: new Date(),
        uploaded: new Date(),
        modified: new Date()
    },

    initialize: function(attributes) {
	this.parent(attributes);
	this.id = uuid();
    },

    update: function(json) {
	if (this.type == 'pending')
	    ; // Do nothing.
	else if (json.status == 'READY')
	    this.type = 'complete';
	else if (json.status == 'UPLOADING')
	    this.type = 'unfinished';
	else if (json.status == 'STALE')
	    this.type = 'stale';

	for (var attr in json) {
	    if (this.type == 'pending' && (attr == 'status' || attr == 'size'))
		continue;
	    this[attr] = json[attr];
	}
	this.modified = new Date().parse(json.modified);
	this.uploaded = new Date().parse(json.uploaded);
	this.created = new Date().parse(json.created);

	this.fireEvent('change');
    },

    remove: function() {
	if (this.xhr) this.xhr.abort();
	//this.parent();
	this.fireEvent('remove');
    },

    del: function() {
	if (this.xhr) this.xhr.abort();

	var xhr = new XMLHttpRequest();
	xhr.open('POST', 'delete/' + this.id + '/');
	xhr.setRequestHeader('X-CSRFToken', CSRF_TOKEN);

	var this_ = this;
	xhr.onreadystatechange = function(e) {
	    if (this.readyState == this.DONE) {
		this_.remove();
	    }
	};
	xhr.send('csrfmiddlewaretoken='+CSRF_TOKEN);

	this.remove();
    },

    upload: function(data, offset, len) {
	if (typeof offset == 'undefined') offset = this.size;
	if (typeof data == 'string') this.set('size_total', data.length);
	if (data.size) this.set('size_total', data.size);
	if (typeof len == 'undefined') len = CHUNK_SIZE;
	if (this.size + len > this.size_total)
	    len = this.size_total - this.size;

	this.set('type', 'pending');

	this.xhr = new XMLHttpRequest();
        this.xhr.open('POST', 'upload/' + this.id + '/');

	var this_ = this;
	var startTime = new Date().getTime();

	if (this.xhr.upload) {
	    this.xhr.upload.addEventListener('progress', function(e) {
		if (!this_.size_total) this_.set('size_total', e.total);
		if (!len) len = this_.size_total;
		this_.set('size', offset + e.position/e.total*len);
	    }, false);

	    this.xhr.upload.addEventListener('load', function(e) {
		if (typeof data == 'string') this_.set('size', offset + len);
	    }, false);
	}

	this.xhr.onreadystatechange = function(e) {
	    if (this.readyState == 4) {
		try {
		    var response = JSON.decode(this.responseText);
		} catch(e) {
		    this_.fireEvent('error', {
			label: 'Upload failed',
			message: 'The server responded with an invalid message',
			details: this.responseText
		    });
		}

		if (this.status == 200 && response.status == 'success') {
		    this_.size = offset + len;
		    this_.update(response.item);

		    if (this_.size < this_.size_total) {
			elapsedTime = new Date().getTime() - startTime;
			if (elapsedTime < CHUNK_UPLOAD_LOW*1000) {
			    len *= 2;
			    //if (len > 64*1024*1024) len = 64*1024*1024;
			    //console.log('Doubling chunk size');
			}
			if (elapsedTime > CHUNK_UPLOAD_HIGH*1000) {
			    len /= 2;
			    if (len < 32*1024) len = 32*1024;
			    //console.log('Halving chunk size');
			}

			// Upload the next chunk.
			this_.upload(data, this_.size, len);
		    } else {
			// We are done.
			this_.set('type', 'complete');
		    }
		} else if (this.status == 403) {
		    this_.fireEvent('error', {
			label: 'Your session expired',
			message_html: 'Please log in again'
		    });
		} else if (this.status != 0) {
		    // Revert to the original size as the chunk upload failed.
		    this_.set('size', offset);
		    if (response) {
			this_.fireEvent('error', {
			    label: response.error_label,
			    message: response.error_message
			});
		    } else {
			this_.fireEvent('error', {
			    label: 'Application Error',
			    message: this.status+' '+this.statusText,
			    details: this.responseText
			});
		    }
		} else {
		    // Revert to the original size as the chunk upload failed.
		    this_.set('size', offset);
		    this_.fireEvent('error', {
			label: 'Upload failed',
			message: 'The upload was terminated before completion'
		    });
		}
	    }
	};

	if (typeof File != 'undefined' && data instanceof File && typeof FormData != 'undefined') {
	    if (data.mozSlice) var chunk = data.mozSlice(offset, offset + len);
	    else if (data.webkiteSlice) var chunk = data.webkitSlice(offset, offset + len);
	    else var chunk = data.slice(offset, offset + len);
	    var body = new FormData();
	    body.append('file', chunk);
	} else if(typeof data == 'string') {
	    var boundary = 'xxxxxxxxxxxxxxxxxxxx';
	    var body = '--' + boundary + '\r\n';
	    body += 'Content-Disposition: form-data; name="file"; filename="' + encodeURIComponent(this.name) + '"\r\n';
	    body += 'Content-Type: application/octet-stream\r\n';
	    body += '\r\n';
	    body += window.btoa(data.substring(offset, offset + len)) + '\r\n';
	    body += '--' + boundary + '--\r\n';
	    this.xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
	    this.xhr.setRequestHeader('X-File-Encoding', 'base64');
	} else {
	    var body = data;
	    len = this.size_total - offset;
	}

	if (this.size_total) this.xhr.setRequestHeader('X-File-Size', this.size_total);
	this.xhr.setRequestHeader('X-File-Offset', offset);
	this.xhr.setRequestHeader('X-File-Name', encodeURIComponent(this.name));
	this.xhr.setRequestHeader('X-CSRFToken', CSRF_TOKEN);
	this.xhr.send(body);
	body = null;
    }
});

var Watcher = new Class({
    Extends: Model,

    defaults: {
	pk: 'email',
	email: '',
	last_notification: new Date(),
	created: new Date()
    },

    save: function() {
	var this_ = this;

	var req = new Request.JSON({
	    url: 'watch/',
	    headers: { 'X-CSRFToken': CSRF_TOKEN },
	    data: {
		email: this.email,
	    },
	    onSuccess: function(response) {
		this_.update(response.watcher);
		this_.fireEvent('save');
	    },
	    onFailure: function(xhr) {
		if (xhr.status == 403) {
		    this_.fireEvent('error', {
			label: 'Session expired',
			message_html: 'Please log in again'
		    });
		} else if (xhr.status != 0) {
		    try {
			var response = JSON.decode(xhr.responseText);
			this_.fireEvent('error', response);
		    } catch(e) {
			this_.fireEvent('error', {
			    message: xhr.statusText,
			    details: xhr.responseText
			});
		    }
		} else {
		    this_.fireEvent('error', {
			message: 'Request failed'
		    });
		}
	    }
	});
	req.send();
    },

    del: function() {
	var this_ = this;
	var req = new Request.JSON({
	    url: 'unwatch/',
	    headers: { 'X-CSRFToken': CSRF_TOKEN },
	    data: { email: this.email },
	    onFailure: function(xhr) {
		if (xhr.status == 403) {
		    this_.fireEvent('error', {
			label: 'Session expired',
			message_html: 'Please log in again'
		    });
		} else if (xhr.status != 0) {
		    this_.fireEvent('error', {
			message: xhr.statusText,
			details: xhr.responseText
		    });
		} else {
		    this_.fireEvent('error', {
			message: 'Request failed'
		    });
		}
	    }
	}).send();

	this_.remove();
    }
});
<|endoftext|>


<commit_before>var React = require('react'),
	DOM = React.DOM;

var languagesComponent = require(__dirname + '/Languages.js');

module.exports = React.createClass({

	propTypes: {
		jsonResume: React.PropTypes.object
	},

	render: function () {

		var components = [];

		components.push(
			DOM.div({ className: 'page-header' },
				DOM.h1(null, [
					DOM.span(null, 'Resume of ' + this.props.jsonResume.basics.name),
					DOM.small(null, ' ' + this.props.jsonResume.basics.label)
				])
			)
		);

		// Optional, human languages component.
		if (this.props.jsonResume.languages && this.props.jsonResume.languages.length > 0) {
			components.push(languagesComponent({
				languages: this.props.jsonResume.languages
			}));
		}

		return DOM.div(
			{ className: 'container-fluid' },
			components
		);

	}

});<commit_msg>Added summary to JsonResume.<commit_after>var React = require('react'),
	DOM = React.DOM;

var languagesComponent = require(__dirname + '/Languages');
var plainTextComponent = require(__dirname + '/PlainText');

module.exports = React.createClass({

	propTypes: {
		jsonResume: React.PropTypes.object
	},

	render: function () {

		var components = [];

		components.push(
			DOM.div({ className: 'page-header' },
				DOM.h1(null, [
					DOM.span(null, 'Resume of ' + this.props.jsonResume.basics.name),
					DOM.small(null, ' ' + this.props.jsonResume.basics.label)
				])
			)
		);

		components.push(
			plainTextComponent({ title: 'About', body: this.props.jsonResume.basics.summary })
		);

		// Optional, human languages component.
		if (this.props.jsonResume.languages && this.props.jsonResume.languages.length > 0) {
			components.push(languagesComponent({
				languages: this.props.jsonResume.languages
			}));
		}

		return DOM.div(
			{ className: 'container-fluid' },
			components
		);

	}

});<|endoftext|>


<commit_before>import React from 'react';
import { TouchableOpacity } from 'react-native';
import { Container, Content, Thumbnail, Card, CardItem, Spinner } from 'native-base';

const citrusYellow = '#F6E49C';
const citrusPink = '#FC8A67';
const citrusOrange = '#E88931';
const citrusGreen = '#00A229';
const periwinkle = '#686CA6'
const lightYellow = '#fbf4d7'

const styles = {
  card: {
    margin: 10
  },
  cardItem: {
    backgroundColor: lightYellow
  },
  container: {
    backgroundColor: citrusYellow,
    marginBottom: 50
  },
  thumbnail: {
    width: 300,
    height: 300,
    marginLeft: 2
  }
}

export default function Meal (props) {
    return (
     <Container style={styles.container}>
      <Content>
        {
        props.meals && props.meals.length ?
        props.meals.map((meal, i) => {
            return (
              <Card style={styles.card} key={i}>
                <CardItem bordered style={styles.cardItem}>
                  <TouchableOpacity onPress={() => props.handleMealClick(meal)}>
                    <Thumbnail style={styles.thumbnail}  source={{uri: meal.photoUrl}} />
                  </TouchableOpacity>
                 </CardItem>
               </Card>
              )
          }) :
        <Spinner color={citrusPink} />
      }
      </Content>
      </Container>
    )
  }

<commit_msg>added date separators to home view<commit_after>import React from 'react';
import { TouchableOpacity, Text, View } from 'react-native';
import { Container, Content, Thumbnail, Card, CardItem, Spinner, Separator } from 'native-base';
import moment from 'moment';

const citrusYellow = '#F6E49C';
const citrusPink = '#FC8A67';
const citrusOrange = '#E88931';
const citrusGreen = '#00A229';
const periwinkle = '#686CA6'
const lightYellow = '#fbf4d7'

const styles = {
  card: {
    margin: 10
  },
  cardItem: {
    backgroundColor: lightYellow
  },
  container: {
    backgroundColor: citrusYellow,
    marginBottom: 50
  },
  thumbnail: {
    width: 300,
    height: 300,
    marginLeft: 2
  }
}

//Moment(this.state.date).format('MMMM DD YYYY')

export default function Meal (props) {

    let oldDate = ''

    const renderSeparator = (date) => {
      if (date !== oldDate){
        oldDate = date;
        return ( <View style={{backgroundColor: citrusPink}}>
                  <Text style={{textAlign: 'center', color: 'white'}}>{date}</Text>
                </View>)
      }
    }

    return (
     <Container style={styles.container}>
      <Content>
        {

        props.meals && props.meals.length ?
        props.meals.map((meal, i) => {
          let date = meal.created_at.slice(0,10)
          date = moment(date).format('MMM DD YYYY')

            return (
              <View key={i}>
              {renderSeparator(date)
              }
              <Card style={styles.card} >
                <CardItem bordered style={styles.cardItem}>
                  <TouchableOpacity onPress={() => props.handleMealClick(meal)}>
                    <Thumbnail style={styles.thumbnail}  source={{uri: meal.photoUrl}} />
                  </TouchableOpacity>
                 </CardItem>
               </Card>
                </View>
              )
          }) :
        <Spinner color={citrusPink} />
      }
      </Content>
      </Container>
    )
  }

<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import styled from 'styled-components'

const Wrapper = styled.div`
  border-radius: 8px;
  box-shadow: rgba(0,0,0,0.4) 0 9px 20px;
  background: white;
`

const Link = styled.a`
  display: block;
  border-radius: 8px;
  height: 21vh;
  background-image: url(${props => props.image});
  background-repeat: no-repeat;
  background-size: cover;
  position: relative;
  overflow: hidden;
  text-decoration: none;
`

const Header = styled.h3`
  margin: 0;
  color: white;
  font-size: 18px;
  position: absolute;
  padding: 10px 10px 0 10px;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: linear-gradient(to bottom, black, transparent);
  text-shadow: black 0 2px 4px;
`

const MediumPost = ({ url, title, image }) =>
  <Wrapper>
    <Link image={image} href={url} target="_blank">
      {title}
    </Link>
  </Wrapper>

MediumPost.propTypes = {
  url: PropTypes.object.isRequired,
  title: PropTypes.string.isRequired,
  image: PropTypes.string.isRequired,
}

export default MediumPost
<commit_msg>Update MediumPost.js<commit_after>import PropTypes from 'prop-types'
import styled from 'styled-components'

const Wrapper = styled.div`
  border-radius: 8px;
  box-shadow: rgba(0,0,0,0.4) 0 9px 20px;
  background: white;
`

const Link = styled.a`
  display: block;
  border-radius: 8px;
  height: 21vh;
  background-image: url(${props => props.image});
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
  position: relative;
  overflow: hidden;
  text-decoration: none;
`

const Header = styled.h3`
  margin: 0;
  color: white;
  font-size: 18px;
  position: absolute;
  padding: 10px 10px 0 10px;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: linear-gradient(to bottom, black, transparent);
  text-shadow: black 0 2px 4px;
`

const MediumPost = ({ url, title, image }) =>
  <Wrapper>
    <Link image={image} href={url} target="_blank">
      {title}
    </Link>
  </Wrapper>

MediumPost.propTypes = {
  url: PropTypes.object.isRequired,
  title: PropTypes.string.isRequired,
  image: PropTypes.string.isRequired,
}

export default MediumPost
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var tasks = fs.readdirSync('./gulp/tasks/');
var gulp = require('gulp');

require('./config');

var karmaConfig = {};
require('./../karma.conf.js')({
    set: function(conf) {
        karmaConfig = conf;
    }
});

gulp.task('release', function(cb) {
    cb(); // no op for version task
});

gulp.task('testsNoWatch', ['karma']); // need this task name for version task

require('gulp-tasks-riq/version')();

require('gulp-tasks-riq/karma')({
    karmaConf: karmaConfig,
    configure: function() {

    },
    testGlobs: [
        global.PUBLIC_WEBAPP_PATH + 'src/**/*.spec.js'
    ]
});

tasks.forEach(function(task) {
    require('./tasks/' + task);
});<commit_msg>change root<commit_after>'use strict';

var fs = require('fs');
var tasks = fs.readdirSync('./gulp/tasks/');
var gulp = require('gulp');

require('./config');

var karmaConfig = {};
require('./../karma.conf.js')({
    set: function(conf) {
        karmaConfig = conf;
    }
});

gulp.task('release', function(cb) {
    cb(); // no op for version task
});

gulp.task('testsNoWatch', ['karma']); // need this task name for version task

require('gulp-tasks-riq/version')();

require('gulp-tasks-riq/karma')({
    karmaConf: karmaConfig,
    configure: function() {

    },
    testGlobs: [
        'src/**/*.spec.js'
    ]
});

tasks.forEach(function(task) {
    require('./tasks/' + task);
});<|endoftext|>


<commit_before>import React from 'react';
import Hamburger from './Hamburger';
import NavList from './NavList';

class Navigation extends React.Component {
  constructor(props) {
    super(props);
    this.state = { open: false };
  }

  componentDidMount() {
    window.addEventListener('keydown', this.handleKey, true);
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.handleKey, true);
  }

  handleKey = e => {
    if (e.keyCode === 27) {
      this.setState({ open: false });
    }
  };

  toggleClass = () => {
    this.setState({ open: !this.state.open });
  };

  blockClicks = e => {
    if (e.target.tagName !== 'A') {
      e.stopPropagation();
    }
  };

  render() {
    const { open } = this.state;
    return (
      <nav className={open ? 'open' : ''} onClick={this.toggleClass}>
        <Hamburger onClick={this.toggleClass} open={open} />
        <NavList blockClicks={this.blockClicks} />
        <style jsx>{`
          nav::before {
            content: '';
            background: rgba(0, 0, 0, 0.4);
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 2;
            visibility: hidden;
            opacity: 0;
            transition: 500ms all ease-in-out;
            will-change: opacity;
          }
          nav.open::before {
            visibility: visible;
            opacity: 1;
          }
        `}</style>
      </nav>
    );
  }
}

export default Navigation;
<commit_msg>remove Navigation constructor<commit_after>import React from 'react';
import Hamburger from './Hamburger';
import NavList from './NavList';

class Navigation extends React.Component {
  state = {
    open: false
  };

  componentDidMount() {
    window.addEventListener('keydown', this.handleKey, true);
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.handleKey, true);
  }

  handleKey = e => {
    if (e.keyCode === 27) {
      this.setState({ open: false });
    }
  };

  toggleClass = () => {
    this.setState({ open: !this.state.open });
  };

  blockClicks = e => {
    if (e.target.tagName !== 'A') {
      e.stopPropagation();
    }
  };

  render() {
    const { open } = this.state;
    return (
      <nav className={open ? 'open' : ''} onClick={this.toggleClass}>
        <Hamburger onClick={this.toggleClass} open={open} />
        <NavList blockClicks={this.blockClicks} />
        <style jsx>{`
          nav::before {
            content: '';
            background: rgba(0, 0, 0, 0.4);
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 2;
            visibility: hidden;
            opacity: 0;
            transition: 500ms all ease-in-out;
            will-change: opacity;
          }
          nav.open::before {
            visibility: visible;
            opacity: 1;
          }
        `}</style>
      </nav>
    );
  }
}

export default Navigation;
<|endoftext|>


<commit_before>'use strict';

var fs   = require('fs');
var path = require('path');

var files = fs.readdirSync(path.join(__dirname, 'tasks'));

files
  .filter(function(file) { return !!file.match(/\.js$/); })
  .forEach(function(file) { require('./tasks/' + file); });
<commit_msg>chore(gulp): add default task<commit_after>'use strict';

var fs   = require('fs');
var path = require('path');
var gulp = require('gulp');

var files = fs.readdirSync(path.join(__dirname, 'tasks'));

files
  .filter(function(file) { return !!file.match(/\.js$/); })
  .forEach(function(file) { require('./tasks/' + file); });

gulp.task('default', [
  'browserify:common',
  'browserify:bundle',
  'less'
]);
<|endoftext|>


<commit_before>function calculateSteps(instructions) {
    var currentLocation = [0, 0],
        allStepsTaken = [
            // Include a copy of the origin
            currentLocation.slice()
        ],
        // 0 = North, 1 = East, 2 = South, 3 = West
        direction = 0;

    instructions.forEach(function (instruction) {
        var turn = instruction.charAt(0),
            steps = parseInt(instruction.substring(1), 10),
            previousLocation = currentLocation.slice(),
            x = previousLocation[0],
            y = previousLocation[1];

        if (turn === 'R') {
            direction++;
        } else {
            direction += 3;
        }

        if (direction > 3) {
            direction -= 4;
        }

        for (var i = 0; i < steps; i++) {
            switch (direction) {
                case 0:
                    x++;
                    break;
                case 1:
                    y++;
                    break;
                case 2:
                    x--;
                    break;
                case 3:
                    y--;
                    break;
            }

            allStepsTaken.push([x, y]);
        }

        currentLocation = [x, y];
    }, this);

    return {
        allLocations: allStepsTaken,
        currentLocation: currentLocation
    };
}

function puzzle1(instructions) {
    var calculation = calculateSteps(instructions),
        finalLocation = calculation.currentLocation;

    var blocksVertical = Math.abs(finalLocation[0]),
        blocksHorizontal = Math.abs(finalLocation[1]),
        blocksTotal = blocksVertical + blocksHorizontal;
    return blocksTotal;
}

function puzzle2(instructions) {
    var calculation = calculateSteps(instructions),
        locations = calculation.allLocations,
        locationCrossedTwice = null;

    // Cycle through all locations looking for a repeat
    for (var l1 = 0; l1 < locations.length && !locationCrossedTwice; l1++) {
        for (var l2 = 0; l2 < l1 && !locationCrossedTwice; l2++) {
            if (locations[l1][0] === locations[l2][0] && locations[l1][1] === locations[l2][1]) {
                locationCrossedTwice = locations[l2];
            }
        }
    }

    var blocksVertical = Math.abs(locationCrossedTwice[0]),
        blocksHorizontal = Math.abs(locationCrossedTwice[1]),
        blocksTotal = blocksVertical + blocksHorizontal;
    return blocksTotal;
}

module.exports = function () {
    console.log('---DAY 01-----------------')
    var rawInput = 'R4, R1, L2, R1, L1, L1, R1, L5, R1, R5, L2, R3, L3, L4, R4, R4, R3, L5, L1, R5, R3, L4, R1, R5, L1, R3, L2, R3, R1, L4, L1, R1, L1, L5, R1, L2, R2, L3, L5, R1, R5, L1, R188, L3, R2, R52, R5, L3, R79, L1, R5, R186, R2, R1, L3, L5, L2, R2, R4, R5, R5, L5, L4, R5, R3, L4, R4, L4, L4, R5, L4, L3, L1, L4, R1, R2, L5, R3, L4, R3, L3, L5, R1, R1, L3, R2, R1, R2, R2, L4, R5, R1, R3, R2, L2, L2, L1, R2, L1, L3, R5, R1, R4, R5, R2, R2, R4, R4, R1, L3, R4, L2, R2, R1, R3, L5, R5, R2, R5, L1, R2, R4, L1, R5, L3, L3, R1, L4, R2, L2, R1, L1, R4, R3, L2, L3, R3, L2, R1, L4, R5, L1, R5, L2, L1, L5, L2, L5, L2, L4, L2, R3',
        splitInput = rawInput.split(', ');

    // Puzzle 1
    var puzzle1Answer = puzzle1(splitInput);
    console.log('--- Puzzle 1 - Answer: ' + puzzle1Answer + ' blocks away.');

    // Puzzle 2
    var puzzle2Answer = puzzle2(splitInput);
    console.log('--- Puzzle 2 - Answer: ' + puzzle2Answer + ' blocks away.');
};<commit_msg>Just returning the needed value<commit_after>function calculateSteps(instructions) {
    var currentLocation = [0, 0],
        allStepsTaken = [
            // Include a copy of the origin
            currentLocation.slice()
        ],
        // 0 = North, 1 = East, 2 = South, 3 = West
        direction = 0;

    instructions.forEach(function (instruction) {
        var turn = instruction.charAt(0),
            steps = parseInt(instruction.substring(1), 10),
            previousLocation = currentLocation.slice(),
            x = previousLocation[0],
            y = previousLocation[1];

        if (turn === 'R') {
            direction++;
        } else {
            direction += 3;
        }

        if (direction > 3) {
            direction -= 4;
        }

        for (var i = 0; i < steps; i++) {
            switch (direction) {
                case 0:
                    x++;
                    break;
                case 1:
                    y++;
                    break;
                case 2:
                    x--;
                    break;
                case 3:
                    y--;
                    break;
            }

            allStepsTaken.push([x, y]);
        }

        currentLocation = [x, y];
    }, this);

    return {
        allLocations: allStepsTaken,
        currentLocation: currentLocation
    };
}

function puzzle1(instructions) {
    var calculation = calculateSteps(instructions),
        finalLocation = calculation.currentLocation;

    var blocksVertical = Math.abs(finalLocation[0]),
        blocksHorizontal = Math.abs(finalLocation[1]),
        blocksTotal = blocksVertical + blocksHorizontal;
    return blocksTotal;
}

function puzzle2(instructions) {
    var calculation = calculateSteps(instructions),
        locations = calculation.allLocations,
        locationCrossedTwice = null;

    // Cycle through all locations looking for a repeat
    for (var l1 = 0; l1 < locations.length && !locationCrossedTwice; l1++) {
        for (var l2 = 0; l2 < l1 && !locationCrossedTwice; l2++) {
            if (locations[l1][0] === locations[l2][0] && locations[l1][1] === locations[l2][1]) {
                locationCrossedTwice = locations[l2];
            }
        }
    }

    var blocksVertical = Math.abs(locationCrossedTwice[0]),
        blocksHorizontal = Math.abs(locationCrossedTwice[1]),
        blocksTotal = blocksVertical + blocksHorizontal;
    return blocksTotal;
}

module.exports = function () {
    console.log('---DAY 01-----------------')
    var rawInput = 'R4, R1, L2, R1, L1, L1, R1, L5, R1, R5, L2, R3, L3, L4, R4, R4, R3, L5, L1, R5, R3, L4, R1, R5, L1, R3, L2, R3, R1, L4, L1, R1, L1, L5, R1, L2, R2, L3, L5, R1, R5, L1, R188, L3, R2, R52, R5, L3, R79, L1, R5, R186, R2, R1, L3, L5, L2, R2, R4, R5, R5, L5, L4, R5, R3, L4, R4, L4, L4, R5, L4, L3, L1, L4, R1, R2, L5, R3, L4, R3, L3, L5, R1, R1, L3, R2, R1, R2, R2, L4, R5, R1, R3, R2, L2, L2, L1, R2, L1, L3, R5, R1, R4, R5, R2, R2, R4, R4, R1, L3, R4, L2, R2, R1, R3, L5, R5, R2, R5, L1, R2, R4, L1, R5, L3, L3, R1, L4, R2, L2, R1, L1, R4, R3, L2, L3, R3, L2, R1, L4, R5, L1, R5, L2, L1, L5, L2, L5, L2, L4, L2, R3',
        splitInput = rawInput.split(', ');

    // Puzzle 1
    var puzzle1Answer = puzzle1(splitInput);
    console.log('--- Puzzle 1 - Answer: ' + puzzle1Answer + '.');

    // Puzzle 2
    var puzzle2Answer = puzzle2(splitInput);
    console.log('--- Puzzle 2 - Answer: ' + puzzle2Answer + '.');
};<|endoftext|>


<commit_before>var TCM = TCM || {};

(function($) {

    TCM.addLoadingCSS = function(container) {
        var vertHeight = (parseInt(container.css('height'), 10) - parseInt(container.css('line-height'), 10)) / 2 + 'px',
            style = '';
        $('head').append(style);
    };

    TCM.addLoading = function(trigger, context) {
        $(context).find(trigger).click(function() {
            var container = $(this).closest(context).addClass('loading');
            TCM.addLoadingCSS(container);
        });
    };

    var filtering = function() {
        var button = $('#filter .visual .content button[type="submit"]').hide(),
            input = $('#filter .visual .filter-group input[type="checkbox"]').each(function() {
                $(this).data('originallyChecked', $(this).is(':checked'));
            }),
            textbox = $('#filter .textual #text-filter'),
            typedText = textbox.val(),
            suggestionList = $('#filter .textual .suggest').hide(),
            keywordGroups = $('#filter .visual .filter-group.keyword'),
            notKeywordGroups = $('#filter .visual .filter-group:not(.keyword)'),
            selected,
            updateButton = function() {
                if (input.filter(function() {
                    return $(this).data('state') === 'changed';
                }).length) {
                    button.fadeIn('fast');
                } else {
                    button.fadeOut('fast');
                }
            };

        input.live('change', function() {
            if ($(this).data('originallyChecked') !== $(this).is(':checked')) {
                $(this).data('state', 'changed');
            } else {
                $(this).data('state', null);
            }
            updateButton();
        });

        textbox.keyup(function(event) {
            if ($(this).val() !== typedText) {
                typedText = $(this).val();
                suggestionList.empty();
                if ($(this).val().length) {
                    var relevantFilters = notKeywordGroups.find('input[type="checkbox"]:not(:checked)').parent('li').filter(function() {
                            return $(this).children('label').html().toLowerCase().indexOf(typedText.toLowerCase()) !== -1;
                        });
                    relevantFilters.each(function() {
                        var typedIndex = $(this).children('label').html().toLowerCase().indexOf(typedText.toLowerCase()),
                            preText = $(this).children('label').html().substring(0, typedIndex),
                            postText = $(this).children('label').html().substring(typedIndex + typedText.length),
                            type = $(this).children('input').attr('name'),
                            id = $(this).children('input').attr('id'),
                            newHTML = '
' + preText + '' + typedText + '' + postText + ' [' + type + ']
';
                        suggestionList.append(newHTML);
                    });
                    keywordGroups.each(function() {
                        var type = $(this).children('h5').html(),
                            name = $(this).data('name'),
                            keywordHTML = '
' + typedText + ' [' + type + ']
';
                        if (!$(this).find('input[type="checkbox"][value="' + typedText + '"]:checked').length) {
                            suggestionList.append(keywordHTML);
                        }
                    });
                    suggestionList.find('li:first-child a').addClass('selected');
                }
            }
        }).keydown(function(event) {
            if (event.keyCode === 38) {
                event.preventDefault();
                if (!suggestionList.find('.selected').parent().is(':first-child')) {
                    suggestionList.find('.selected').removeClass('selected').parent().prev().children('a').addClass('selected');
                }
                return false;
            }
            if (event.keyCode === 40) {
                event.preventDefault();
                if (!suggestionList.find('.selected').parent().is(':last-child')) {
                    suggestionList.find('.selected').removeClass('selected').parent().next().children('a').addClass('selected');
                }
                return false;
            }
            if (event.keyCode === 13) {
                event.preventDefault();
                suggestionList.find('.selected').click();
                suggestionList.show();
                return false;
            }
            if (event.keyCode === 9) {
                var thisFilterName = input.filter('#' + suggestionList.find('.selected').data('id')).siblings('label').html();
                if (thisFilterName) {
                    event.preventDefault();
                    textbox.val(thisFilterName);
                    return false;
                }
            }
            return true;
        });

        textbox.focus(function() {
            suggestionList.show();
            textbox.data('clicked', false);
        }).blur(function() {
            function hideList() {
                if (textbox.data('clicked') !== true) {
                    suggestionList.hide();
                }
            }
            window.setTimeout(hideList, 150);
        });

        suggestionList.hover(function() {
            selected = $(this).find('.selected').removeClass('selected');
        }, function() {
            selected.addClass('selected');
        });

        suggestionList.find('a').live('mousedown', function() {
            textbox.data('clicked', true);
        }).live('click', function() {
            if ($(this).data('class') === 'keyword') {
                var name = $(this).data('name'),
                    thisGroup = keywordGroups.filter(function() {
                        return $(this).data('name') === name;
                    }),
                    existingKeyword = thisGroup.find('input[type="checkbox"][value="' + typedText + '"][name="' + name + '"]'),
                    index = thisGroup.find('li').length + 1,
                    newHTML =
                        '
' +
                            '<input type="checkbox" name="' + name + '" value="' + typedText + '" id="id-' + name + '-' + index + '" checked="checked" data-state="changed" data-originallyChecked="false">' +
                            '' + typedText + '' +
                        '
';
                if (existingKeyword.length) {
                    existingKeyword.attr('checked', 'checked');
                    if (existingKeyword.data('originallyChecked') !== existingKeyword.is(':checked')) {
                        existingKeyword.data('state', 'changed');
                    }
                } else {
                    thisGroup.removeClass('empty').children('ul').append(newHTML);
                    input = input.add('#id-' + name + '-' + index);
                }
            } else {
                var thisFilter = input.filter('#' + $(this).data('id')).attr('checked', 'checked');
                if (thisFilter.data('originallyChecked') !== thisFilter.is(':checked')) {
                    thisFilter.data('state', 'changed');
                }
            }
            updateButton();
            textbox.data('clicked', false).val(null);
            typedText = null;
            suggestionList.empty().hide();
            return false;
        });
    };

    $(function() {
        filtering();
        $('input[placeholder], textarea[placeholder]').placeholder();
        $('input:not([type=radio], [type=checkbox]), textarea').blur(
            function() {
                $(this).addClass('hadfocus');
            }
        );
        $('#filter .toggle a').click(
            function() {
                $('#filter .visual').toggleClass('compact').toggleClass('expanded');
                return false;
            }
        );
        if ($('html').hasClass('no-details')) {
            $('details').html5accordion('summary');
        }
        $('.details:not(html)').html5accordion('.summary');
        // $('.subnav .findertoggle').click(function() {
        //     $(this).add('.subnav .finder').toggleClass('expanded').toggleClass('compact');
        //     return false;
        // });
        // $('.subnav').html5finder( {
        //     loading: true,
        //     horizontalScroll: true,
        //     scrollContainer: '.finder.expanded',
        //     headerSelector: 'header.listordering',
        //     sectionSelector: '.col',
        //     sectionContentSelector: '.colcontent',
        //     sectionClasses: [
        //         'products',
        //         'cycles',
        //         'runs',
        //         'cases',
        //         'results'
        //     ],
        //     sectionItemSelectors: [
        //         'input[name="product"]',
        //         'input[name="cycle"]',
        //         'input[name="run"]',
        //         'input[name="case"]',
        //         'input[name="result"]'
        //     ]
        // });
        $('.selectruns').html5finder( {
            loading: true,
            ellipsis: true,
            headerSelector: '.listordering',
            sectionSelector: '.col',
            sectionContentSelector: '.colcontent',
            sectionClasses: [
                'products',
                'cycles',
                'runs'
            ],
            sectionItemSelectors: [
                'input[name="product"]',
                'input[name="testcycle"]',
                'input[name="testrun"]'
            ],
            callback: function() {
                $('.selectruns + .environment').slideUp('fast');
            },
            lastChildCallback: function(choice) {
                var environments = $('.selectruns + .environment').css('min-height', '169px').addClass('loading').slideDown('fast'),
                    ajaxUrl = $(choice).data("sub-url");
                TCM.addLoadingCSS(environments);
                $.get(ajaxUrl, function(data) {
                    environments.html(data);
                    $('.loadingCSS').detach();
                    $('.loading').removeClass('loading');
                });
            }
        });
        $('.selectruns + .environment.empty').hide();
    });

    $(window).load(function() {
        $('#listcontent .items .title').ellipsis(true, 250);
    });

})(jQuery);
<commit_msg>js filtering autofocus on textbox and add fake placeholder on initial page load<commit_after>var TCM = TCM || {};

(function($) {

    TCM.addLoadingCSS = function(container) {
        var vertHeight = (parseInt(container.css('height'), 10) - parseInt(container.css('line-height'), 10)) / 2 + 'px',
            style = '';
        $('head').append(style);
    };

    TCM.addLoading = function(trigger, context) {
        $(context).find(trigger).click(function() {
            var container = $(this).closest(context).addClass('loading');
            TCM.addLoadingCSS(container);
        });
    };

    var filtering = function() {
        var button = $('#filter .visual .content button[type="submit"]').hide(),
            input = $('#filter .visual .filter-group input[type="checkbox"]').each(function() {
                $(this).data('originallyChecked', $(this).is(':checked'));
            }),
            textbox = $('#filter .textual #text-filter'),
            typedText = textbox.val(),
            placeholder = textbox.attr('placeholder'),
            suggestionList = $('#filter .textual .suggest').hide(),
            keywordGroups = $('#filter .visual .filter-group.keyword'),
            notKeywordGroups = $('#filter .visual .filter-group:not(.keyword)'),
            selected,
            removeFakePlaceholder = function() {
                if (textbox.val() === placeholder) {
                    textbox.val(null);
                }
                textbox.removeClass('placeholder');
            },
            updateButton = function() {
                if (input.filter(function() {
                    return $(this).data('state') === 'changed';
                }).length) {
                    button.fadeIn('fast');
                } else {
                    button.fadeOut('fast');
                }
            };

        input.live('change', function() {
            if ($(this).data('originallyChecked') !== $(this).is(':checked')) {
                $(this).data('state', 'changed');
            } else {
                $(this).data('state', null);
            }
            updateButton();
        });

        textbox.keyup(function(event) {
            if ($(this).val() !== typedText && $(this).val() !== placeholder) {
                typedText = $(this).val();
                suggestionList.empty();
                if ($(this).val().length) {
                    var relevantFilters = notKeywordGroups.find('input[type="checkbox"]:not(:checked)').parent('li').filter(function() {
                            return $(this).children('label').html().toLowerCase().indexOf(typedText.toLowerCase()) !== -1;
                        });
                    relevantFilters.each(function() {
                        var typedIndex = $(this).children('label').html().toLowerCase().indexOf(typedText.toLowerCase()),
                            preText = $(this).children('label').html().substring(0, typedIndex),
                            postText = $(this).children('label').html().substring(typedIndex + typedText.length),
                            type = $(this).children('input').attr('name'),
                            id = $(this).children('input').attr('id'),
                            newHTML = '
' + preText + '' + typedText + '' + postText + ' [' + type + ']
';
                        suggestionList.append(newHTML);
                    });
                    keywordGroups.each(function() {
                        var type = $(this).children('h5').html(),
                            name = $(this).data('name'),
                            keywordHTML = '
' + typedText + ' [' + type + ']
';
                        if (!$(this).find('input[type="checkbox"][value="' + typedText + '"]:checked').length) {
                            suggestionList.append(keywordHTML);
                        }
                    });
                    suggestionList.find('li:first-child a').addClass('selected');
                }
            }
        }).keydown(function(event) {
            if (event.keyCode === 38) {
                event.preventDefault();
                if (!suggestionList.find('.selected').parent().is(':first-child')) {
                    suggestionList.find('.selected').removeClass('selected').parent().prev().children('a').addClass('selected');
                }
                return false;
            }
            if (event.keyCode === 40) {
                event.preventDefault();
                if (!suggestionList.find('.selected').parent().is(':last-child')) {
                    suggestionList.find('.selected').removeClass('selected').parent().next().children('a').addClass('selected');
                }
                return false;
            }
            if (event.keyCode === 13) {
                event.preventDefault();
                suggestionList.find('.selected').click();
                suggestionList.show();
                return false;
            }
            if (event.keyCode === 9) {
                var thisFilterName = input.filter('#' + suggestionList.find('.selected').data('id')).siblings('label').html();
                if (thisFilterName) {
                    event.preventDefault();
                    textbox.val(thisFilterName);
                    return false;
                }
            }
            return true;
        }).keypress(function(event) {
            if (typeof event.which == "undefined" || event.which > 0) {
                // IE returns undefined, but only fires keypress events for printable keys.
                // In other browsers except old versions of WebKit, evt.which is
                // only greater than zero if the keypress is a printable key.
                // We also need to filter out backspace and ctrl/alt/meta key combinations:
                if (!event.ctrlKey && !event.metaKey && !event.altKey && event.which !== 13) {
                    removeFakePlaceholder();
                }
            }
        });

        textbox.focus(function() {
            suggestionList.show();
            textbox.data('clicked', false);
            if (textbox.val().length === 0 && textbox.hasClass('placeholder')) {
                textbox.val(placeholder);
                textbox.get(0).setSelectionRange(0, 0);
            }
        }).blur(function() {
            function hideList() {
                if (textbox.data('clicked') !== true) {
                    suggestionList.hide();
                }
            }
            removeFakePlaceholder();
            window.setTimeout(hideList, 150);
        });

        suggestionList.hover(function() {
            selected = $(this).find('.selected').removeClass('selected');
        }, function() {
            selected.addClass('selected');
        });

        suggestionList.find('a').live('mousedown', function() {
            textbox.data('clicked', true);
        }).live('click', function() {
            if ($(this).data('class') === 'keyword') {
                var name = $(this).data('name'),
                    thisGroup = keywordGroups.filter(function() {
                        return $(this).data('name') === name;
                    }),
                    existingKeyword = thisGroup.find('input[type="checkbox"][value="' + typedText + '"][name="' + name + '"]'),
                    index = thisGroup.find('li').length + 1,
                    newHTML =
                        '
' +
                            '<input type="checkbox" name="' + name + '" value="' + typedText + '" id="id-' + name + '-' + index + '" checked="checked" data-state="changed" data-originallyChecked="false">' +
                            '' + typedText + '' +
                        '
';
                if (existingKeyword.length) {
                    existingKeyword.attr('checked', 'checked');
                    if (existingKeyword.data('originallyChecked') !== existingKeyword.is(':checked')) {
                        existingKeyword.data('state', 'changed');
                    }
                } else {
                    thisGroup.removeClass('empty').children('ul').append(newHTML);
                    input = input.add('#id-' + name + '-' + index);
                }
            } else {
                var thisFilter = input.filter('#' + $(this).data('id')).attr('checked', 'checked');
                if (thisFilter.data('originallyChecked') !== thisFilter.is(':checked')) {
                    thisFilter.data('state', 'changed');
                }
            }
            updateButton();
            textbox.data('clicked', false).val(null);
            typedText = null;
            suggestionList.empty().hide();
            return false;
        });

        textbox.addClass('placeholder').focus();
    };

    $(function() {
        filtering();
        $('input[placeholder], textarea[placeholder]').placeholder();
        $('input:not([type=radio], [type=checkbox]), textarea').blur(
            function() {
                $(this).addClass('hadfocus');
            }
        );
        $('#filter .toggle a').click(
            function() {
                $('#filter .visual').toggleClass('compact').toggleClass('expanded');
                return false;
            }
        );
        if ($('html').hasClass('no-details')) {
            $('details').html5accordion('summary');
        }
        $('.details:not(html)').html5accordion('.summary');
        // $('.subnav .findertoggle').click(function() {
        //     $(this).add('.subnav .finder').toggleClass('expanded').toggleClass('compact');
        //     return false;
        // });
        // $('.subnav').html5finder( {
        //     loading: true,
        //     horizontalScroll: true,
        //     scrollContainer: '.finder.expanded',
        //     headerSelector: 'header.listordering',
        //     sectionSelector: '.col',
        //     sectionContentSelector: '.colcontent',
        //     sectionClasses: [
        //         'products',
        //         'cycles',
        //         'runs',
        //         'cases',
        //         'results'
        //     ],
        //     sectionItemSelectors: [
        //         'input[name="product"]',
        //         'input[name="cycle"]',
        //         'input[name="run"]',
        //         'input[name="case"]',
        //         'input[name="result"]'
        //     ]
        // });
        $('.selectruns').html5finder( {
            loading: true,
            ellipsis: true,
            headerSelector: '.listordering',
            sectionSelector: '.col',
            sectionContentSelector: '.colcontent',
            sectionClasses: [
                'products',
                'cycles',
                'runs'
            ],
            sectionItemSelectors: [
                'input[name="product"]',
                'input[name="testcycle"]',
                'input[name="testrun"]'
            ],
            callback: function() {
                $('.selectruns + .environment').slideUp('fast');
            },
            lastChildCallback: function(choice) {
                var environments = $('.selectruns + .environment').css('min-height', '169px').addClass('loading').slideDown('fast'),
                    ajaxUrl = $(choice).data("sub-url");
                TCM.addLoadingCSS(environments);
                $.get(ajaxUrl, function(data) {
                    environments.html(data);
                    $('.loadingCSS').detach();
                    $('.loading').removeClass('loading');
                });
            }
        });
        $('.selectruns + .environment.empty').hide();
    });

    $(window).load(function() {
        $('#listcontent .items .title').ellipsis(true, 250);
    });

})(jQuery);
<|endoftext|>


<commit_before>import React from 'react';
import Hamburger from './Hamburger';
import NavList from './NavList';

class Navigation extends React.Component {
  constructor(props) {
    super(props);
    this.state = { open: false, hamburgerColor: 'white' };
    this.onClick = this.toggleClass.bind(this);
    this.blockClicks = this.blockClicks.bind(this);
    this.handleScroll = this.handleScroll.bind(this);
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll, true);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll, true);
  }

  handleScroll() {
    const header = document.querySelector('header');
    let hamburgerColor;
    if (window.pageYOffset > header.offsetHeight) {
      hamburgerColor = 'black';
    } else {
      hamburgerColor = 'white';
    }
    this.setState({ hamburgerColor });
  }

  toggleClass() {
    this.setState({ open: !this.state.open });
  }

  blockClicks(e) {
    e.stopPropagation();
  }

  render() {
    return (
      <nav className={this.state.open ? 'open' : ''} onClick={this.onClick}>
        <Hamburger onClick={this.onClick} open={this.state.open} hamburgerColor={this.state.hamburgerColor} />
        <NavList blockClicks={this.blockClicks} />
        <style jsx>{`
          nav::before {
            content: '';
            background: rgba(0, 0, 0, 0.4);
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 2;
            visibility: hidden;
            opacity: 0;
            transition: 500ms all ease-in-out;
            will-change: opacity;
          }

          nav.open::before {
            visibility: visible;
            opacity: 1;
          }
        `}</style>
      </nav>
    );
  }
}

export default Navigation;
<commit_msg>pressing 'escape' will close nav<commit_after>import React from 'react';
import Hamburger from './Hamburger';
import NavList from './NavList';

class Navigation extends React.Component {
  constructor(props) {
    super(props);
    this.state = { open: false, hamburgerColor: 'white' };
    this.onClick = this.toggleClass.bind(this);
    this.blockClicks = this.blockClicks.bind(this);
    this.handleScroll = this.handleScroll.bind(this);
    this.handleKey = this.handleKey.bind(this);
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll, true);
    window.addEventListener('keydown', this.handleKey, true);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll, true);
  }

  handleScroll() {
    const header = document.querySelector('header');
    let hamburgerColor;
    if (window.pageYOffset > header.offsetHeight) {
      hamburgerColor = 'black';
    } else {
      hamburgerColor = 'white';
    }
    this.setState({ hamburgerColor });
  }

  handleKey(e) {
    if (e.keyCode === 27) {
      this.setState({ open: false });
    }
  }

  toggleClass() {
    this.setState({ open: !this.state.open });
  }

  blockClicks(e) {
    e.stopPropagation();
  }

  render() {
    return (
      <nav className={this.state.open ? 'open' : ''} onClick={this.onClick}>
        <Hamburger onClick={this.onClick} open={this.state.open} hamburgerColor={this.state.hamburgerColor} />
        <NavList blockClicks={this.blockClicks} />
        <style jsx>{`
          nav::before {
            content: '';
            background: rgba(0, 0, 0, 0.4);
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 2;
            visibility: hidden;
            opacity: 0;
            transition: 500ms all ease-in-out;
            will-change: opacity;
          }

          nav.open::before {
            visibility: visible;
            opacity: 1;
          }
        `}</style>
      </nav>
    );
  }
}

export default Navigation;
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');

var browserSync = require('browser-sync');
var modRewrite = require('connect-modrewrite');
var url = require('url');
var config = require('./config');

function browserSyncInit(baseDir, files, browser) {
    browser = browser === undefined ? 'default' : browser;

    var rewrite = modRewrite(['!\.html|\.woff|\.js|\.ttf|\.svg|\.css|\.png|\.jpg /index.html [L]']);

    // connect middlewares
    var middlewares = [rewrite];

    var options = {
        //startPath: '/index.html',
        server: {
            baseDir: baseDir,
            middleware: middlewares
        },
        browser: browser,
        open: config.browsersync.open,
        https: config.browsersync.https
    };

    if(files) {
        options.files = files;
    }

    browserSync(options);
}

gulp.task('serve', ['watch'], function () {
    browserSyncInit([
        '.tmp/templates',
        '.tmp',
        'app'
    ], [
        '.tmp/styles/**/*.css',
        '.tmp/scripts/**/*.js',
        '.tmp/templates/**/*.html',
        'app/*.html'
    ]);
});

gulp.task('serve:dist', ['build:dist'], function () {
    browserSyncInit('dist');
});
<commit_msg>add some suffix exceptions to mod-rewrite<commit_after>'use strict';

var gulp = require('gulp');

var browserSync = require('browser-sync');
var modRewrite = require('connect-modrewrite');
var url = require('url');
var config = require('./config');

function browserSyncInit(baseDir, files, browser) {
    browser = browser === undefined ? 'default' : browser;

    var rewrite = modRewrite(['!\.html|\.woff|\.js|\.ttf|\.svg|\.css|\.png|\.eot|\.svg|\.ttf|\.woff2|\.otf$ /index.html [L]']);

    // connect middlewares
    var middlewares = [rewrite];

    var options = {
        //startPath: '/index.html',
        server: {
            baseDir: baseDir,
            middleware: middlewares
        },
        browser: browser,
        open: config.browsersync.open,
        https: config.browsersync.https
    };

    if(files) {
        options.files = files;
    }

    browserSync(options);
}

gulp.task('serve', ['watch'], function () {
    browserSyncInit([
        '.tmp/templates',
        '.tmp',
        'app'
    ], [
        '.tmp/styles/**/*.css',
        '.tmp/scripts/**/*.js',
        '.tmp/templates/**/*.html',
        'app/*.html'
    ]);
});

gulp.task('serve:dist', ['build:dist'], function () {
    browserSyncInit('dist');
});
<|endoftext|>