<commit_before>/*!
 * Dialogs Manager v3.0.3
 * https://github.com/cobicarmel/dialogs-manager/
 *
 * Copyright Kobi Zaltzberg
 * Released under the MIT license
 * https://github.com/cobicarmel/dialogs-manager/blob/master/LICENSE.txt
 */

(function ($, global) {
	'use strict';

	/*
	 * Dialog Manager
	 */
	var DialogsManager = {
		widgetsTypes: {},
		createWidgetType: function (typeName, properties, Parent) {
			if (!Parent) {
				Parent = this.Widget;
			}

			var WidgetType = function () {

				Parent.apply(this, arguments);
			};

			var prototype = WidgetType.prototype = new Parent(typeName);

			$.extend(prototype, properties);

			prototype.constructor = WidgetType;

			WidgetType.extend = function (typeName, properties) {

				return DialogsManager.createWidgetType(typeName, properties, WidgetType);
			};

			return WidgetType;
		},
		addWidgetType: function (typeName, properties, Parent) {

			if (properties && properties.prototype instanceof this.Widget) {
				return this.widgetsTypes[typeName] = properties;
			}

			return this.widgetsTypes[typeName] = this.createWidgetType(typeName, properties, Parent);
		},
		getWidgetType: function (widgetType) {

			return this.widgetsTypes[widgetType];
		}
	};

	/*
	 * Dialog Manager instances constructor
	 */
	DialogsManager.Instance = function () {

		var self = this,
			elements = {},
			settings = {};

		var initElements = function () {

			elements.body = $('body');
		};

		var initSettings = function (options) {

			var defaultSettings = {
				classPrefix: 'dialog',
				effects: {
					show: 'fadeIn',
					hide: 'fadeOut'
				}
			};

			$.extend(settings, defaultSettings, options);
		};

		this.createWidget = function (widgetType, properties) {

			var WidgetTypeConstructor = DialogsManager.getWidgetType(widgetType),
				widget = new WidgetTypeConstructor(widgetType);

			properties = properties || {};

			widget.init(self, properties);

			widget.setMessage(properties.message);

			return widget;
		};

		this.getSettings = function (property) {

			if (property) {
				return settings[property];
			}

			return Object.create(settings);
		};

		this.init = function (settings) {

			initSettings(settings);

			initElements();

			return self;
		};

		self.init();
	};

	/*
	 * Widget types constructor
	 */
	DialogsManager.Widget = function (widgetName) {

		var self = this,
			settings = {},
			events = {},
			elements = {};

		var bindEvents = function () {

			self.getElements('window').on('keyup', onWindowKeyUp);

			if ( settings.hideOnBackgroundClick ) {
				self.getElements( 'widget' ).on( 'click', function (event) {
					if ( event.target !== this ) {
						return;
					}

					self.hide();
				} );
			}
		};

		var callEffect = function () {

			var intent = Array.prototype.splice.call(arguments, 0, 1);

			var effect = settings.effects[intent],
				$widget = elements.widget;

			if ($.isFunction(effect)) {
				effect.apply($widget, arguments);
			}
			else {

				if ($widget[effect]) {
					$widget[effect].apply($widget, arguments);
				}
				else {
					throw 'Reference Error: The effect ' + effect + ' not found';
				}
			}
		};

		var initElements = function () {

			self.addElement('widget');

			self.addElement('message');

			self.addElement('window', window);

			var id = self.getSettings('id');

			if (id) {

				self.getElements('widget').attr('id', id);
			}
		};

		var initSettings = function (parent, userSettings) {

			var parentSettings = parent.getSettings();

			settings = {
				effects: parentSettings.effects,
				classes: {
					globalPrefix: parentSettings.classPrefix,
					prefix: parentSettings.classPrefix + '-' + widgetName,
					widget: 'dialog-widget'
				},
				hideOnBackgroundClick: true
			};

			$.extend(true, settings, self.getDefaultSettings(), userSettings);

			initSettingsEvents();
		};

		var initSettingsEvents = function () {

			var settings = self.getSettings();

			$.each(settings, function (settingKey) {

				var eventName = settingKey.match(/^on([A-Z].*)/);

				if (!eventName) {
					return;
				}

				eventName = eventName[1].charAt(0).toLowerCase() + eventName[1].slice(1);

				self.on(eventName, this);
			});
		};

		var normalizeClassName = function (name) {

			return name.replace(/([a-z])([A-Z])/g, function () {
				return arguments[1] + '-' + arguments[2].toLowerCase();
			});
		};

		var onWindowKeyUp = function(event) {
			var ESC_KEY = 27,
				keyCode = event.which;

			if ( ESC_KEY === keyCode ) {
				self.hide();
			}
		};

		var unbindEvents = function() {

			self.getElements('window').off('keyup', onWindowKeyUp);
		};

		this.addElement = function (name, element, type) {

			var $newElement = elements[name] = $(element || '<div>'),
				className = settings.classes.prefix + '-';

			name = normalizeClassName(name);

			className += name;

			if (!type) {
				type = name;
			}

			className += ' ' + settings.classes.globalPrefix + '-' + type;

			$newElement.addClass(className);

			return $newElement;
		};

		this.getSettings = function (setting) {

			var copy = Object.create(settings);

			if (setting) {
				return copy[setting];
			}

			return copy;
		};

		this.init = function (parent, properties) {

			if (!(parent instanceof DialogsManager.Instance)) {
				throw 'The ' + self.widgetName + ' must to be initialized from an instance of DialogsManager.Instance';
			}

			self.trigger('init', properties);

			initSettings(parent, properties);

			initElements();

			self.buildWidget();

			if (self.attachEvents) {
				self.attachEvents();
			}

			self.on('show', bindEvents);

			self.on('hide', unbindEvents);

			self.trigger('ready');

			return self;
		};

		this.getElements = function (item) {

			return item ? elements[item] : elements;
		};

		this.hide = function () {

			callEffect('hide');

			self.trigger('hide');

			return self;
		};

		this.on = function (eventName, callback) {
			if (!events[eventName]) {
				events[eventName] = [];
			}

			events[eventName].push(callback);

			return self;
		};

		this.setMessage = function (message) {

			elements.message.html(message);

			return self;
		};

		this.show = function (e, userSettings) {

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

			elements.widget.appendTo('body');

			callEffect('show');

			self.trigger('show', userSettings);

			return self;
		};

		this.trigger = function (eventName, params) {

			var methodName = 'on' + eventName[0].toUpperCase() + eventName.slice(1);

			if (self[methodName]) {
				self[methodName](params);
			}

			var callbacks = events[eventName];

			if (!callbacks) {
				return;
			}

			$.each(callbacks, function (index, callback) {
				callback.call(self, params);
			});
		};
	};

	// Inheritable widget methods
	DialogsManager.Widget.prototype.buildWidget = function () {

		var elements = this.getElements();

		elements.widget.html(elements.message);
	};

	DialogsManager.Widget.prototype.getDefaultSettings = function () {

		return {};
	};

	DialogsManager.Widget.prototype.onHide = function () {
	};

	DialogsManager.Widget.prototype.onShow = function () {
	};

	DialogsManager.Widget.prototype.onInit = function () {
	};

	DialogsManager.Widget.prototype.onReady = function () {
	};

	/*
	 * Default basic widget types
	 */
	DialogsManager.addWidgetType('options', {
		activeKeyUp: function (event) {

			var TAB_KEY = 9;

			if (event.which === TAB_KEY) {

				event.preventDefault();
			}

			if (this.hotKeys[event.which]) {
				this.hotKeys[event.which](this);
			}
		},
		activeKeyDown: function (event) {

			var TAB_KEY = 9;

			if (event.which === TAB_KEY) {
				event.preventDefault();

				var currentButtonIndex = this.focusedButton.index(),
					nextButtonIndex;

				if (event.shiftKey) {

					nextButtonIndex = currentButtonIndex - 1;

					if (nextButtonIndex < 0) {
						nextButtonIndex = this.buttons.length - 1;
					}
				} else {

					nextButtonIndex = currentButtonIndex + 1;

					if (nextButtonIndex >= this.buttons.length) {
						nextButtonIndex = 0;
					}
				}

				this.focusedButton = this.buttons[nextButtonIndex].focus();
			}
		},
		addButton: function (options) {

			var self = this,
				$button = self.addElement(options.name, $('<button>').text(options.text));

			self.buttons.push($button);

			var buttonFn = function () {

				if (self.getSettings('hideOnButtonClick')) {
					self.hide();
				}

				if ($.isFunction(options.callback)) {
					options.callback.call(this, self);
				}
			};

			$button.on('click', buttonFn);

			if (options.hotKey) {
				this.hotKeys[options.hotKey] = buttonFn;
			}

			this.getElements('buttonsWrapper').append($button);

			if (options.focus) {
				this.focusedButton = $button;
			}

			return self;
		},
		bindHotKeys: function () {

			this.getElements('window').on({
				keyup: this.activeKeyUp,
				keydown: this.activeKeyDown
			});
		},
		buildWidget: function () {

			var $widgetHeader = this.addElement('widgetHeader'),
				$widgetContent = this.addElement('widgetContent'),
				$buttonsWrapper = this.addElement('buttonsWrapper');

			var elements = this.getElements();

			$widgetContent.append($widgetHeader, elements.message, $buttonsWrapper);

			elements.widget.html($widgetContent);
		},
		ensureClosureMethods: function () {

			var self = this,
				closureMethodsNames = [
					'placeWidget',
					'activeKeyUp',
					'activeKeyDown'
				];

			$.each(closureMethodsNames, function () {

				var methodName = this,
					oldMethod = self[methodName];

				self[methodName] = function () {
					oldMethod.apply(self, arguments);
				};
			});
		},
		getDefaultSettings: function () {

			return {
				position: {
					my: 'center',
					at: 'center center-100'
				},
				headerMessage: '',
				hideOnButtonClick: true,
				refreshPosition: true
			};
		},
		onHide: function () {

			this.unbindHotKeys();

			this.getElements('window').off('resize', this.placeWidget);
		},
		onInit: function () {

			this.ensureClosureMethods();

			this.buttons = [];

			this.hotKeys = {};

			this.focusedButton = null;
		},
		onReady: function(){

			this.setHeaderMessage(this.getSettings('headerMessage'));
		},
		onShow: function (userSettings) {

			var self = this;

			self.placeWidget(userSettings);

			if (self.getSettings('refreshPosition')) {

				self.getElements('window').on('resize',  self.placeWidget);
			}

			self.bindHotKeys();

			if (!self.focusedButton) {
				self.focusedButton = self.buttons[0];
			}

			if (self.focusedButton) {
				self.focusedButton.focus();
			}
		},
		placeWidget: function (userSettings) {

			var elements = this.getElements(),
				position = this.getSettings('position');

			position.of = elements.widget;

			if (userSettings) {
				$.extend(position, userSettings);
			}

			elements.widgetContent.position(position);
		},
		setHeaderMessage: function (message) {

			this.getElements('widgetHeader').html(message);

			return this;
		},
		unbindHotKeys: function () {

			this.getElements('window').off({
				keyup: this.activeKeyUp,
				keydown: this.activeKeyDown
			});
		}
	});

	DialogsManager.addWidgetType('confirm', DialogsManager.getWidgetType('options').extend('confirm', {
		onReady: function () {

			DialogsManager.getWidgetType('options').prototype.onReady.apply(this, arguments);

			var strings = this.getSettings('strings'),
				isDefaultCancel = this.getSettings('defaultOption') === 'cancel';

			this.addButton({
				name: 'cancel',
				text: strings.cancel,
				callback: function (widget) {

					widget.trigger('cancel');
				},
				focus: isDefaultCancel
			});

			this.addButton({
				name: 'ok',
				text: strings.confirm,
				callback: function (widget) {

					widget.trigger('confirm');
				},
				focus: !isDefaultCancel
			});
		},
		getDefaultSettings: function () {

			var settings = DialogsManager.getWidgetType('options').prototype.getDefaultSettings.apply(this, arguments);

			settings.strings = {
				confirm: 'OK',
				cancel: 'Cancel'
			};

			settings.defaultOption = 'cancel';

			return settings;
		}
	}));

	DialogsManager.addWidgetType('alert', DialogsManager.getWidgetType('options').extend('alert', {
		onReady: function () {

			DialogsManager.getWidgetType('options').prototype.onReady.apply(this, arguments);

			var strings = this.getSettings('strings');

			this.addButton({
				name: 'ok',
				text: strings.confirm,
				callback: function (widget) {

					widget.trigger('confirm');
				}
			});
		},
		getDefaultSettings: function () {
			var settings = DialogsManager.getWidgetType('options').prototype.getDefaultSettings.apply(this, arguments);

			settings.strings = {
				confirm: 'OK'
			};

			return settings;
		}
	}));

	DialogsManager.addWidgetType('popup', {
		getDefaultSettings: function () {

			return {
				position: {
					my: 'center',
					at: 'center',
					of: window
				},
				hide: {
					delay: 5000
				}
			};
		},
		onShow: function () {

			this.getElements('message').position(this.getSettings('position'));

			setTimeout(this.hide, this.getSettings('hide').delay);
		}
	});

	// Exporting the DialogsManager variable to global
	global.DialogsManager = DialogsManager;
})(typeof require === 'function' ? require('jquery') : jQuery, typeof module !== 'undefined' ? module.exports : window);<commit_msg>New `ensureClosureMethods` functionality<commit_after>/*!
 * Dialogs Manager v3.0.3
 * https://github.com/cobicarmel/dialogs-manager/
 *
 * Copyright Kobi Zaltzberg
 * Released under the MIT license
 * https://github.com/cobicarmel/dialogs-manager/blob/master/LICENSE.txt
 */

(function ($, global) {
	'use strict';

	/*
	 * Dialog Manager
	 */
	var DialogsManager = {
		widgetsTypes: {},
		createWidgetType: function (typeName, properties, Parent) {
			if (!Parent) {
				Parent = this.Widget;
			}

			var WidgetType = function () {

				Parent.apply(this, arguments);
			};

			var prototype = WidgetType.prototype = new Parent(typeName);

			$.extend(prototype, properties);

			prototype.constructor = WidgetType;

			WidgetType.extend = function (typeName, properties) {

				return DialogsManager.createWidgetType(typeName, properties, WidgetType);
			};

			return WidgetType;
		},
		addWidgetType: function (typeName, properties, Parent) {

			if (properties && properties.prototype instanceof this.Widget) {
				return this.widgetsTypes[typeName] = properties;
			}

			return this.widgetsTypes[typeName] = this.createWidgetType(typeName, properties, Parent);
		},
		getWidgetType: function (widgetType) {

			return this.widgetsTypes[widgetType];
		}
	};

	/*
	 * Dialog Manager instances constructor
	 */
	DialogsManager.Instance = function () {

		var self = this,
			elements = {},
			settings = {};

		var initElements = function () {

			elements.body = $('body');
		};

		var initSettings = function (options) {

			var defaultSettings = {
				classPrefix: 'dialog',
				effects: {
					show: 'fadeIn',
					hide: 'fadeOut'
				}
			};

			$.extend(settings, defaultSettings, options);
		};

		this.createWidget = function (widgetType, properties) {

			var WidgetTypeConstructor = DialogsManager.getWidgetType(widgetType),
				widget = new WidgetTypeConstructor(widgetType);

			properties = properties || {};

			widget.init(self, properties);

			widget.setMessage(properties.message);

			return widget;
		};

		this.getSettings = function (property) {

			if (property) {
				return settings[property];
			}

			return Object.create(settings);
		};

		this.init = function (settings) {

			initSettings(settings);

			initElements();

			return self;
		};

		self.init();
	};

	/*
	 * Widget types constructor
	 */
	DialogsManager.Widget = function (widgetName) {

		var self = this,
			settings = {},
			events = {},
			elements = {};

		var bindEvents = function () {

			self.getElements('window').on('keyup', onWindowKeyUp);

			if ( settings.hideOnBackgroundClick ) {
				self.getElements( 'widget' ).on( 'click', function (event) {
					if ( event.target !== this ) {
						return;
					}

					self.hide();
				} );
			}
		};

		var callEffect = function () {

			var intent = Array.prototype.splice.call(arguments, 0, 1);

			var effect = settings.effects[intent],
				$widget = elements.widget;

			if ($.isFunction(effect)) {
				effect.apply($widget, arguments);
			}
			else {

				if ($widget[effect]) {
					$widget[effect].apply($widget, arguments);
				}
				else {
					throw 'Reference Error: The effect ' + effect + ' not found';
				}
			}
		};

		var ensureClosureMethods = function() {
			var closureMethodsNames = self.getClosureMethods();

			$.each(closureMethodsNames, function () {

				var methodName = this,
					oldMethod = self[methodName];

				self[methodName] = function () {
					oldMethod.apply(self, arguments);
				};
			});
		};

		var initElements = function () {

			self.addElement('widget');

			self.addElement('message');

			self.addElement('window', window);

			var id = self.getSettings('id');

			if (id) {

				self.getElements('widget').attr('id', id);
			}
		};

		var initSettings = function (parent, userSettings) {

			var parentSettings = parent.getSettings();

			settings = {
				effects: parentSettings.effects,
				classes: {
					globalPrefix: parentSettings.classPrefix,
					prefix: parentSettings.classPrefix + '-' + widgetName,
					widget: 'dialog-widget'
				},
				hideOnBackgroundClick: true
			};

			$.extend(true, settings, self.getDefaultSettings(), userSettings);

			initSettingsEvents();
		};

		var initSettingsEvents = function () {

			var settings = self.getSettings();

			$.each(settings, function (settingKey) {

				var eventName = settingKey.match(/^on([A-Z].*)/);

				if (!eventName) {
					return;
				}

				eventName = eventName[1].charAt(0).toLowerCase() + eventName[1].slice(1);

				self.on(eventName, this);
			});
		};

		var normalizeClassName = function (name) {

			return name.replace(/([a-z])([A-Z])/g, function () {
				return arguments[1] + '-' + arguments[2].toLowerCase();
			});
		};

		var onWindowKeyUp = function(event) {
			var ESC_KEY = 27,
				keyCode = event.which;

			if ( ESC_KEY === keyCode ) {
				self.hide();
			}
		};

		var unbindEvents = function() {

			self.getElements('window').off('keyup', onWindowKeyUp);
		};

		this.addElement = function (name, element, type) {

			var $newElement = elements[name] = $(element || '<div>'),
				className = settings.classes.prefix + '-';

			name = normalizeClassName(name);

			className += name;

			if (!type) {
				type = name;
			}

			className += ' ' + settings.classes.globalPrefix + '-' + type;

			$newElement.addClass(className);

			return $newElement;
		};

		this.getSettings = function (setting) {

			var copy = Object.create(settings);

			if (setting) {
				return copy[setting];
			}

			return copy;
		};

		this.init = function (parent, properties) {

			if (!(parent instanceof DialogsManager.Instance)) {
				throw 'The ' + self.widgetName + ' must to be initialized from an instance of DialogsManager.Instance';
			}

			ensureClosureMethods();

			self.trigger('init', properties);

			initSettings(parent, properties);

			initElements();

			self.buildWidget();

			if (self.attachEvents) {
				self.attachEvents();
			}

			self.on('show', bindEvents);

			self.on('hide', unbindEvents);

			self.trigger('ready');

			return self;
		};

		this.getElements = function (item) {

			return item ? elements[item] : elements;
		};

		this.hide = function () {

			callEffect('hide');

			self.trigger('hide');

			return self;
		};

		this.on = function (eventName, callback) {
			if (!events[eventName]) {
				events[eventName] = [];
			}

			events[eventName].push(callback);

			return self;
		};

		this.setMessage = function (message) {

			elements.message.html(message);

			return self;
		};

		this.show = function (e, userSettings) {

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

			elements.widget.appendTo('body');

			callEffect('show');

			self.trigger('show', userSettings);

			return self;
		};

		this.trigger = function (eventName, params) {

			var methodName = 'on' + eventName[0].toUpperCase() + eventName.slice(1);

			if (self[methodName]) {
				self[methodName](params);
			}

			var callbacks = events[eventName];

			if (!callbacks) {
				return;
			}

			$.each(callbacks, function (index, callback) {
				callback.call(self, params);
			});
		};
	};

	// Inheritable widget methods
	DialogsManager.Widget.prototype.buildWidget = function () {

		var elements = this.getElements();

		elements.widget.html(elements.message);
	};

	DialogsManager.Widget.prototype.getDefaultSettings = function () {

		return {};
	};

	DialogsManager.Widget.prototype.getClosureMethods = function() {
	};

	DialogsManager.Widget.prototype.onHide = function () {
	};

	DialogsManager.Widget.prototype.onShow = function () {
	};

	DialogsManager.Widget.prototype.onInit = function () {
	};

	DialogsManager.Widget.prototype.onReady = function () {
	};

	/*
	 * Default basic widget types
	 */
	DialogsManager.addWidgetType('options', {
		activeKeyUp: function (event) {

			var TAB_KEY = 9;

			if (event.which === TAB_KEY) {

				event.preventDefault();
			}

			if (this.hotKeys[event.which]) {
				this.hotKeys[event.which](this);
			}
		},
		activeKeyDown: function (event) {

			var TAB_KEY = 9;

			if (event.which === TAB_KEY) {
				event.preventDefault();

				var currentButtonIndex = this.focusedButton.index(),
					nextButtonIndex;

				if (event.shiftKey) {

					nextButtonIndex = currentButtonIndex - 1;

					if (nextButtonIndex < 0) {
						nextButtonIndex = this.buttons.length - 1;
					}
				} else {

					nextButtonIndex = currentButtonIndex + 1;

					if (nextButtonIndex >= this.buttons.length) {
						nextButtonIndex = 0;
					}
				}

				this.focusedButton = this.buttons[nextButtonIndex].focus();
			}
		},
		addButton: function (options) {

			var self = this,
				$button = self.addElement(options.name, $('<button>').text(options.text));

			self.buttons.push($button);

			var buttonFn = function () {

				if (self.getSettings('hideOnButtonClick')) {
					self.hide();
				}

				if ($.isFunction(options.callback)) {
					options.callback.call(this, self);
				}
			};

			$button.on('click', buttonFn);

			if (options.hotKey) {
				this.hotKeys[options.hotKey] = buttonFn;
			}

			this.getElements('buttonsWrapper').append($button);

			if (options.focus) {
				this.focusedButton = $button;
			}

			return self;
		},
		bindHotKeys: function () {

			this.getElements('window').on({
				keyup: this.activeKeyUp,
				keydown: this.activeKeyDown
			});
		},
		buildWidget: function () {

			var $widgetHeader = this.addElement('widgetHeader'),
				$widgetContent = this.addElement('widgetContent'),
				$buttonsWrapper = this.addElement('buttonsWrapper');

			var elements = this.getElements();

			$widgetContent.append($widgetHeader, elements.message, $buttonsWrapper);

			elements.widget.html($widgetContent);
		},
		getClosureMethods: function () {

			var closureMethods = DialogsManager.getWidgetType('light-box').prototype.getClosureMethods.apply(this, arguments);

			return closureMethods.concat( [
				'activeKeyUp',
				'activeKeyDown'
			] );
		},
		getDefaultSettings: function () {

			return {
				position: {
					my: 'center',
					at: 'center center-100'
				},
				headerMessage: '',
				hideOnButtonClick: true,
				refreshPosition: true
			};
		},
		onHide: function () {

			this.unbindHotKeys();

			this.getElements('window').off('resize', this.placeWidget);
		},
		onInit: function () {
			this.buttons = [];

			this.hotKeys = {};

			this.focusedButton = null;
		},
		onReady: function(){

			this.setHeaderMessage(this.getSettings('headerMessage'));
		},
		onShow: function (userSettings) {

			var self = this;

			self.placeWidget(userSettings);

			if (self.getSettings('refreshPosition')) {

				self.getElements('window').on('resize',  self.placeWidget);
			}

			self.bindHotKeys();

			if (!self.focusedButton) {
				self.focusedButton = self.buttons[0];
			}

			if (self.focusedButton) {
				self.focusedButton.focus();
			}
		},
		placeWidget: function (userSettings) {

			var elements = this.getElements(),
				position = this.getSettings('position');

			position.of = elements.widget;

			if (userSettings) {
				$.extend(position, userSettings);
			}

			elements.widgetContent.position(position);
		},
		setHeaderMessage: function (message) {

			this.getElements('widgetHeader').html(message);

			return this;
		},
		unbindHotKeys: function () {

			this.getElements('window').off({
				keyup: this.activeKeyUp,
				keydown: this.activeKeyDown
			});
		}
	});

	DialogsManager.addWidgetType('confirm', DialogsManager.getWidgetType('options').extend('confirm', {
		onReady: function () {

			DialogsManager.getWidgetType('options').prototype.onReady.apply(this, arguments);

			var strings = this.getSettings('strings'),
				isDefaultCancel = this.getSettings('defaultOption') === 'cancel';

			this.addButton({
				name: 'cancel',
				text: strings.cancel,
				callback: function (widget) {

					widget.trigger('cancel');
				},
				focus: isDefaultCancel
			});

			this.addButton({
				name: 'ok',
				text: strings.confirm,
				callback: function (widget) {

					widget.trigger('confirm');
				},
				focus: !isDefaultCancel
			});
		},
		getDefaultSettings: function () {

			var settings = DialogsManager.getWidgetType('options').prototype.getDefaultSettings.apply(this, arguments);

			settings.strings = {
				confirm: 'OK',
				cancel: 'Cancel'
			};

			settings.defaultOption = 'cancel';

			return settings;
		}
	}));

	DialogsManager.addWidgetType('alert', DialogsManager.getWidgetType('options').extend('alert', {
		onReady: function () {

			DialogsManager.getWidgetType('options').prototype.onReady.apply(this, arguments);

			var strings = this.getSettings('strings');

			this.addButton({
				name: 'ok',
				text: strings.confirm,
				callback: function (widget) {

					widget.trigger('confirm');
				}
			});
		},
		getDefaultSettings: function () {
			var settings = DialogsManager.getWidgetType('options').prototype.getDefaultSettings.apply(this, arguments);

			settings.strings = {
				confirm: 'OK'
			};

			return settings;
		}
	}));

	DialogsManager.addWidgetType('popup', {
		getDefaultSettings: function () {

			return {
				position: {
					my: 'center',
					at: 'center',
					of: window
				},
				hide: {
					delay: 5000
				}
			};
		},
		onShow: function () {

			this.getElements('message').position(this.getSettings('position'));

			setTimeout(this.hide, this.getSettings('hide').delay);
		}
	});

	// Exporting the DialogsManager variable to global
	global.DialogsManager = DialogsManager;
})(typeof require === 'function' ? require('jquery') : jQuery, typeof module !== 'undefined' ? module.exports : window);<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
// limitations under the License.

(function(scope, testing) {

  function numberToString(x) {
    return x.toFixed(3).replace('.000', '');
  }

  function clamp(min, max, x) {
    return Math.min(max, Math.max(min, x));
  }

  function parseNumber(string) {
    if (/^\s*[-+]?(\d*\.)?\d+\s*$/.test(string))
      return Number(string);
  }

  function mergeNumbers(left, right) {
    return [left, right, numberToString];
  }

  function clampedMergeNumbers(min, max) {
    return function(left, right) {
      return [left, right, function(x) {
        return numberToString(clamp(min, max, x));
      }];
    };
  }

  scope.addPropertiesHandler(parseNumber, clampedMergeNumbers(0, 1), ['opacity']);

  scope.parseNumber = parseNumber;
  scope.mergeNumbers = mergeNumbers;
  scope.numberToString = numberToString;

})(webAnimationsMinifill, webAnimationsTesting);
<commit_msg>Support animation of z-index<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
// limitations under the License.

(function(scope, testing) {

  function numberToString(x) {
    return x.toFixed(3).replace('.000', '');
  }

  function clamp(min, max, x) {
    return Math.min(max, Math.max(min, x));
  }

  function parseNumber(string) {
    if (/^\s*[-+]?(\d*\.)?\d+\s*$/.test(string))
      return Number(string);
  }

  function mergeNumbers(left, right) {
    return [left, right, numberToString];
  }

  function clampedMergeNumbers(min, max) {
    return function(left, right) {
      return [left, right, function(x) {
        return numberToString(clamp(min, max, x));
      }];
    };
  }

  function round(left, right) {
    return [left, right, Math.round];
  }

  scope.addPropertiesHandler(parseNumber, clampedMergeNumbers(0, 1), ['opacity']);
  scope.addPropertiesHandler(parseNumber, round, ['z-index']);

  scope.parseNumber = parseNumber;
  scope.mergeNumbers = mergeNumbers;
  scope.numberToString = numberToString;

})(webAnimationsMinifill, webAnimationsTesting);
<|endoftext|>


<commit_before>var through = require('through2');

var indent = function (biggest, current) {
    for ( var i = 0; i < biggest - current.length; i++ ) {
        process.stdout.write(' ');
    }
};

module.exports = through.obj(function (file, type, done) {
    var results = JSON.parse(file.contents.toString()).sort(function (a, b) {
        return b.hz - a.hz;
    });

    var longest = results.slice().sort(function (a, b) {
        return b.name.length - a.name.length;
    })[0].name.length;

    var slowest = results.map(function (i) {
        return Math.round((1 / i.hz) * 1000).toString().length;
    }).sort().reverse()[0];

    var postcss = results.find(function (i) {
        return i.name == 'PostCSS';
    }).hz;

    process.stdout.write('\n');
    results.forEach(function (i) {
        process.stdout.write(i.name + ': ');
        indent(longest, i.name);

        var time = Math.round((1 / i.hz) * 1000).toString();
        process.stdout.write(time + ' ms ');
        indent(slowest, time);

        if ( i.name != 'PostCSS' ) {
            var times;
            if ( i.hz > postcss ) {
                times = (i.hz / postcss).toFixed(1);
                process.stdout.write('(' + times + ' times faster)');
            } else {
                times = (postcss / i.hz).toFixed(1);
                process.stdout.write('(' + times + ' times slower)');
            }
        }
        process.stdout.write('\n');
    });

    process.stdout.write('\n');
    done();
});
<commit_msg>Do not use ES6 methods in tasks<commit_after>var through = require('through2');

var indent = function (biggest, current) {
    for ( var i = 0; i < biggest - current.length; i++ ) {
        process.stdout.write(' ');
    }
};

module.exports = through.obj(function (file, type, done) {
    var results = JSON.parse(file.contents.toString()).sort(function (a, b) {
        return b.hz - a.hz;
    });

    var longest = results.slice().sort(function (a, b) {
        return b.name.length - a.name.length;
    })[0].name.length;

    var slowest = results.map(function (i) {
        return Math.round((1 / i.hz) * 1000).toString().length;
    }).sort().reverse()[0];

    var postcss;
    results.forEach(function (i) {
        if ( i.name == 'PostCSS' ) {
            postcss = i.hz;
            return false;
        }
    });

    process.stdout.write('\n');
    results.forEach(function (i) {
        process.stdout.write(i.name + ': ');
        indent(longest, i.name);

        var time = Math.round((1 / i.hz) * 1000).toString();
        process.stdout.write(time + ' ms ');
        indent(slowest, time);

        if ( i.name != 'PostCSS' ) {
            var times;
            if ( i.hz > postcss ) {
                times = (i.hz / postcss).toFixed(1);
                process.stdout.write('(' + times + ' times faster)');
            } else {
                times = (postcss / i.hz).toFixed(1);
                process.stdout.write('(' + times + ' times slower)');
            }
        }
        process.stdout.write('\n');
    });

    process.stdout.write('\n');
    done();
});
<|endoftext|>


<commit_before>import { createElement as h } from 'react'
import { render } from 'react-dom'
import { bindActionCreators } from 'redux'
import { Provider, connect } from 'react-redux'

import isDemo from '../../utils/isDemo'

import enhanceState from './enhancers/enhanceState'
import createStore from './utils/createStore'
import * as storage from './utils/storage'
import reducers from './reducers'
import * as actions from './actions'

import { initialState as initialTokenState } from './reducers/token'
import { initialState as initialRouteState } from './reducers/route'
import { initialState as initialViewsState } from './reducers/views'
import { initialState as initialPagesState } from './reducers/pages'
import { initialState as initialReferrersState } from './reducers/referrers'
import { initialState as initialDurationsState } from './reducers/durations'
import { initialState as initialLanguagesState } from './reducers/languages'
import { initialState as initialOsState } from './reducers/os'
import { initialState as initialSizesState } from './reducers/sizes'

import Main from './components/Main'

const persistedState = storage.load()
const store = createStore(reducers, persistedState)

const mapStateToProps = (state) => enhanceState(state)
const mapDispatchToProps = (dispatch) => bindActionCreators(actions, dispatch)

const ConnectedMain = connect(mapStateToProps, mapDispatchToProps)(Main)
const container = document.querySelector('#main')

if (isDemo === true) {
	console.warn('Ackee runs in demo mode')
}

store.subscribe(() => {

	const currentState = store.getState()

	storage.save({
		token: {
			...initialTokenState(),
			value: currentState.token.value
		},
		route: {
			...initialRouteState(),
			value: currentState.route.value
		},
		views: {
			...initialViewsState(),
			type: currentState.views.type,
			interval: currentState.views.interval
		},
		pages: {
			...initialPagesState(),
			type: currentState.pages.type
		},
		referrers: {
			...initialReferrersState(),
			sorting: currentState.referrers.sorting
		},
		durations: {
			...initialDurationsState(),
			type: currentState.durations.type
		},
		languages: {
			...initialLanguagesState(),
			sorting: currentState.languages.sorting
		},
		os: {
			...initialOsState(),
			type: currentState.os.type,
			sorting: currentState.os.sorting
		},
		sizes: {
			...initialSizesState(),
			type: currentState.sizes.type
		}
	})

})

const App = h(Provider, { store },
	h(ConnectedMain)
)

render(App, container)<commit_msg>Save state<commit_after>import { createElement as h } from 'react'
import { render } from 'react-dom'
import { bindActionCreators } from 'redux'
import { Provider, connect } from 'react-redux'

import isDemo from '../../utils/isDemo'

import enhanceState from './enhancers/enhanceState'
import createStore from './utils/createStore'
import * as storage from './utils/storage'
import reducers from './reducers'
import * as actions from './actions'

import { initialState as initialTokenState } from './reducers/token'
import { initialState as initialRouteState } from './reducers/route'
import { initialState as initialViewsState } from './reducers/views'
import { initialState as initialPagesState } from './reducers/pages'
import { initialState as initialReferrersState } from './reducers/referrers'
import { initialState as initialDurationsState } from './reducers/durations'
import { initialState as initialLanguagesState } from './reducers/languages'
import { initialState as initialOsState } from './reducers/os'
import { initialState as initialSizesState } from './reducers/sizes'

import Main from './components/Main'

const persistedState = storage.load()
const store = createStore(reducers, persistedState)

const mapStateToProps = (state) => enhanceState(state)
const mapDispatchToProps = (dispatch) => bindActionCreators(actions, dispatch)

const ConnectedMain = connect(mapStateToProps, mapDispatchToProps)(Main)
const container = document.querySelector('#main')

if (isDemo === true) {
	console.warn('Ackee runs in demo mode')
}

store.subscribe(() => {

	const currentState = store.getState()

	storage.save({
		token: {
			...initialTokenState(),
			value: currentState.token.value
		},
		route: {
			...initialRouteState(),
			value: currentState.route.value
		},
		views: {
			...initialViewsState(),
			type: currentState.views.type,
			interval: currentState.views.interval
		},
		pages: {
			...initialPagesState(),
			dateRange: currentState.pages.dateRange,
			sorting: currentState.pages.sorting
		},
		referrers: {
			...initialReferrersState(),
			dateRange: currentState.referrers.dateRange,
			sorting: currentState.referrers.sorting
		},
		durations: {
			...initialDurationsState(),
			type: currentState.durations.type
		},
		languages: {
			...initialLanguagesState(),
			dateRange: currentState.languages.dateRange,
			sorting: currentState.languages.sorting
		},
		os: {
			...initialOsState(),
			dateRange: currentState.os.dateRange,
			type: currentState.os.type,
			sorting: currentState.os.sorting
		},
		sizes: {
			...initialSizesState(),
			dateRange: currentState.sizes.dateRange,
			type: currentState.sizes.type
		}
	})

})

const App = h(Provider, { store },
	h(ConnectedMain)
)

render(App, container)<|endoftext|>


<commit_before>import Cart from './cart';
import playerconfig from '../../assets/json/player_default.json';

export default class Player extends Phaser.Group {
    constructor (game) {
        super(game);
        this.playerinfo = playerconfig;
        this.enableBody = true;
        this.jumpKey = this.game.input.keyboard.addKey(Phaser.KeyCode.SPACEBAR);
        this.jumping = 0;
        this.jumpButton = this.game.add.button(this.game.width - 250, 0, 'jumper');
        this.jumpButton.onInputDown.add(this.jumpButtonDown, this);
        this.jumpButton.onInputUp.add(this.jumpButtonUp, this);

        this.cart = new Cart(this.game, 50, 430);
        this.add(this.cart);
    }
    getInfo () {
        return this.playerinfo;
    }
    setInfo (key, value) {
        this.playerinfo[key] = value;
    }
    jumpButtonDown () {
        console.log("RUNNING jumpButtonDown ...");
        this.jumping |= 1;
    }
    jumpButtonUp() {
        console.log("RUNNING jumpButtonUp ...");
        this.jumping &= ~1;
    }
    update () {
        super.update();

        if (this.jumpKey.isDown) {
            this.jumping |= 2;
        }
        else {
            this.jumping &= ~2;
        }

        if (this.jumping) {
            console.log("JUMPING: " + this.jumping);
        }
    }
    collectGem() {
        this.setInfo('gems', this.getInfo()['gems'] + 1);
    }
}
<commit_msg>Make jump bounce up.<commit_after>import Cart from './cart';
import playerconfig from '../../assets/json/player_default.json';

export default class Player extends Phaser.Group {
    constructor (game) {
        super(game);
        this.playerinfo = playerconfig;
        this.enableBody = true;
        this.jumpKey = this.game.input.keyboard.addKey(Phaser.KeyCode.SPACEBAR);
        this.jumping = 0;
        this.jumpButton = this.game.add.button(this.game.width - 250, 0, 'jumper');
        this.jumpButton.onInputDown.add(this.jumpButtonDown, this);
        this.jumpButton.onInputUp.add(this.jumpButtonUp, this);

        this.cart = new Cart(this.game, 50, 430);
        this.add(this.cart);
    }
    getInfo () {
        return this.playerinfo;
    }
    setInfo (key, value) {
        this.playerinfo[key] = value;
    }
    jumpButtonDown () {
        console.log("RUNNING jumpButtonDown ...");
        this.jumping |= 1;
    }
    jumpButtonUp() {
        console.log("RUNNING jumpButtonUp ...");
        this.jumping &= ~1;
    }
    update () {
        super.update();

        if (this.jumpKey.isDown) {
            this.jumping |= 2;
        }
        else {
            this.jumping &= ~2;
        }

        if (this.jumping) {
            console.log("JUMPING: " + this.jumping);
            this.cart.body.velocity.y = -100;
        }
    }
    collectGem() {
        this.setInfo('gems', this.getInfo()['gems'] + 1);
    }
}
<|endoftext|>


<commit_before>'use strict';

module.exports = grunt => {
  let _ = require('lodash');
  let webpack = require('webpack');

  grunt.registerTask('webpack', function () {
    const compiler = webpack(makeConfig(grunt.config('prod')));
    let done = this.async();
    if (grunt.option('watch')) {
      compiler.watch({}, logResult(_.noop));
    } else {
      compiler.run(logResult(done));
    }
  });

  function logResult(callback) {
    return (err, stats) => {
      if (stats.hasError) {
        grunt.log.writeln(stats.toString({colors: true}));
      } else {
        grunt.log.ok(stats.toString({colors: true}));
      }
      callback();
    }
  }

  function makeConfig(prod) {
    let path = require('path'),
      ExtractTextPlugin = require('extract-text-webpack-plugin'),
      ngAnnotatePlugin = require('ng-annotate-webpack-plugin'),
      AssetsPlugin = require('assets-webpack-plugin');

    const APP = path.join(grunt.config('srcDir'));
    const BUILD = path.join(grunt.config('buildDir'));
    let configuration = {
      context: APP,
      entry: {
        main: './js/main.js'
      },
      output: {
        path: BUILD,
        filename: makeName('[name]'),
        publicPath: '/app/',
        chunkFilename: makeName('[id].[name]')
      },
      module: {
        loaders: [
          {
            test: /\.jsx?$/,
            loader: 'babel',
            exclude: /node_modules/
          },
          {
            test: /\.less$/,
            loader: ExtractTextPlugin.extract('style-loader', 'css-loader!less-loader')
          },
          {
            test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=application/font-woff'
          }, {
            test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=application/font-woff'
          }, {
            test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=application/octet-stream'
          }, {
            test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'file'
          }, {
            test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=image/svg+xml'
          }
        ]
      },
      plugins: [
        new webpack.optimize.CommonsChunkPlugin('vendor', makeName('vendor')),
        new ExtractTextPlugin(makeName('[name]', 'css')),
        new ngAnnotatePlugin({
          add: true
        })

      ]
    };
    if (prod) {
      configuration.plugins.push(new webpack.optimize.UglifyJsPlugin());
      configuration.plugins.push(new AssetsPlugin({path: BUILD, filename: 'map.json'}));
    }

    return configuration;

    function makeName(name, extension) {
      extension = extension || 'js';
      return prod ? `${name}.[chunkhash].${extension}` : `${name}.${extension}`;
    }
  }
};
<commit_msg>Cleanup webpack config<commit_after>'use strict';

module.exports = grunt => {
  let _ = require('lodash');
  let webpack = require('webpack');

  grunt.registerTask('webpack', function () {
    const compiler = webpack(makeConfig(grunt.config('prod')));
    let done = this.async();
    if (grunt.option('watch')) {
      compiler.watch({}, logResult(_.noop));
    } else {
      compiler.run(logResult(done));
    }
  });

  function logResult(callback) {
    return (err, stats) => {
      if (stats.hasError) {
        grunt.log.writeln(stats.toString({colors: true}));
      } else {
        grunt.log.ok(stats.toString({colors: true}));
      }
      callback();
    }
  }

  function makeConfig(prod) {
    let path = require('path'),
      ExtractTextPlugin = require('extract-text-webpack-plugin'),
      NgAnnotatePlugin = require('ng-annotate-webpack-plugin'),
      AssetsPlugin = require('assets-webpack-plugin');

    const APP = path.join(grunt.config('srcDir'));
    const BUILD = path.join(grunt.config('buildDir'));
    let configuration = {
      context: APP,
      entry: {
        main: './js/main.js'
      },
      output: {
        path: BUILD,
        filename: makeName('[name]'),
        publicPath: '/app/',
        chunkFilename: makeName('[id].[name]')
      },
      module: {
        loaders: [
          {
            test: /\.jsx?$/,
            loader: 'babel',
            exclude: /node_modules/
          },
          {
            test: /\.less$/,
            loader: ExtractTextPlugin.extract('style-loader', 'css-loader!less-loader')
          },
          {
            test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=application/font-woff'
          }, {
            test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=application/font-woff'
          }, {
            test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=application/octet-stream'
          }, {
            test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'file'
          }, {
            test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
            loader: 'url?limit=10000&minetype=image/svg+xml'
          }
        ]
      },
      plugins: [
        new webpack.optimize.CommonsChunkPlugin('vendor', makeName('vendor')),
        new ExtractTextPlugin(makeName('[name]', 'css')),
        new NgAnnotatePlugin({add: true})
      ]
    };
    if (prod) {
      configuration.plugins.push(new webpack.optimize.UglifyJsPlugin());
      configuration.plugins.push(new AssetsPlugin({path: BUILD, filename: 'map.json'}));
    }

    return configuration;

    function makeName(name, extension) {
      extension = extension || 'js';
      return prod ? `${name}.[chunkhash].${extension}` : `${name}.${extension}`;
    }
  }
};
<|endoftext|>


<commit_before>/* Hyperaudio core
 *
 */

var hyperaudio = (function() {

	// jQuery 2.0.3 (c) 2013 http://jquery.com/

	var
		// [[Class]] -> type pairs
		class2type = {},
		core_toString = class2type.toString,
		core_hasOwn = class2type.hasOwnProperty;

	function hyperaudio() {
		// Nada
	}

	hyperaudio.extend = function() {
		var options, name, src, copy, copyIsArray, clone,
			target = arguments[0] || {},
			i = 1,
			length = arguments.length,
			deep = false;

		// Handle a deep copy situation
		if ( typeof target === "boolean" ) {
			deep = target;
			target = arguments[1] || {};
			// skip the boolean and the target
			i = 2;
		}

		// Handle case when target is a string or something (possible in deep copy)
		if ( typeof target !== "object" && !hyperaudio.isFunction(target) ) {
			target = {};
		}

		// extend hyperaudio itself if only one argument is passed
		if ( length === i ) {
			target = this;
			--i;
		}

		for ( ; i < length; i++ ) {
			// Only deal with non-null/undefined values
			if ( (options = arguments[ i ]) != null ) {
				// Extend the base object
				for ( name in options ) {
					src = target[ name ];
					copy = options[ name ];

					// Prevent never-ending loop
					if ( target === copy ) {
						continue;
					}

					// Recurse if we're merging plain objects or arrays
					if ( deep && copy && ( hyperaudio.isPlainObject(copy) || (copyIsArray = hyperaudio.isArray(copy)) ) ) {
						if ( copyIsArray ) {
							copyIsArray = false;
							clone = src && hyperaudio.isArray(src) ? src : [];

						} else {
							clone = src && hyperaudio.isPlainObject(src) ? src : {};
						}

						// Never move original objects, clone them
						target[ name ] = hyperaudio.extend( deep, clone, copy );

					// Don't bring in undefined values
					} else if ( copy !== undefined ) {
						target[ name ] = copy;
					}
				}
			}
		}

		// Return the modified object
		return target;
	};

	hyperaudio.extend({

		// See test/unit/core.js for details concerning isFunction.
		// Since version 1.3, DOM methods and functions like alert
		// aren't supported. They return false on IE (#2968).
		isFunction: function( obj ) {
			return hyperaudio.type(obj) === "function";
		},

		isArray: Array.isArray,

		isWindow: function( obj ) {
			return obj != null && obj === obj.window;
		},

		type: function( obj ) {
			if ( obj == null ) {
				return String( obj );
			}
			// Support: Safari <= 5.1 (functionish RegExp)
			return typeof obj === "object" || typeof obj === "function" ?
				class2type[ core_toString.call(obj) ] || "object" :
				typeof obj;
		},

		isPlainObject: function( obj ) {
			// Not plain objects:
			// - Any object or value whose internal [[Class]] property is not "[object Object]"
			// - DOM nodes
			// - window
			if ( hyperaudio.type( obj ) !== "object" || obj.nodeType || hyperaudio.isWindow( obj ) ) {
				return false;
			}

			// Support: Firefox <20
			// The try/catch suppresses exceptions thrown when attempting to access
			// the "constructor" property of certain host objects, ie. |window.location|
			// https://bugzilla.mozilla.org/show_bug.cgi?id=814622
			try {
				if ( obj.constructor &&
						!core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
					return false;
				}
			} catch ( e ) {
				return false;
			}

			// If the function hasn't returned already, we're confident that
			// |obj| is a plain object, created by {} or constructed with new Object
			return true;
		}
	});

	function isArraylike( obj ) {
		var length = obj.length,
			type = hyperaudio.type( obj );

		if ( hyperaudio.isWindow( obj ) ) {
			return false;
		}

		if ( obj.nodeType === 1 && length ) {
			return true;
		}

		return type === "array" || type !== "function" &&
			( length === 0 ||
			typeof length === "number" && length > 0 && ( length - 1 ) in obj );
	}
	// [End jQuery code]

	// [Adapted from] jQuery 2.0.3 (c) 2013 http://jquery.com/
	// - each() : removed args parameter (was for use internal to jQuery)

	hyperaudio.extend({
		each: function( obj, callback ) {
			var value,
				i = 0,
				length = obj.length,
				isArray = isArraylike( obj );

			if ( isArray ) {
				for ( ; i < length; i++ ) {
					value = callback.call( obj[ i ], i, obj[ i ] );

					if ( value === false ) {
						break;
					}
				}
			} else {
				for ( i in obj ) {
					value = callback.call( obj[ i ], i, obj[ i ] );

					if ( value === false ) {
						break;
					}
				}
			}

			return obj;
		}
	});
	// [End jQuery code]

	hyperaudio.extend({
		event: {
			ready: 'ha:ready',
			load: 'ha:load',
			save: 'ha:save',
			change: 'ha:change',
			// login: 'ha:login', // No DOM element relating to a login. It is handled by the api.signin when the stage fails to authenticate.
			unauthenticated: 'ha:unauthenticated',
			userplay: 'ha:userplay',
			userpause: 'ha:userpause',
			usercurrenttime: 'ha:usercurrenttime',
			userplayword: 'ha:userplayword',
			error: 'ha:error'
		},
		_commonMethods: {
			options: {
				DEBUG: false,
				entity: 'core'
			},
			_trigger: function(eventType, eventData) {
				var eventObject = hyperaudio.extend(true, {options: this.options}, eventData),
					event = new CustomEvent(eventType, {
						detail: eventObject,
						bubbles: true,
						cancelable: true
					});
				hyperaudio.gaEvent({
					type: this.options.entity,
					action: eventType + ' event: ' + (eventObject.msg ? eventObject.msg : '')
				});
				this.target.dispatchEvent(event);
			},
			_error: function(msg) {
				var data = {msg: this.options.entity + ' Error : ' + msg};
				this._trigger(hyperaudio.event.error, data);
			},
			_debug: function() {
				var self = this;
				hyperaudio.each(hyperaudio.event, function(eventName, eventType) {
					self.target.addEventListener(eventType, function(event) {
						console.log(self.options.entity + ' ' + eventType + ' event : %o', event);
					}, false);
				});
			}
		},
		register: function(name, module) {
			if(typeof name === 'string') {
				if(typeof module === 'function') {
					module.prototype = hyperaudio.extend({}, this._commonMethods, module.prototype);
					this[name] = function(options) {
						return new module(options);
					};
				} else if(typeof module === 'object') {
					module = hyperaudio.extend({}, this._commonMethods, module);
					this[name] = module;
				}
			}
		},
		utility: function(name, utility) {
			if(typeof name === 'string') {
				this[name] = utility;
			}
		},

		// http://stackoverflow.com/questions/1403888/get-url-parameter-with-javascript-or-jquery
		getURLParameter: function(name) {
			// return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
			// Now looks at top window (frame).
			return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(window.top.location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
		},

		gaEvent: function(detail) {
			// detail: {origin, type, action}

			if(typeof detail !== 'object') {
				if(typeof detail === 'string') {
					detail = {
						type: 'message',
						action: detail
					};
				} else {
					detail = {};
				}
			}

			detail.origin = detail.origin ? detail.origin : 'Hyperaudio Lib';
			detail.type = detail.type ? detail.type : 'no type';
			detail.action = detail.action ? detail.action : 'no action';

			var event = new CustomEvent("ga", {
				detail: detail,
				bubbles: true,
				cancelable: true
			});
			document.dispatchEvent(event);
		},

		hasClass: function(e, c) {
			if ( !e ) return false;

			var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
			return re.test(e.className);
		},
		addClass: function(e, c) {
			if ( this.hasClass(e, c) ) {
				return;
			}

			e.className += ' ' + c;
		},
		removeClass: function (e, c) {
			if ( !this.hasClass(e, c) ) {
				return;
			}

			var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
			e.className = e.className.replace(re, ' ').replace(/\s{2,}/g, ' ');
		},
		toggleClass: function (e, c) {
			if ( this.hasClass(e, c) ) {
				this.removeClass(e, c);
			} else {
				this.addClass(e, c);
			}
		}

	});

	return hyperaudio;
}());<commit_msg>Added empty element fn to core.<commit_after>/* Hyperaudio core
 *
 */

var hyperaudio = (function() {

	// jQuery 2.0.3 (c) 2013 http://jquery.com/

	var
		// [[Class]] -> type pairs
		class2type = {},
		core_toString = class2type.toString,
		core_hasOwn = class2type.hasOwnProperty;

	function hyperaudio() {
		// Nada
	}

	hyperaudio.extend = function() {
		var options, name, src, copy, copyIsArray, clone,
			target = arguments[0] || {},
			i = 1,
			length = arguments.length,
			deep = false;

		// Handle a deep copy situation
		if ( typeof target === "boolean" ) {
			deep = target;
			target = arguments[1] || {};
			// skip the boolean and the target
			i = 2;
		}

		// Handle case when target is a string or something (possible in deep copy)
		if ( typeof target !== "object" && !hyperaudio.isFunction(target) ) {
			target = {};
		}

		// extend hyperaudio itself if only one argument is passed
		if ( length === i ) {
			target = this;
			--i;
		}

		for ( ; i < length; i++ ) {
			// Only deal with non-null/undefined values
			if ( (options = arguments[ i ]) != null ) {
				// Extend the base object
				for ( name in options ) {
					src = target[ name ];
					copy = options[ name ];

					// Prevent never-ending loop
					if ( target === copy ) {
						continue;
					}

					// Recurse if we're merging plain objects or arrays
					if ( deep && copy && ( hyperaudio.isPlainObject(copy) || (copyIsArray = hyperaudio.isArray(copy)) ) ) {
						if ( copyIsArray ) {
							copyIsArray = false;
							clone = src && hyperaudio.isArray(src) ? src : [];

						} else {
							clone = src && hyperaudio.isPlainObject(src) ? src : {};
						}

						// Never move original objects, clone them
						target[ name ] = hyperaudio.extend( deep, clone, copy );

					// Don't bring in undefined values
					} else if ( copy !== undefined ) {
						target[ name ] = copy;
					}
				}
			}
		}

		// Return the modified object
		return target;
	};

	hyperaudio.extend({

		// See test/unit/core.js for details concerning isFunction.
		// Since version 1.3, DOM methods and functions like alert
		// aren't supported. They return false on IE (#2968).
		isFunction: function( obj ) {
			return hyperaudio.type(obj) === "function";
		},

		isArray: Array.isArray,

		isWindow: function( obj ) {
			return obj != null && obj === obj.window;
		},

		type: function( obj ) {
			if ( obj == null ) {
				return String( obj );
			}
			// Support: Safari <= 5.1 (functionish RegExp)
			return typeof obj === "object" || typeof obj === "function" ?
				class2type[ core_toString.call(obj) ] || "object" :
				typeof obj;
		},

		isPlainObject: function( obj ) {
			// Not plain objects:
			// - Any object or value whose internal [[Class]] property is not "[object Object]"
			// - DOM nodes
			// - window
			if ( hyperaudio.type( obj ) !== "object" || obj.nodeType || hyperaudio.isWindow( obj ) ) {
				return false;
			}

			// Support: Firefox <20
			// The try/catch suppresses exceptions thrown when attempting to access
			// the "constructor" property of certain host objects, ie. |window.location|
			// https://bugzilla.mozilla.org/show_bug.cgi?id=814622
			try {
				if ( obj.constructor &&
						!core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
					return false;
				}
			} catch ( e ) {
				return false;
			}

			// If the function hasn't returned already, we're confident that
			// |obj| is a plain object, created by {} or constructed with new Object
			return true;
		}
	});

	function isArraylike( obj ) {
		var length = obj.length,
			type = hyperaudio.type( obj );

		if ( hyperaudio.isWindow( obj ) ) {
			return false;
		}

		if ( obj.nodeType === 1 && length ) {
			return true;
		}

		return type === "array" || type !== "function" &&
			( length === 0 ||
			typeof length === "number" && length > 0 && ( length - 1 ) in obj );
	}
	// [End jQuery code]

	// [Adapted from] jQuery 2.0.3 (c) 2013 http://jquery.com/
	// - each() : removed args parameter (was for use internal to jQuery)

	hyperaudio.extend({
		each: function( obj, callback ) {
			var value,
				i = 0,
				length = obj.length,
				isArray = isArraylike( obj );

			if ( isArray ) {
				for ( ; i < length; i++ ) {
					value = callback.call( obj[ i ], i, obj[ i ] );

					if ( value === false ) {
						break;
					}
				}
			} else {
				for ( i in obj ) {
					value = callback.call( obj[ i ], i, obj[ i ] );

					if ( value === false ) {
						break;
					}
				}
			}

			return obj;
		}
	});
	// [End jQuery code]

	hyperaudio.extend({
		event: {
			ready: 'ha:ready',
			load: 'ha:load',
			save: 'ha:save',
			change: 'ha:change',
			// login: 'ha:login', // No DOM element relating to a login. It is handled by the api.signin when the stage fails to authenticate.
			unauthenticated: 'ha:unauthenticated',
			userplay: 'ha:userplay',
			userpause: 'ha:userpause',
			usercurrenttime: 'ha:usercurrenttime',
			userplayword: 'ha:userplayword',
			error: 'ha:error'
		},
		_commonMethods: {
			options: {
				DEBUG: false,
				entity: 'core'
			},
			_trigger: function(eventType, eventData) {
				var eventObject = hyperaudio.extend(true, {options: this.options}, eventData),
					event = new CustomEvent(eventType, {
						detail: eventObject,
						bubbles: true,
						cancelable: true
					});
				hyperaudio.gaEvent({
					type: this.options.entity,
					action: eventType + ' event: ' + (eventObject.msg ? eventObject.msg : '')
				});
				this.target.dispatchEvent(event);
			},
			_error: function(msg) {
				var data = {msg: this.options.entity + ' Error : ' + msg};
				this._trigger(hyperaudio.event.error, data);
			},
			_debug: function() {
				var self = this;
				hyperaudio.each(hyperaudio.event, function(eventName, eventType) {
					self.target.addEventListener(eventType, function(event) {
						console.log(self.options.entity + ' ' + eventType + ' event : %o', event);
					}, false);
				});
			}
		},
		register: function(name, module) {
			if(typeof name === 'string') {
				if(typeof module === 'function') {
					module.prototype = hyperaudio.extend({}, this._commonMethods, module.prototype);
					this[name] = function(options) {
						return new module(options);
					};
				} else if(typeof module === 'object') {
					module = hyperaudio.extend({}, this._commonMethods, module);
					this[name] = module;
				}
			}
		},
		utility: function(name, utility) {
			if(typeof name === 'string') {
				this[name] = utility;
			}
		},

		// http://stackoverflow.com/questions/1403888/get-url-parameter-with-javascript-or-jquery
		getURLParameter: function(name) {
			// return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
			// Now looks at top window (frame).
			return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(window.top.location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
		},

		gaEvent: function(detail) {
			// detail: {origin, type, action}

			if(typeof detail !== 'object') {
				if(typeof detail === 'string') {
					detail = {
						type: 'message',
						action: detail
					};
				} else {
					detail = {};
				}
			}

			detail.origin = detail.origin ? detail.origin : 'Hyperaudio Lib';
			detail.type = detail.type ? detail.type : 'no type';
			detail.action = detail.action ? detail.action : 'no action';

			var event = new CustomEvent("ga", {
				detail: detail,
				bubbles: true,
				cancelable: true
			});
			document.dispatchEvent(event);
		},

		hasClass: function(e, c) {
			if ( !e ) return false;

			var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
			return re.test(e.className);
		},
		addClass: function(e, c) {
			if ( this.hasClass(e, c) ) {
				return;
			}

			e.className += ' ' + c;
		},
		removeClass: function (e, c) {
			if ( !this.hasClass(e, c) ) {
				return;
			}

			var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
			e.className = e.className.replace(re, ' ').replace(/\s{2,}/g, ' ');
		},
		toggleClass: function (e, c) {
			if ( this.hasClass(e, c) ) {
				this.removeClass(e, c);
			} else {
				this.addClass(e, c);
			}
		},
		empty: function(el) {
			// Empties the element... Possibly better than el.innerHTML = '';
			while(el && el.firstChild) {
				el.removeChild(el.firstChild);
			}
		}

	});

	return hyperaudio;
}());<|endoftext|>


<commit_before>// Load paths and gulp
import paths from '../config/paths.json'
import gulp from 'gulp'

// Specific task modules
const wbBuild = require('workbox-build');

// Workbox Task
gulp.task('bundle-sw', () => {
  return wbBuild.generateSW({
    globDirectory: paths.build,
    swDest: paths.build + 'sw.js',
    globPatterns: ['**\/*.{html,js,css}'],
    globIgnores: ['[!tmp-]*.html'],
  })
  .then(() => {
    console.log('Service worker generated.');
  })
  .catch((err) => {
    console.log('[ERROR] This happened: ' + err);
  });
})
<commit_msg>fix(workflow): fix glob!!<commit_after>// Load paths and gulp
import paths from '../config/paths.json'
import gulp from 'gulp'

// Specific task modules
const wbBuild = require('workbox-build');

// Workbox Task
gulp.task('bundle-sw', () => {
  return wbBuild.generateSW({
    globDirectory: paths.build,
    swDest: paths.build + 'sw.js',
    globPatterns: ['**\/*.{html,js,css}'],
    globIgnores: ['tmp-*.html'],
  })
  .then(() => {
    console.log('Service worker generated.');
  })
  .catch((err) => {
    console.log('[ERROR] This happened: ' + err);
  });
})
<|endoftext|>


<commit_before>/* global YT */
import DOM from '../utils/dom';
import Slide from '../modules/slide';

/**
 * Player wrapper around the YT player. This is mostly to get around the event
 * in which we need to play a video which player isn't ready yet.
 */
class Player {
  /**
   * @param {Element} el
   */
  constructor(el) {
    this.ready = false;
    this.onReadyC = null;
    this.slide = Slide.getSectionFromEl(el).section;

    const playerVars = this.getPlayerVars(el);

    this.player = new YT.Player(el, {
      videoId: el.dataset.youtubeId,
      playerVars,
      events: {
        onReady: () => {
          this.ready = true;
          if (this.timeout && this.player.getPlayerState() !== 1) {
            this.play();
          }

          if (this.onReadyC) {
            this.onReadyC();
            this.onReadyC = null;
          }
        }
      }
    });

    this.el = this.player.getIframe();
    this.timeout = null;
  }

  /**
   *
   */
  play() {
    if (this.ready) {
      this.timeout = setTimeout(() => {
        this.timeout = null;
      }, 1000);
      this.player.playVideo();
    } else {
      this.onReadyC = this.play;
    }
  }

  /**
   *
   */
  pause() {
    this.player.pauseVideo();
  }

  /**
   * Get player vars by element.
   * @return {{modestbranding: number}}
   */
  getPlayerVars() {
    const vars = {
      modestbranding: 1,
      rel: 0,
      origin: window.location.origin
    };

    if (this.slide.classList.contains('fullscreen')) {
      // Disabling keyboard interaction for fullscreenvideos
      vars.disablekb = 1;
      vars.showinfo = 0;
    }

    return vars;
  }
}

/**
 * Video plugin.
 */
export default class YouTube {
  /**
   * Grid plugin that shows a grid on top of the WebSlides for easy prototyping.
   * @param {WebSlides} wsInstance The WebSlides instance
   */
  constructor(wsInstance) {
    /**
     * @type {WebSlides}
     * @private
     */
    this.ws_ = wsInstance;

    this.videos = DOM.toArray(this.ws_.el.querySelectorAll('[data-youtube'));

    if (this.videos.length) {
      this.inject();
    }
  }

  /**
   * Once the YouTube API is ready this gets called so we can start the videos.
   */
  onYTReady() {
    this.videos.forEach(video => {
      const player = new Player(video);

      if (typeof video.dataset.autoplay !== 'undefined') {
        const {i} = Slide.getSectionFromEl(player.el);
        const slide = this.ws_.slides[i - 1];

        slide.player = player;
        slide.onEnable(YouTube.onSectionEnabled);
        slide.onDisable(YouTube.onSectionDisabled);

        if (this.ws_.currentSlide_ === slide) {
          YouTube.onSectionEnabled(slide);
        }
      }
    });
  }

  /**
   * Injects the YouTube iFrame API into the page.
   */
  inject() {
    window.onYouTubeIframeAPIReady = this.onYTReady.bind(this);
    const tag = document.createElement('script');
    tag.src = `https://www.youtube.com/iframe_api`;
    const firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  }

  /**
   * On Section enable hook. Will play the video.
   * @param {Slide} slide
   */
  static onSectionEnabled(slide) {
    slide.player.play();
  }

  /**
   * On Section enable hook. Will pause the video.
   * @param {Slide} slide
   */
  static onSectionDisabled(slide) {
    slide.player.pause();
  }
}
<commit_msg>Adding more docs<commit_after>/* global YT */
import DOM from '../utils/dom';
import Slide from '../modules/slide';

/**
 * Player wrapper around the YT player. This is mostly to get around the event
 * in which we need to play a video which player isn't ready yet.
 */
class Player {
  /**
   * @param {Element} el
   */
  constructor(el) {
    this.ready = false;
    this.onReadyC = null;
    this.slide = Slide.getSectionFromEl(el).section;

    const playerVars = this.getPlayerVars(el);

    this.player = new YT.Player(el, {
      videoId: el.dataset.youtubeId,
      playerVars,
      events: {
        onReady: () => {
          this.ready = true;
          if (this.timeout && this.player.getPlayerState() !== 1) {
            this.play();
          }

          if (this.onReadyC) {
            this.onReadyC();
            this.onReadyC = null;
          }
        }
      }
    });

    this.el = this.player.getIframe();
    this.timeout = null;
  }

  /**
   * Plays the video.
   */
  play() {
    if (this.ready) {
      this.timeout = setTimeout(() => {
        this.timeout = null;
      }, 1000);
      this.player.playVideo();
    } else {
      this.onReadyC = this.play;
    }
  }

  /**
   * Pause playing the video if it's already playing.
   */
  pause() {
    if (this.player &&
        this.player.pauseVideo &&
        this.player.getPlayerState() === 1) {
      this.player.pauseVideo();
    }
  }

  /**
   * Get player vars by element.
   * @return {{modestbranding: number}}
   */
  getPlayerVars() {
    const vars = {
      modestbranding: 1,
      rel: 0,
      origin: window.location.origin
    };

    if (this.slide.classList.contains('fullscreen')) {
      // Disabling keyboard interaction for fullscreenvideos
      vars.disablekb = 1;
      vars.showinfo = 0;
    }

    return vars;
  }
}

/**
 * Video plugin.
 */
export default class YouTube {
  /**
   * Grid plugin that shows a grid on top of the WebSlides for easy prototyping.
   * @param {WebSlides} wsInstance The WebSlides instance
   */
  constructor(wsInstance) {
    /**
     * @type {WebSlides}
     * @private
     */
    this.ws_ = wsInstance;

    this.videos = DOM.toArray(this.ws_.el.querySelectorAll('[data-youtube'));

    if (this.videos.length) {
      this.inject();
    }
  }

  /**
   * Once the YouTube API is ready this gets called so we can start the videos.
   */
  onYTReady() {
    this.videos.forEach(video => {
      const player = new Player(video);

      if (typeof video.dataset.autoplay !== 'undefined') {
        const {i} = Slide.getSectionFromEl(player.el);
        const slide = this.ws_.slides[i - 1];

        slide.player = player;
        slide.onEnable(YouTube.onSectionEnabled);
        slide.onDisable(YouTube.onSectionDisabled);

        if (this.ws_.currentSlide_ === slide) {
          YouTube.onSectionEnabled(slide);
        }
      }
    });
  }

  /**
   * Injects the YouTube iFrame API into the page.
   */
  inject() {
    window.onYouTubeIframeAPIReady = this.onYTReady.bind(this);
    const tag = document.createElement('script');
    tag.src = `https://www.youtube.com/iframe_api`;
    const firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  }

  /**
   * On Section enable hook. Will play the video.
   * @param {Slide} slide
   */
  static onSectionEnabled(slide) {
    slide.player.play();
  }

  /**
   * On Section enable hook. Will pause the video.
   * @param {Slide} slide
   */
  static onSectionDisabled(slide) {
    slide.player.pause();
  }
}
<|endoftext|>


<commit_before>/*
  Copyright 2009 The Rhizosphere Authors. All Rights Reserved.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

// RHIZODEP=rhizo.model.loader,rhizo.base,rhizo.ui.component,rhizo.jquery,rhizo.ui.gui
namespace('rhizo.bootstrap');

/**
 * Uuid counter to uniquely identify the container of each visualization within
 * the document.
 * @type {number}
 * @private
 */
rhizo.bootstrap.uuids_ = 0;

/**
 * A Bootstrap is the main entry point to start a Rhizosphere visualization.
 * It takes care of loading the data to visualize, create the chrome and other
 * ui elements for the visualization, and bind all the necessary event handlers.
 *
 * @param {HTMLElement} container The HTML element that will contain the
 *     visualization.
 * @param {*} opt_options Visualization-wide configuration options.
 * @constructor
 */
rhizo.bootstrap.Bootstrap = function(container, opt_options) {
  this.container_ = container;
  var containerId = $(container).attr('id');
  if (!containerId || containerId.length == 0) {
    // Generates a unique element id for the visualization container if one
    // isn't defined yet.
    // The generated id must be consistent over time (assuming the order of
    // bootstrap calls does not change over time when multiple visualizations
    // are present), since long-lived Rhizosphere state representations are
    // based on this.
    $(container).attr('rhizo-uuid-' + (rhizo.bootstrap.uuids_++));
  }
  this.options_ = { selectfilter: '.rhizo-model:visible' };
  if (opt_options) {
    $.extend(this.options_, opt_options);
  }
};

/**
 * Performs all the necessary steps to prepare a Rhizosphere visualization, and
 * then tries loading the given datasource and display it.
 *
 * @param {string} opt_resource The URI of the datasource to load and visualize
 *     with Rhizosphere. If null and the bootstrapper is not allowed to
 *     configure itself from URL parameters, this method behaves like prepare().
 */
rhizo.bootstrap.Bootstrap.prototype.prepareAndDeploy = function(opt_resource) {
  this.prepare();
  this.deploy(opt_resource);
};

/**
 * Performs all the necessary steps to prepare a Rhizosphere visualization, up
 * to the point where it can receive the models to display.
 *
 * Use this method in conjunction with deploy() if you want to be in charge
 * of loading the actual models to visualize.
 */
rhizo.bootstrap.Bootstrap.prototype.prepare = function() {
  // Initialize the GUI, project and template.
  this.gui_ = this.initGui_();
  this.project_ = new rhizo.Project(this.gui_, this.options_);
  this.template_ = this.initTemplate_(this.gui_, this.project_);
  this.project_.chromeReady();
};

/**
 * Loads the data items to visualize from the given datasource URI and displays
 * them in the Rhizosphere visualization managed by this bootstrapper.
 * The boostrapper must have already been prepared before invoking this method.
 *
 * @param {string} opt_resource The URI of the datasource to load and visualize
 *     with Rhizosphere. If null, and the bootstrapper is allowed to configure
 *     itself from the URL parameters, it'll try to extract the datasource URI
 *     from the URL.
 */
rhizo.bootstrap.Bootstrap.prototype.deploy = function(opt_resource) {
  // Identify if we have to load a Rhizosphere datasource. Either we received
  // this information explicitly or we try finding it in the URL.
  var resource = opt_resource || this.tryInitResourceFromUrl_();

  if (resource) {
    rhizo.model.loader.load(resource,
                            jQuery.proxy(this.deployExplicit, this),
                            this.options_,
                            this.project_.logger());
  }
};

/**
 * Loads the data items to visualize via the given loader instance and displays
 * them in the Rhizosphere visualization managed by this bootstrapper.
 * The boostrapper must have already been prepared before invoking this method.
 *
 * @param {*} loader A model loader as defined in rhizo.model.loader.js
 */
rhizo.bootstrap.Bootstrap.prototype.deployWithLoader = function(loader) {
  loader.load(jQuery.proxy(this.deployExplicit, this),
              this.options_, this.project_.logger());
};

/**
 * Displays the given data items (models) in the Rhizosphere visualization
 * managed by this bootstrapper. The boostrapper must have already been
 * prepared before invoking this method.
 *
 * @param {*} metamodel A descriptor for the attributes and properties that
 *     each model in the visualization has.
 * @param {*} renderer A component capable of creating HTML representation of
 *     model instances.
 * @param {Array.<*>} models The list of data items to visualize.
 */
rhizo.bootstrap.Bootstrap.prototype.deployExplicit = function(metamodel,
                                                              renderer,
                                                              models) {
  this.project_.setMetaModel(metamodel);
  this.project_.setRenderer(renderer);

  if (this.project_.metaReady()) {
    this.template_.renderDynamic(this.options_);
    this.template_.activateDynamic(this.options_);
    this.project_.deploy(models);
  }

  this.gui_.done();
  this.template_.done();
};

/**
 * Identify the platform and device we are running onto.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.identifyPlatformAndDevice_ = function() {
  if (this.options_.forcePlatform && this.options_.forceDevice) {
    return {platform: this.options_.forcePlatform,
            device: this.options_.forceDevice};
  }
  var ua = navigator.userAgent;
  if (ua.toLowerCase().indexOf('ipad') != -1) {
    return {platform: 'mobile', device: 'ipad'};
  }
  return {platform: 'default', device: 'default'};
};

/**
 * Identifies the best template to use for the visualization.
 * @param {rhizo.ui.gui.GUI} gui
 * @return {function(rhizo.Project):Object} A constructor for the template to
 *     use.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.identifyTemplate_ = function(gui) {
  var templateCtors = {
    'bottom' : rhizo.ui.component.BottomTemplate,
    'default': rhizo.ui.component.StandardTemplate
  };

  if (this.options_.forceTemplate &&
      this.options_.forceTemplate in templateCtors)
  if (this.options_.forceTemplate) {
    return templateCtors[this.options_.forceTemplate];
  }

  // No specific template has been forced. Select a specific one based on
  // document size and target platform.
  if (gui.isMobile() || gui.isSmall()) {
    return templateCtors['bottom'];
  }
  return templateCtors['default'];
};

/**
 * Identifies the platform and device we are running upon and creates a GUI
 * for this project.
 * @return {rhizo.ui.gui.GUI} The project GUI.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.initGui_ = function() {
  // Identify the target platform and device we are running onto.
  var platformDevice = this.identifyPlatformAndDevice_();

  // Create the GUI.
  var gui = new rhizo.ui.gui.GUI(this.container_,
                                 platformDevice.platform,
                                 platformDevice.device);
  if (this.options_.noAnims) {
    gui.disableFx(true);
  }

  // Extends jQuery with all the additional behaviors required by Rhizosphere
  // Disable animations and other performance tunings if needed.
  //
  // TODO(battlehorse): this must happen at the global level, and not locally
  // for every single visualization.
  // See http://code.google.com/p/rhizosphere/issues/detail?id=68.
  rhizo.jquery.init(gui, this.options_.noAnims);

  return gui;
};

/**
 * Initializes the template that will render this project chrome.
 * @param {rhizo.ui.gui.GUI} gui
 * @param {rhizo.Project} project
 * @return {*} The project template.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.initTemplate_ = function(gui, project) {
  // Identify the target device and template to use.
  var templateCtor = this.identifyTemplate_(gui);
  var template = new templateCtor(this.project_);

  // Get the minimum chrome up and running.
  template.renderChrome(this.options_);
  template.activateChrome(this.options_);
  return template;
};

/**
 * If the bootstrapper is allowed to extract parameters from the document
 * location, tries extracting the URI of the resource to display from the there.
 *
 * @return {string} The URI of the resource to load and display.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.tryInitResourceFromUrl_ = function() {
  if (!this.options_.allowConfigFromUrl) {
    this.project_.logger().warn(
        'Sources extraction from url is disabled');
    return null;
  }

  var regex = new RegExp('(source|src)=([^&#]+)');
  var results = regex.exec(document.location.href);
  if (!results || !results[2]) {
    this.project_.logger().error(
        'Unable to identify datasource from location');
    return null;
  } else {
    return decodeURIComponent(results[2]);
  }
};<commit_msg>Adding iPhone user-agent autodetection in the bootstrap code, to match equivalent functionality in the appengine handlers.<commit_after>/*
  Copyright 2009 The Rhizosphere Authors. All Rights Reserved.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

// RHIZODEP=rhizo.model.loader,rhizo.base,rhizo.ui.component,rhizo.jquery,rhizo.ui.gui
namespace('rhizo.bootstrap');

/**
 * Uuid counter to uniquely identify the container of each visualization within
 * the document.
 * @type {number}
 * @private
 */
rhizo.bootstrap.uuids_ = 0;

/**
 * A Bootstrap is the main entry point to start a Rhizosphere visualization.
 * It takes care of loading the data to visualize, create the chrome and other
 * ui elements for the visualization, and bind all the necessary event handlers.
 *
 * @param {HTMLElement} container The HTML element that will contain the
 *     visualization.
 * @param {*} opt_options Visualization-wide configuration options.
 * @constructor
 */
rhizo.bootstrap.Bootstrap = function(container, opt_options) {
  this.container_ = container;
  var containerId = $(container).attr('id');
  if (!containerId || containerId.length == 0) {
    // Generates a unique element id for the visualization container if one
    // isn't defined yet.
    // The generated id must be consistent over time (assuming the order of
    // bootstrap calls does not change over time when multiple visualizations
    // are present), since long-lived Rhizosphere state representations are
    // based on this.
    $(container).attr('rhizo-uuid-' + (rhizo.bootstrap.uuids_++));
  }
  this.options_ = { selectfilter: '.rhizo-model:visible' };
  if (opt_options) {
    $.extend(this.options_, opt_options);
  }
};

/**
 * Performs all the necessary steps to prepare a Rhizosphere visualization, and
 * then tries loading the given datasource and display it.
 *
 * @param {string} opt_resource The URI of the datasource to load and visualize
 *     with Rhizosphere. If null and the bootstrapper is not allowed to
 *     configure itself from URL parameters, this method behaves like prepare().
 */
rhizo.bootstrap.Bootstrap.prototype.prepareAndDeploy = function(opt_resource) {
  this.prepare();
  this.deploy(opt_resource);
};

/**
 * Performs all the necessary steps to prepare a Rhizosphere visualization, up
 * to the point where it can receive the models to display.
 *
 * Use this method in conjunction with deploy() if you want to be in charge
 * of loading the actual models to visualize.
 */
rhizo.bootstrap.Bootstrap.prototype.prepare = function() {
  // Initialize the GUI, project and template.
  this.gui_ = this.initGui_();
  this.project_ = new rhizo.Project(this.gui_, this.options_);
  this.template_ = this.initTemplate_(this.gui_, this.project_);
  this.project_.chromeReady();
};

/**
 * Loads the data items to visualize from the given datasource URI and displays
 * them in the Rhizosphere visualization managed by this bootstrapper.
 * The boostrapper must have already been prepared before invoking this method.
 *
 * @param {string} opt_resource The URI of the datasource to load and visualize
 *     with Rhizosphere. If null, and the bootstrapper is allowed to configure
 *     itself from the URL parameters, it'll try to extract the datasource URI
 *     from the URL.
 */
rhizo.bootstrap.Bootstrap.prototype.deploy = function(opt_resource) {
  // Identify if we have to load a Rhizosphere datasource. Either we received
  // this information explicitly or we try finding it in the URL.
  var resource = opt_resource || this.tryInitResourceFromUrl_();

  if (resource) {
    rhizo.model.loader.load(resource,
                            jQuery.proxy(this.deployExplicit, this),
                            this.options_,
                            this.project_.logger());
  }
};

/**
 * Loads the data items to visualize via the given loader instance and displays
 * them in the Rhizosphere visualization managed by this bootstrapper.
 * The boostrapper must have already been prepared before invoking this method.
 *
 * @param {*} loader A model loader as defined in rhizo.model.loader.js
 */
rhizo.bootstrap.Bootstrap.prototype.deployWithLoader = function(loader) {
  loader.load(jQuery.proxy(this.deployExplicit, this),
              this.options_, this.project_.logger());
};

/**
 * Displays the given data items (models) in the Rhizosphere visualization
 * managed by this bootstrapper. The boostrapper must have already been
 * prepared before invoking this method.
 *
 * @param {*} metamodel A descriptor for the attributes and properties that
 *     each model in the visualization has.
 * @param {*} renderer A component capable of creating HTML representation of
 *     model instances.
 * @param {Array.<*>} models The list of data items to visualize.
 */
rhizo.bootstrap.Bootstrap.prototype.deployExplicit = function(metamodel,
                                                              renderer,
                                                              models) {
  this.project_.setMetaModel(metamodel);
  this.project_.setRenderer(renderer);

  if (this.project_.metaReady()) {
    this.template_.renderDynamic(this.options_);
    this.template_.activateDynamic(this.options_);
    this.project_.deploy(models);
  }

  this.gui_.done();
  this.template_.done();
};

/**
 * Identify the platform and device we are running onto.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.identifyPlatformAndDevice_ = function() {
  if (this.options_.forcePlatform && this.options_.forceDevice) {
    return {platform: this.options_.forcePlatform,
            device: this.options_.forceDevice};
  }
  var ua = navigator.userAgent;
  if (ua.toLowerCase().indexOf('ipad') != -1) {
    return {platform: 'mobile', device: 'ipad'};
  } else if (ua.toLowerCase().indexOf('iphone') != -1) {
    return {platform: 'mobile', device: 'iphone'};
  }
  return {platform: 'default', device: 'default'};
};

/**
 * Identifies the best template to use for the visualization.
 * @param {rhizo.ui.gui.GUI} gui
 * @return {function(rhizo.Project):Object} A constructor for the template to
 *     use.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.identifyTemplate_ = function(gui) {
  var templateCtors = {
    'bottom' : rhizo.ui.component.BottomTemplate,
    'default': rhizo.ui.component.StandardTemplate
  };

  if (this.options_.forceTemplate &&
      this.options_.forceTemplate in templateCtors)
  if (this.options_.forceTemplate) {
    return templateCtors[this.options_.forceTemplate];
  }

  // No specific template has been forced. Select a specific one based on
  // document size and target platform.
  if (gui.isMobile() || gui.isSmall()) {
    return templateCtors['bottom'];
  }
  return templateCtors['default'];
};

/**
 * Identifies the platform and device we are running upon and creates a GUI
 * for this project.
 * @return {rhizo.ui.gui.GUI} The project GUI.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.initGui_ = function() {
  // Identify the target platform and device we are running onto.
  var platformDevice = this.identifyPlatformAndDevice_();

  // Create the GUI.
  var gui = new rhizo.ui.gui.GUI(this.container_,
                                 platformDevice.platform,
                                 platformDevice.device);
  if (this.options_.noAnims) {
    gui.disableFx(true);
  }

  // Extends jQuery with all the additional behaviors required by Rhizosphere
  // Disable animations and other performance tunings if needed.
  //
  // TODO(battlehorse): this must happen at the global level, and not locally
  // for every single visualization.
  // See http://code.google.com/p/rhizosphere/issues/detail?id=68.
  rhizo.jquery.init(gui, this.options_.noAnims);

  return gui;
};

/**
 * Initializes the template that will render this project chrome.
 * @param {rhizo.ui.gui.GUI} gui
 * @param {rhizo.Project} project
 * @return {*} The project template.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.initTemplate_ = function(gui, project) {
  // Identify the target device and template to use.
  var templateCtor = this.identifyTemplate_(gui);
  var template = new templateCtor(this.project_);

  // Get the minimum chrome up and running.
  template.renderChrome(this.options_);
  template.activateChrome(this.options_);
  return template;
};

/**
 * If the bootstrapper is allowed to extract parameters from the document
 * location, tries extracting the URI of the resource to display from the there.
 *
 * @return {string} The URI of the resource to load and display.
 * @private
 */
rhizo.bootstrap.Bootstrap.prototype.tryInitResourceFromUrl_ = function() {
  if (!this.options_.allowConfigFromUrl) {
    this.project_.logger().warn(
        'Sources extraction from url is disabled');
    return null;
  }

  var regex = new RegExp('(source|src)=([^&#]+)');
  var results = regex.exec(document.location.href);
  if (!results || !results[2]) {
    this.project_.logger().error(
        'Unable to identify datasource from location');
    return null;
  } else {
    return decodeURIComponent(results[2]);
  }
};<|endoftext|>


<commit_before>// Copyright 2002-2012, University of Colorado

/**
 * DOM nodes. Currently lightweight handling
 *
 * @author Jonathan Olson
 */

var phet = phet || {};
phet.scene = phet.scene || {};
phet.scene.nodes = phet.scene.nodes || {};

(function(){
    phet.scene.nodes.DOM = function( node ) {
        phet.scene.Node.call( this );
        this.node = node;

        this.invalidateDOM();

        // can this node be interacted with? if set to true, it will not be layered like normal, but will be placed on top
        this.interactive = false;
    };
    var DOM = phet.scene.nodes.DOM;

    DOM.prototype = Object.create( phet.scene.Node.prototype );
    DOM.prototype.constructor = DOM;

    DOM.prototype.invalidateDOM = function() {
        // TODO: do we need to reset the CSS transform to get the proper bounds?

        // TODO: reset with the proper bounds here
        this.invalidateSelf( phet.math.Bounds2.NOTHING );
    },

    DOM.prototype.renderSelf = function( state ) {
        // something of the form matrix(...) as a String, with a Z translation to trigger hardware acceleration (hopefully)
        var cssTransform = 'translateZ(0) ' + state.transform.getMatrix().cssTransform();

        $( this.node ).css( {
            '-webkit-transform': cssTransform,
            '-moz-transform': cssTransform,
            '-ms-transform': cssTransform,
            '-o-transform': cssTransform,
            'transform': cssTransform,
            'transform-origin': 'top left', // at the origin of the component. consider 0px 0px instead. Critical, since otherwise this defaults to 50% 50%!!! see https://developer.mozilla.org/en-US/docs/CSS/transform-origin
            position: 'absolute',
            left: 0,
            top: 0
        } );

        var layer = ( state.isDOMState() && !this.interactive ) ? state.layer : state.scene.getUILayer();

        var container = layer.getContainer();

        if( this.node.parentNode !== container ) {
            // TODO: correct layering of DOM nodes inside the container
            $( container ).append( this.node );
        }
    };
})();

<commit_msg>Adding -ms-transform-origin<commit_after>// Copyright 2002-2012, University of Colorado

/**
 * DOM nodes. Currently lightweight handling
 *
 * @author Jonathan Olson
 */

var phet = phet || {};
phet.scene = phet.scene || {};
phet.scene.nodes = phet.scene.nodes || {};

(function(){
    phet.scene.nodes.DOM = function( node ) {
        phet.scene.Node.call( this );
        this.node = node;

        this.invalidateDOM();

        // can this node be interacted with? if set to true, it will not be layered like normal, but will be placed on top
        this.interactive = false;
    };
    var DOM = phet.scene.nodes.DOM;

    DOM.prototype = Object.create( phet.scene.Node.prototype );
    DOM.prototype.constructor = DOM;

    DOM.prototype.invalidateDOM = function() {
        // TODO: do we need to reset the CSS transform to get the proper bounds?

        // TODO: reset with the proper bounds here
        this.invalidateSelf( phet.math.Bounds2.NOTHING );
    },

    DOM.prototype.renderSelf = function( state ) {
        // something of the form matrix(...) as a String, with a Z translation to trigger hardware acceleration (hopefully)
        var cssTransform = 'translateZ(0) ' + state.transform.getMatrix().cssTransform();

        $( this.node ).css( {
            '-webkit-transform': cssTransform,
            '-moz-transform': cssTransform,
            '-ms-transform': cssTransform,
            '-o-transform': cssTransform,
            'transform': cssTransform,
            'transform-origin': 'top left', // at the origin of the component. consider 0px 0px instead. Critical, since otherwise this defaults to 50% 50%!!! see https://developer.mozilla.org/en-US/docs/CSS/transform-origin
            '-ms-transform-origin': 'top left',
            position: 'absolute',
            left: 0,
            top: 0
        } );

        var layer = ( state.isDOMState() && !this.interactive ) ? state.layer : state.scene.getUILayer();

        var container = layer.getContainer();

        if( this.node.parentNode !== container ) {
            // TODO: correct layering of DOM nodes inside the container
            $( container ).append( this.node );
        }
    };
})();

<|endoftext|>