<commit_before>/*
 * jQuery UI Spinner @VERSION
 *
 * Copyright (c) 2008 jQuery
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Spinner
 *
 * Depends:
 *  ui.core.js
 */
(function($) {

$.widget('ui.spinner', {
	_init: function() {
		this._trigger('init', null, this.ui(null));

		// perform data bind on generic objects
		if (typeof this.options.items[0] == 'object' && !this.element.is('input')) {
			var data = this.options.items;
			for (var i=0; i<data.length; i++) {
				this._addItem(data[i]);
			}
		}

		// check for decimals in steppinng and set _decimals as internal
		this._decimals = parseInt(this.options.decimals, 10);
		if (this.options.stepping.toString().indexOf('.') != -1) {
			var s = this.options.stepping.toString();
			this._decimals = s.slice(s.indexOf('.')+1, s.length).length;
		}

		//Initialize needed constants
		var self = this;
		this.element
			.addClass('ui-spinner-box')
			.attr('autocomplete', 'off'); // switch off autocomplete in opera

		this._setValue( isNaN(this._getValue()) ? this.options.start : this._getValue() );

		this.element
		.wrap('<div>')
		.parent()
			.addClass('ui-spinner')
			.append('<button class="ui-spinner-up" type="button">▲</button>')
			.find('.ui-spinner-up')
				.bind('mousedown', function(e) {
					$(this).addClass('ui-spinner-pressed');
					if (!self.counter) {
						self.counter = 1;
					}
					self._mousedown(100, '_up', e);
				})
				.bind('mouseup', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.counter == 1) {
						self._up(e);
					}
					self._mouseup(e);
				})
				.bind('mouseout', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.timer) {
						self._mouseup(e);
					}
				})
				// mousedown/mouseup capture first click, now handle second click
				.bind('dblclick', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self._up(e);
					self._mouseup(e);
				})
				.bind('keydown.spinner', function(e) {
					var KEYS = $.keyCode;
					if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.ENTER) {
						$(this).addClass('ui-spinner-pressed');
						if (!self.counter) {
							self.counter = 1;
						}
						self._up.call(self, e);
					} else if (e.keyCode == KEYS.DOWN || e.keyCode == KEYS.RIGHT) {
						self.element.siblings('.ui-spinner-down').focus();
					} else if (e.keyCode == KEYS.LEFT) {
						self.element.focus();
					}
				})
				.bind('keyup.spinner', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self.counter = 0;
					self._propagate('change', e);
				})
			.end()
			.append('<button class="ui-spinner-down" type="button">▼</button>')
			.find('.ui-spinner-down')
				.bind('mousedown', function(e) {
					$(this).addClass('ui-spinner-pressed');
					if (!self.counter) {
						self.counter = 1;
					}
					self._mousedown(100, '_down', e);
				})
				.bind('mouseup', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.counter == 1) {
						self._down();
					}
					self._mouseup(e);
				})
				.bind('mouseout', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.timer) {
						self._mouseup(e);
					}
				})
				// mousedown/mouseup capture first click, now handle second click
				.bind('dblclick', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self._down(e);
					self._mouseup(e);
				})
				.bind('keydown.spinner', function(e) {
					var KEYS = $.keyCode;
					if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.ENTER) {
						$(this).addClass('ui-spinner-pressed');
						if (!self.counter) {
							self.counter = 1;
						}
						self._down.call(self, e);
					} else if (e.keyCode == KEYS.UP || e.keyCode == KEYS.LEFT) {
						self.element.siblings('.ui-spinner-up').focus();
					}
				})
				.bind('keyup.spinner', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self.counter = 0;
					self._propagate('change', e);
				})
			.end();

		// DataList: Set contraints for object length and step size.
		// Manipulate height of spinner.
		this._items = this.element.children().length;
		if (this._items > 1) {
			var height = this.element.outerHeight()/this._items;
			this.element
			.addClass('ui-spinner-list')
			.height(height)
			.children()
				.addClass('ui-spinner-listitem')
				.height(height)
				.css('overflow', 'hidden')
			.end()
			.parent()
				.height(height)
			.end();
			this.options.stepping = 1;
			this.options.min = 0;
			this.options.max = this._items-1;
		}

		this.element
		.bind('keydown.spinner', function(e) {
			if (!self.counter) {
				self.counter = 1;
			}
			return self._keydown.call(self, e);
		})
		.bind('keyup.spinner', function(e) {
			self.counter = 0;
			self._propagate('change', e);
		})
		.bind('blur.spinner', function(e) {
			self._cleanUp();
		});

		if ($.fn.mousewheel) {
			this.element.mousewheel(function(e, delta) {
				self._mousewheel(e, delta);
			});
		}
	},

	_constrain: function() {
		if (this.options.min != undefined && this._getValue() < this.options.min) {
			this._setValue(this.options.min);
		}
		if (this.options.max != undefined && this._getValue() > this.options.max) {
			this._setValue(this.options.max);
		}
	},
	_cleanUp: function() {
		this._setValue(this._getValue());
		this._constrain();
	},
	_spin: function(d, e) {
		if (this.disabled) {
			return;
		}

		if (isNaN(this._getValue())) {
			this._setValue(this.options.start);
		}
		this._setValue(this._getValue() + (d == 'up' ? 1:-1) * (this.options.incremental && this.counter > 100 ? (this.counter > 200 ? 100 : 10) : 1) * this.options.stepping);
		this._animate(d);
		this._constrain();
		if (this.counter) {
			this.counter++;
		}
		this._propagate('spin', e);
	},
	_down: function(e) {
		this._spin('down', e);
		this._propagate('down', e);
	},
	_up: function(e) {
		this._spin('up', e);
		this._propagate('up', e);
	},
	_mousedown: function(i, d, e) {
		var self = this;
		i = i || 100;
		if (this.timer) {
			window.clearInterval(this.timer);
			this.timer = 0;
		}
		this.timer = window.setInterval(function() {
			self[d](e);
			if (self.counter > 20) {
				self._mousedown(20, d, e);
			}
		}, i);
	},
	_mouseup: function(e) {
		this.counter = 0;
		if (this.timer) {
			window.clearInterval(this.timer);
			this.timer = 0;
		}
		this.element[0].focus();
		this._propagate('change', e);
	},
	_keydown: function(e) {
		var KEYS = $.keyCode;

		if (e.keyCode == KEYS.UP) {
			this._up(e);
		}
		if (e.keyCode == KEYS.DOWN) {
			this._down(e);
		}
		if (e.keyCode == KEYS.HOME) {
			//Home key goes to min, if defined, else to start
			this._setValue(this.options.min || this.options.start);
		}
		if (e.keyCode == KEYS.END && this.options.max != undefined) {
			//End key goes to maximum
			this._setValue(this.options.max);
		}
		return (e.keyCode == KEYS.TAB || e.keyCode == KEYS.BACKSPACE ||
			e.keyCode == KEYS.LEFT || e.keyCode == KEYS.RIGHT || e.keyCode == KEYS.PERIOD ||
			e.keyCode == KEYS.NUMPAD_DECIMAL || e.keyCode == KEYS.NUMPAD_SUBTRACT ||
			(e.keyCode >= 96 && e.keyCode <= 105) || // add support for numeric keypad 0-9
			(/[0-9\-\.]/).test(String.fromCharCode(e.keyCode))) ? true : false;
	},
	_mousewheel: function(e, delta) {
		var self = this;
		delta = ($.browser.opera ? -delta / Math.abs(delta) : delta);
		(delta > 0 ? self._up(e) : self._down(e));
		if (self.timeout) {
			window.clearTimeout(self.timeout);
			self.timeout = 0;
		}
		self.timeout = window.setTimeout(function(){self._propagate('change', e)}, 400);
		e.preventDefault();
	},
	_getValue: function() {
		return parseFloat(this.element.val().replace(/[^0-9\-\.]/g, ''));
	},
	_setValue: function(newVal) {
		if (isNaN(newVal)) {
			newVal = this.options.start;
		}
		this.element.val(
			this.options.currency ?
				$.ui.spinner.format.currency(newVal, this.options.currency) :
				$.ui.spinner.format.number(newVal, this._decimals)
		);
	},
	_animate: function(d) {
		if (this.element.hasClass('ui-spinner-list') && ((d == 'up' && this._getValue() <= this.options.max) || (d == 'down' && this._getValue() >= this.options.min)) ) {
			this.element.animate({marginTop: '-' + this._getValue() * this.element.parent().height() }, {
				duration: 'fast',
				queue: false
			});
		}
	},
	_addItem: function(obj, fmt) {
		if (!this.element.is('input')) {
			var wrapper = 'div';
			if (this.element.is('ol') || this.element.is('ul')) {
				wrapper = 'li';
			}
			var html = obj; // string or object set it to html first

			if (typeof obj == 'object') {
				var format = (fmt !== undefined ? fmt : this.options.format);

				html = format.replace(/%(\(([^)]+)\))?/g,
					(function(data){
						return function(match, a, lbl) {
							if (!lbl) {
								for (var itm in data) {
									return data[itm]; // return the first item only
								}
							} else {
								return data[lbl];
							}
						};
					})(obj)
				);
			}
			this.element.append('<'+ wrapper +' class="ui-spinner-dyn">'+ html + '</'+ wrapper +'>');
		}
	},

	plugins: {},
	ui: function(e) {
		return {
			options: this.options,
			element: this.element,
			value: this._getValue(),
			add: this._addItem
		};
	},
	_propagate: function(n,e) {
		$.ui.plugin.call(this, n, [e, this.ui()]);
		return this.element.triggerHandler(n == 'spin' ? n : 'spin'+n, [e, this.ui()], this.options[n]);
	},
	destroy: function() {
		if (!$.data(this.element[0], 'spinner')) {
			return;
		}
		if ($.fn.mousewheel) {
			this.element.unmousewheel();
		}
		this.element
			.removeClass('ui-spinner-box ui-spinner-list')
			.removeAttr('disabled')
			.removeAttr('autocomplete')
			.removeData('spinner')
			.unbind('.spinner')
			.siblings()
				.remove()
			.end()
			.children()
				.removeClass('ui-spinner-listitem')
				.remove('.ui-spinner-dyn')
			.end()
			.parent()
				.removeClass('ui-spinner ui-spinner-disabled')
				.before(this.element.clone())
				.remove()
			.end();
	},
	enable: function() {
		this.element
			.removeAttr('disabled')
			.siblings()
				.removeAttr('disabled')
			.parent()
				.removeClass('ui-spinner-disabled');
		this.disabled = false;
	},
	disable: function() {
		this.element
			.attr('disabled', true)
			.siblings()
				.attr('disabled', true)
			.parent()
				.addClass('ui-spinner-disabled');
		this.disabled = true;
	}
});

$.extend($.ui.spinner, {
	defaults: {
		decimals: 0,
		stepping: 1,
		start: 0,
		incremental: true,
		currency: false,
		format: '%',
		items: []
	},
	format: {
		currency: function(num, sym) {
			num = isNaN(num) ? 0 : num;
			return (num !== Math.abs(num) ? '-' : '') + sym + this.number(Math.abs(num), 2);
		},
		number: function(num, dec) {
			num = isNaN(num) ? 0 : parseFloat(num,10).toFixed(dec);

			var regex = /(\d+)(\d{3})/,
				n = num.toString().split('.'),
				n1 = n[0],
				n2 = n.length > 1 ? '.' + n[1] : '';

			while (regex.test(n1)) {
				n1 = n1.replace(regex, '$1,$2');
			}

			return (n1 + n2);
		}
	}
});

})(jQuery);
<commit_msg>Spinner: further refactored number formatter. 3 lines!<commit_after>/*
 * jQuery UI Spinner @VERSION
 *
 * Copyright (c) 2008 jQuery
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Spinner
 *
 * Depends:
 *  ui.core.js
 */
(function($) {

$.widget('ui.spinner', {
	_init: function() {
		this._trigger('init', null, this.ui(null));

		// perform data bind on generic objects
		if (typeof this.options.items[0] == 'object' && !this.element.is('input')) {
			var data = this.options.items;
			for (var i=0; i<data.length; i++) {
				this._addItem(data[i]);
			}
		}

		// check for decimals in steppinng and set _decimals as internal
		this._decimals = parseInt(this.options.decimals, 10);
		if (this.options.stepping.toString().indexOf('.') != -1) {
			var s = this.options.stepping.toString();
			this._decimals = s.slice(s.indexOf('.')+1, s.length).length;
		}

		//Initialize needed constants
		var self = this;
		this.element
			.addClass('ui-spinner-box')
			.attr('autocomplete', 'off'); // switch off autocomplete in opera

		this._setValue( isNaN(this._getValue()) ? this.options.start : this._getValue() );

		this.element
		.wrap('<div>')
		.parent()
			.addClass('ui-spinner')
			.append('<button class="ui-spinner-up" type="button">▲</button>')
			.find('.ui-spinner-up')
				.bind('mousedown', function(e) {
					$(this).addClass('ui-spinner-pressed');
					if (!self.counter) {
						self.counter = 1;
					}
					self._mousedown(100, '_up', e);
				})
				.bind('mouseup', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.counter == 1) {
						self._up(e);
					}
					self._mouseup(e);
				})
				.bind('mouseout', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.timer) {
						self._mouseup(e);
					}
				})
				// mousedown/mouseup capture first click, now handle second click
				.bind('dblclick', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self._up(e);
					self._mouseup(e);
				})
				.bind('keydown.spinner', function(e) {
					var KEYS = $.keyCode;
					if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.ENTER) {
						$(this).addClass('ui-spinner-pressed');
						if (!self.counter) {
							self.counter = 1;
						}
						self._up.call(self, e);
					} else if (e.keyCode == KEYS.DOWN || e.keyCode == KEYS.RIGHT) {
						self.element.siblings('.ui-spinner-down').focus();
					} else if (e.keyCode == KEYS.LEFT) {
						self.element.focus();
					}
				})
				.bind('keyup.spinner', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self.counter = 0;
					self._propagate('change', e);
				})
			.end()
			.append('<button class="ui-spinner-down" type="button">▼</button>')
			.find('.ui-spinner-down')
				.bind('mousedown', function(e) {
					$(this).addClass('ui-spinner-pressed');
					if (!self.counter) {
						self.counter = 1;
					}
					self._mousedown(100, '_down', e);
				})
				.bind('mouseup', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.counter == 1) {
						self._down();
					}
					self._mouseup(e);
				})
				.bind('mouseout', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					if (self.timer) {
						self._mouseup(e);
					}
				})
				// mousedown/mouseup capture first click, now handle second click
				.bind('dblclick', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self._down(e);
					self._mouseup(e);
				})
				.bind('keydown.spinner', function(e) {
					var KEYS = $.keyCode;
					if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.ENTER) {
						$(this).addClass('ui-spinner-pressed');
						if (!self.counter) {
							self.counter = 1;
						}
						self._down.call(self, e);
					} else if (e.keyCode == KEYS.UP || e.keyCode == KEYS.LEFT) {
						self.element.siblings('.ui-spinner-up').focus();
					}
				})
				.bind('keyup.spinner', function(e) {
					$(this).removeClass('ui-spinner-pressed');
					self.counter = 0;
					self._propagate('change', e);
				})
			.end();

		// DataList: Set contraints for object length and step size.
		// Manipulate height of spinner.
		this._items = this.element.children().length;
		if (this._items > 1) {
			var height = this.element.outerHeight()/this._items;
			this.element
			.addClass('ui-spinner-list')
			.height(height)
			.children()
				.addClass('ui-spinner-listitem')
				.height(height)
				.css('overflow', 'hidden')
			.end()
			.parent()
				.height(height)
			.end();
			this.options.stepping = 1;
			this.options.min = 0;
			this.options.max = this._items-1;
		}

		this.element
		.bind('keydown.spinner', function(e) {
			if (!self.counter) {
				self.counter = 1;
			}
			return self._keydown.call(self, e);
		})
		.bind('keyup.spinner', function(e) {
			self.counter = 0;
			self._propagate('change', e);
		})
		.bind('blur.spinner', function(e) {
			self._cleanUp();
		});

		if ($.fn.mousewheel) {
			this.element.mousewheel(function(e, delta) {
				self._mousewheel(e, delta);
			});
		}
	},

	_constrain: function() {
		if (this.options.min != undefined && this._getValue() < this.options.min) {
			this._setValue(this.options.min);
		}
		if (this.options.max != undefined && this._getValue() > this.options.max) {
			this._setValue(this.options.max);
		}
	},
	_cleanUp: function() {
		this._setValue(this._getValue());
		this._constrain();
	},
	_spin: function(d, e) {
		if (this.disabled) {
			return;
		}

		if (isNaN(this._getValue())) {
			this._setValue(this.options.start);
		}
		this._setValue(this._getValue() + (d == 'up' ? 1:-1) * (this.options.incremental && this.counter > 100 ? (this.counter > 200 ? 100 : 10) : 1) * this.options.stepping);
		this._animate(d);
		this._constrain();
		if (this.counter) {
			this.counter++;
		}
		this._propagate('spin', e);
	},
	_down: function(e) {
		this._spin('down', e);
		this._propagate('down', e);
	},
	_up: function(e) {
		this._spin('up', e);
		this._propagate('up', e);
	},
	_mousedown: function(i, d, e) {
		var self = this;
		i = i || 100;
		if (this.timer) {
			window.clearInterval(this.timer);
			this.timer = 0;
		}
		this.timer = window.setInterval(function() {
			self[d](e);
			if (self.counter > 20) {
				self._mousedown(20, d, e);
			}
		}, i);
	},
	_mouseup: function(e) {
		this.counter = 0;
		if (this.timer) {
			window.clearInterval(this.timer);
			this.timer = 0;
		}
		this.element[0].focus();
		this._propagate('change', e);
	},
	_keydown: function(e) {
		var KEYS = $.keyCode;

		if (e.keyCode == KEYS.UP) {
			this._up(e);
		}
		if (e.keyCode == KEYS.DOWN) {
			this._down(e);
		}
		if (e.keyCode == KEYS.HOME) {
			//Home key goes to min, if defined, else to start
			this._setValue(this.options.min || this.options.start);
		}
		if (e.keyCode == KEYS.END && this.options.max != undefined) {
			//End key goes to maximum
			this._setValue(this.options.max);
		}
		return (e.keyCode == KEYS.TAB || e.keyCode == KEYS.BACKSPACE ||
			e.keyCode == KEYS.LEFT || e.keyCode == KEYS.RIGHT || e.keyCode == KEYS.PERIOD ||
			e.keyCode == KEYS.NUMPAD_DECIMAL || e.keyCode == KEYS.NUMPAD_SUBTRACT ||
			(e.keyCode >= 96 && e.keyCode <= 105) || // add support for numeric keypad 0-9
			(/[0-9\-\.]/).test(String.fromCharCode(e.keyCode))) ? true : false;
	},
	_mousewheel: function(e, delta) {
		var self = this;
		delta = ($.browser.opera ? -delta / Math.abs(delta) : delta);
		(delta > 0 ? self._up(e) : self._down(e));
		if (self.timeout) {
			window.clearTimeout(self.timeout);
			self.timeout = 0;
		}
		self.timeout = window.setTimeout(function(){self._propagate('change', e)}, 400);
		e.preventDefault();
	},
	_getValue: function() {
		return parseFloat(this.element.val().replace(/[^0-9\-\.]/g, ''));
	},
	_setValue: function(newVal) {
		if (isNaN(newVal)) {
			newVal = this.options.start;
		}
		this.element.val(
			this.options.currency ?
				$.ui.spinner.format.currency(newVal, this.options.currency) :
				$.ui.spinner.format.number(newVal, this._decimals)
		);
	},
	_animate: function(d) {
		if (this.element.hasClass('ui-spinner-list') && ((d == 'up' && this._getValue() <= this.options.max) || (d == 'down' && this._getValue() >= this.options.min)) ) {
			this.element.animate({marginTop: '-' + this._getValue() * this.element.parent().height() }, {
				duration: 'fast',
				queue: false
			});
		}
	},
	_addItem: function(obj, fmt) {
		if (!this.element.is('input')) {
			var wrapper = 'div';
			if (this.element.is('ol') || this.element.is('ul')) {
				wrapper = 'li';
			}
			var html = obj; // string or object set it to html first

			if (typeof obj == 'object') {
				var format = (fmt !== undefined ? fmt : this.options.format);

				html = format.replace(/%(\(([^)]+)\))?/g,
					(function(data){
						return function(match, a, lbl) {
							if (!lbl) {
								for (var itm in data) {
									return data[itm]; // return the first item only
								}
							} else {
								return data[lbl];
							}
						};
					})(obj)
				);
			}
			this.element.append('<'+ wrapper +' class="ui-spinner-dyn">'+ html + '</'+ wrapper +'>');
		}
	},

	plugins: {},
	ui: function(e) {
		return {
			options: this.options,
			element: this.element,
			value: this._getValue(),
			add: this._addItem
		};
	},
	_propagate: function(n,e) {
		$.ui.plugin.call(this, n, [e, this.ui()]);
		return this.element.triggerHandler(n == 'spin' ? n : 'spin'+n, [e, this.ui()], this.options[n]);
	},
	destroy: function() {
		if (!$.data(this.element[0], 'spinner')) {
			return;
		}
		if ($.fn.mousewheel) {
			this.element.unmousewheel();
		}
		this.element
			.removeClass('ui-spinner-box ui-spinner-list')
			.removeAttr('disabled')
			.removeAttr('autocomplete')
			.removeData('spinner')
			.unbind('.spinner')
			.siblings()
				.remove()
			.end()
			.children()
				.removeClass('ui-spinner-listitem')
				.remove('.ui-spinner-dyn')
			.end()
			.parent()
				.removeClass('ui-spinner ui-spinner-disabled')
				.before(this.element.clone())
				.remove()
			.end();
	},
	enable: function() {
		this.element
			.removeAttr('disabled')
			.siblings()
				.removeAttr('disabled')
			.parent()
				.removeClass('ui-spinner-disabled');
		this.disabled = false;
	},
	disable: function() {
		this.element
			.attr('disabled', true)
			.siblings()
				.attr('disabled', true)
			.parent()
				.addClass('ui-spinner-disabled');
		this.disabled = true;
	}
});

$.extend($.ui.spinner, {
	defaults: {
		decimals: 0,
		stepping: 1,
		start: 0,
		incremental: true,
		currency: false,
		format: '%',
		items: []
	},
	format: {
		currency: function(num, sym) {
			num = isNaN(num) ? 0 : num;
			return (num !== Math.abs(num) ? '-' : '') + sym + this.number(Math.abs(num), 2);
		},
		number: function(num, dec) {
			var regex = /(\d+)(\d{3})/;
			for (num = isNaN(num) ? 0 : parseFloat(num,10).toFixed(dec); regex.test(num); num=num.replace(regex, '$1,$2'));
			return num;
		}
	}
});

})(jQuery);
<|endoftext|>


<commit_before>$(document).on('ready', function(){
	var headerHeight = $('.navbar').height();
	var footerHeight = $('footer').height();
	var bottomPadding = 75;
	var codeAreaHeight = $(window).height() - headerHeight - footerHeight - bottomPadding;
	var margin = 20;
	var chatAreaHeight = codeAreaHeight - $('#chat-box').height() - margin;
	$('#code').css('height', codeAreaHeight);
	$('#chat').css('height', chatAreaHeight);

	// allow tab character in the code textarea
	$(document).delegate('#code', 'keydown', function(e){
		var keyCode = e.keyCode || e.which;
		if (keyCode == 9) {
			e.preventDefault();
			var start = $(this).get(0).selectionStart;
			var end = $(this).get(0).selectionEnd;
			$(this).val($(this).val().substring(0, start) + '\t' + $(this).val().substring(end));
			$(this).get(0).selectionStart = $(this).get(0).selectionEnd = start + 1;
		}
	});

	// have enter key submit chat message
	$(document).delegate('#chat-box', 'keydown', function(e){
		var keyCode = e.keyCode || e.which;
		if (keyCode == 13) {
			e.preventDefault();
			$('#chat-button').click();
		}
	});

	var socketAttrs = {
		name: null,
		color: null
	}
	var socket = io.connect();
	socket.on('update-chat', function(name, color, msg) {
		updateChat('' + name + ': ' + msg);
	});
	socket.on('user-connected', function(name, color) {
		updateChat('' + name + ' has connected to the session.');
	});
	socket.on('user-disconnected', function(name, color) {
		updateChat('' + name + ' has left the session.');
	});
	socket.on('user-set', function(name, color) {
		socketAttrs.name = name;
		socketAttrs.color = color;
	});
	socket.emit('set-user', user.firstName, session.shortCode);

	$('#chat-button').on('click', function(){
		var chatBox = $('#chat-box');
		socket.emit('send-chat-message', chatBox.val());
		// update the sender's chat box immediately, since there's
		// no need to wait for the server to respond (makes it look faster)
		updateChat('' + socketAttrs.name + ': ' + chatBox.val());
		chatBox.val('');
	})

	var updateChat = function(msg) {
		$('#chat').append('
' + msg + '
');
	}
});<commit_msg>chat to scroll down automatically once overflow is reached<commit_after>$(document).on('ready', function(){
	var headerHeight = $('.navbar').height();
	var footerHeight = $('footer').height();
	var bottomPadding = 75;
	var codeAreaHeight = $(window).height() - headerHeight - footerHeight - bottomPadding;
	var margin = 20;
	var chatAreaHeight = codeAreaHeight - $('#chat-box').height() - margin;
	$('#code').css('height', codeAreaHeight);
	$('#chat').css('height', chatAreaHeight);

	// allow tab character in the code textarea
	$(document).delegate('#code', 'keydown', function(e){
		var keyCode = e.keyCode || e.which;
		if (keyCode == 9) {
			e.preventDefault();
			var start = $(this).get(0).selectionStart;
			var end = $(this).get(0).selectionEnd;
			$(this).val($(this).val().substring(0, start) + '\t' + $(this).val().substring(end));
			$(this).get(0).selectionStart = $(this).get(0).selectionEnd = start + 1;
		}
	});

	// have enter key submit chat message
	$(document).delegate('#chat-box', 'keydown', function(e){
		var keyCode = e.keyCode || e.which;
		if (keyCode == 13) {
			e.preventDefault();
			$('#chat-button').click();
		}
	});

	var socketAttrs = {
		name: null,
		color: null
	}
	var socket = io.connect();
	socket.on('update-chat', function(name, color, msg) {
		updateChat('' + name + ': ' + msg);
	});
	socket.on('user-connected', function(name, color) {
		updateChat('' + name + ' has connected to the session.');
	});
	socket.on('user-disconnected', function(name, color) {
		updateChat('' + name + ' has left the session.');
	});
	socket.on('user-set', function(name, color) {
		socketAttrs.name = name;
		socketAttrs.color = color;
	});
	socket.emit('set-user', user.firstName, session.shortCode);

	$('#chat-button').on('click', function(){
		var chatBox = $('#chat-box');
		if (chatBox.val().trim() == '') return;
		socket.emit('send-chat-message', chatBox.val().trim());
		// update the sender's chat box immediately, since there's
		// no need to wait for the server to respond (makes it look faster)
		updateChat('' + socketAttrs.name + ': ' + chatBox.val());
		chatBox.val('');
	})

	var updateChat = function(msg) {
		chat = $('#chat');
		chat.append('
' + msg + '
');
		chat.scrollTop(chat.prop("scrollHeight"));
	}
});<|endoftext|>


<commit_before>/*
  Aras.HTML5 provides a HTML5 client library to build Aras Innovator Applications

  Copyright (C) 2015 Processwall Limited.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published
  by the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see http://opensource.org/licenses/AGPL-3.0.

  Company: Processwall Limited
  Address: The Winnowing House, Mill Lane, Askham Richard, York, YO23 3NW, United Kingdom
  Tel:     +44 113 815 3440
  Email:   support@processwall.com
*/

define([
	'dojo/_base/declare',
	'dijit/layout/ContentPane'
], function(declare, ContentPane) {

	return declare('Aras.View.PDF', [ContentPane], {

		url: null,

		_updateContent: function() {
			this.set('content', '<object style="width: 100%; height: 100%" class="arasPDF" data="' + this.url + '" type="application/pdf"/>');
		},

		startup: function() {
			this.inherited(arguments);

			this._updateContent();
		}

	});
});<commit_msg>Added watch to URL in PDF<commit_after>/*
  Aras.HTML5 provides a HTML5 client library to build Aras Innovator Applications

  Copyright (C) 2015 Processwall Limited.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published
  by the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see http://opensource.org/licenses/AGPL-3.0.

  Company: Processwall Limited
  Address: The Winnowing House, Mill Lane, Askham Richard, York, YO23 3NW, United Kingdom
  Tel:     +44 113 815 3440
  Email:   support@processwall.com
*/

define([
	'dojo/_base/declare',
	'dojo/_base/lang',
	'dijit/layout/ContentPane'
], function(declare, lang, ContentPane) {

	return declare('Aras.View.PDF', [ContentPane], {

		url: null,

		_updateContent: function() {

			if (this.url != null)
			{
				this.set('content', '<object style="width: 100%; height: 100%" class="arasPDF" data="' + this.url + '" type="application/pdf"/>');
			}
			else
			{
				this.set('content', '');
			}
		},

		startup: function() {
			this.inherited(arguments);

			this._updateContent();

			this.watch('url', lang.hitch(this, function(name, oldval, newcal) {
				this._updateContent();
			}));
		}

	});
});<|endoftext|>


<commit_before>// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html

module.exports = function(config) {
  config.set({
    // base path, that will be used to resolve files and exclude
    basePath: '',

    // testing framework to use (jasmine/mocha/qunit/...)
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'app/bower_components/angular/angular.js',
      'node_modules/hoodie-plugin-angularjs/hoodie.angularjs.js',
      'app/bower_components/debug-browser/debug.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
//      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-animate/angular-animate.js',
      'app/bower_components/angular-datepicker/app/scripts/datePicker.js',
      'app/bower_components/angular-duration-filter/src/duration.js',
      'app/bower_components/angular-elastic/elastic.js',
      'app/bower_components/angular-loading-bar/src/loading-bar.js',
      'app/bower_components/angular-touch/angular-touch.js',
      'app/bower_components/angular-ui-router/release/angular-ui-router.js',
      'app/bower_components/bradypodion/dist/bradypodion.js',
      'app/scripts/*.js',
      'app/scripts/**/*.js',
//      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [],

    // web server port
    port: 8080,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};
<commit_msg>add ui.bootstrap to tests, now work again<commit_after>// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html

module.exports = function(config) {
  config.set({
    // base path, that will be used to resolve files and exclude
    basePath: '',

    // testing framework to use (jasmine/mocha/qunit/...)
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'app/bower_components/angular/angular.js',
      'node_modules/hoodie-plugin-angularjs/hoodie.angularjs.js',
      'app/bower_components/debug-browser/debug.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
//      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-animate/angular-animate.js',
      'app/bower_components/angular-datepicker/app/scripts/datePicker.js',
      'app/bower_components/angular-duration-filter/src/duration.js',
      'app/bower_components/angular-elastic/elastic.js',
      'app/bower_components/angular-loading-bar/src/loading-bar.js',
      'app/bower_components/angular-touch/angular-touch.js',
      'app/bower_components/angular-ui-router/release/angular-ui-router.js',
      'app/bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
      'app/bower_components/bradypodion/dist/bradypodion.js',
      'app/scripts/*.js',
      'app/scripts/**/*.js',
//      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [],

    // web server port
    port: 8080,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

import {LitElement, html} from 'lit-element';

import * as promptApi from '../utils/PromptApiService';

export class VoxPrompts extends LitElement {
    static get properties() {
        return {
            prompt: {type: String},
            state: {type: String},
        };
    }

    constructor() {
        super();
        this.state = 'NOT_ASKED';
        this.getNewPrompt();
    }

    async getNewPrompt() {
        this.state = 'LOADING';
        const promptRequest = await promptApi.getNewPrompt();

        if (promptRequest.status === 'SUCCESS') {
            this.state = 'SUCCESS';
            this.prompt = promptRequest.prompt;
        } else if (promptRequest.status === 'EMPTY') {
            this.state = 'FINISHED';
        } else {
            this.state = 'FAILURE';
        }
    }

    handleSkip() {
        this.getNewPrompt();
    }

    renderPromptType() {
        switch (this.prompt.type) {
            case 'TEXT':
                return html`<p>${this.prompt.body}</p>`;
            case 'IMAGE':
                return html`<img
                    src="${this.prompt.body}"
                    alt="Prompt Image"
                />`;
        }
    }

    renderPromptState() {
        switch (this.state) {
            case 'NOT_ASKED':
                return html`<p>haven't asked yet</p>`;
            case 'LOADING':
                return html`<p>Loading</p>`;
            case 'SUCCESS':
                return this.renderPromptType();
            case 'FAILURE':
                return html`<p><b>Prompt failed to load.</b></p>`;
            case 'FINISHED':
                return html`<p><i>No more prompts...</i></p>`;
        }
    }

    render() {
        return html`
            ${this.renderPromptState()}

            <button @click="${this.handleSkip}">skip</button>
            <button @click="${promptApi.resetAllPromptsUnread}">
                reset all prompts to unread
            </button>
        `;
    }
}

customElements.define('vox-prompts', VoxPrompts);
<commit_msg>use firstUpdated()<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

import {LitElement, html} from 'lit-element';

import * as promptApi from '../utils/PromptApiService';

export class VoxPrompts extends LitElement {
    static get properties() {
        return {
            prompt: {type: String},
            state: {type: String},
        };
    }

    constructor() {
        super();
        this.state = 'NOT_ASKED';
    }

    firstUpdated() {
        this.getNewPrompt();
    }

    async getNewPrompt() {
        this.state = 'LOADING';
        const promptRequest = await promptApi.getNewPrompt();

        if (promptRequest.status === 'SUCCESS') {
            this.state = 'SUCCESS';
            this.prompt = promptRequest.prompt;
        } else if (promptRequest.status === 'EMPTY') {
            this.state = 'FINISHED';
        } else {
            this.state = 'FAILURE';
        }
    }

    handleSkip() {
        this.getNewPrompt();
    }

    renderPromptType() {
        switch (this.prompt.type) {
            case 'TEXT':
                return html`<p>${this.prompt.body}</p>`;
            case 'IMAGE':
                return html`<img
                    src="${this.prompt.body}"
                    alt="Prompt Image"
                />`;
        }
    }

    renderPromptState() {
        switch (this.state) {
            case 'NOT_ASKED':
                return html`<p>haven't asked yet</p>`;
            case 'LOADING':
                return html`<p>Loading</p>`;
            case 'SUCCESS':
                return this.renderPromptType();
            case 'FAILURE':
                return html`<p><b>Prompt failed to load.</b></p>`;
            case 'FINISHED':
                return html`<p><i>No more prompts...</i></p>`;
        }
    }

    render() {
        return html`
            ${this.renderPromptState()}

            <button @click="${this.handleSkip}">skip</button>
            <button @click="${promptApi.resetAllPromptsUnread}">
                reset all prompts to unread
            </button>
        `;
    }
}

customElements.define('vox-prompts', VoxPrompts);
<|endoftext|>


<commit_before>'use strict';

// https://www.html5rocks.com/en/tutorials/pointerlock/intro/

function PointerLockManager() {
    this.__init__();
}

PointerLockManager.prototype = {
    __init__: function () {
        this.element = document.body;
        this.has_pointer_lock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
        if (this.has_pointer_lock === true) {
            //console.log('Pointer lock is supported!')

            // Hook pointer lock state change events.
            document.addEventListener('pointerlockchange', this.pointer_lock_change.bind(this), false);
            document.addEventListener('mozpointerlockchange', this.pointer_lock_change.bind(this), false);
            document.addEventListener('webkitpointerlockchange', this.pointer_lock_change.bind(this), false);
            // Hook pointer lock error events.
            document.addEventListener('pointerlockerror', this.pointer_lock_error.bind(this), false);
            document.addEventListener('mozpointerlockerror', this.pointer_lock_error.bind(this), false);
            document.addEventListener('webkitpointerlockerror', this.pointer_lock_error.bind(this), false);
        } else {
            raise_exception_with_full_logging('Pointer lock is not supported!');
        }
    },

    pointer_lock_change: function () {
        if (document.pointerLockElement !== this.element || document.mozPointerLockElement !== this.element || document.webkitPointerLockElement !== this.element) {
            CURRENT_PLAYER.set_state(PLAYER_STATE_PAUSED);
        }
    },

    pointer_lock_error: function(e) {
        raise_exception_with_full_logging('Pointer lock error!' + e);
    },

    request_pointer_lock: function() {
        this.element.requestPointerLock = this.element.requestPointerLock || this.element.mozRequestPointerLock || this.element.webkitRequestPointerLock;
        this.element.requestPointerLock();
    }

};<commit_msg>general updating 33<commit_after>'use strict';

// https://www.html5rocks.com/en/tutorials/pointerlock/intro/

function PointerLockManager() {
    this.__init__();
}

PointerLockManager.prototype = {
    __init__: function () {
        this.element = document.body;
        this.has_pointer_lock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
        if (this.has_pointer_lock === true) {
            //console.log('Pointer lock is supported!')

            // Hook pointer lock state change events.
            document.addEventListener('pointerlockchange', this.pointer_lock_change.bind(this), false);
            document.addEventListener('mozpointerlockchange', this.pointer_lock_change.bind(this), false);
            document.addEventListener('webkitpointerlockchange', this.pointer_lock_change.bind(this), false);
            // Hook pointer lock error events.
            document.addEventListener('pointerlockerror', this.pointer_lock_error.bind(this), false);
            document.addEventListener('mozpointerlockerror', this.pointer_lock_error.bind(this), false);
            document.addEventListener('webkitpointerlockerror', this.pointer_lock_error.bind(this), false);
        } else {
            raise_exception_with_full_logging('Pointer lock is not supported!');
        }
    },

    pointer_lock_change: function () {
        if (document.pointerLockElement !== this.element && document.mozPointerLockElement !== this.element && document.webkitPointerLockElement !== this.element) {
            CURRENT_PLAYER.set_state(PLAYER_STATE_PAUSED);
        }
    },

    pointer_lock_error: function(e) {
        raise_exception_with_full_logging('Pointer lock error!');
    },

    request_pointer_lock: function() {
        this.element.requestPointerLock = this.element.requestPointerLock || this.element.mozRequestPointerLock || this.element.webkitRequestPointerLock;
        this.element.requestPointerLock();
    }

};<|endoftext|>


<commit_before>/**!
 * AngularJS file upload/drop directive with http post and progress
 * @author  Danial  <danial.farid@gmail.com>
 * @version 1.6.8
 */
(function() {

var angularFileUpload = angular.module('angularFileUpload', []);

angularFileUpload.service('$upload', ['$http', '$q', '$timeout', function($http, $q, $timeout) {
	function sendHttp(config) {
		config.method = config.method || 'POST';
		config.headers = config.headers || {};
		config.transformRequest = config.transformRequest || function(data, headersGetter) {
			if (window.ArrayBuffer && data instanceof window.ArrayBuffer) {
				return data;
			}
			return $http.defaults.transformRequest[0](data, headersGetter);
		};
		var deferred = $q.defer();

		if (window.XMLHttpRequest.__isShim) {
			config.headers['__setXHR_'] = function() {
				return function(xhr) {
					if (!xhr) return;
					config.__XHR = xhr;
					config.xhrFn && config.xhrFn(xhr);
					xhr.upload.addEventListener('progress', function(e) {
						deferred.notify(e);
					}, false);
					//fix for firefox not firing upload progress end, also IE8-9
					xhr.upload.addEventListener('load', function(e) {
						if (e.lengthComputable) {
							deferred.notify(e);
						}
					}, false);
				};
			};
		}

		$http(config).then(function(r){deferred.resolve(r)}, function(e){deferred.reject(e)}, function(n){deferred.notify(n)});

		var promise = deferred.promise;
		promise.success = function(fn) {
			promise.then(function(response) {
				fn(response.data, response.status, response.headers, config);
			});
			return promise;
		};

		promise.error = function(fn) {
			promise.then(null, function(response) {
				fn(response.data, response.status, response.headers, config);
			});
			return promise;
		};

		promise.progress = function(fn) {
			promise.then(null, null, function(update) {
				fn(update);
			});
			return promise;
		};
		promise.abort = function() {
			if (config.__XHR) {
				$timeout(function() {
					config.__XHR.abort();
				});
			}
			return promise;
		};
		promise.xhr = function(fn) {
			config.xhrFn = (function(origXhrFn) {
				return function() {
					origXhrFn && origXhrFn.apply(promise, arguments);
					fn.apply(promise, arguments);
				}
			})(config.xhrFn);
			return promise;
		};

		return promise;
	}

	this.upload = function(config) {
		config.headers = config.headers || {};
		config.headers['Content-Type'] = undefined;
		config.transformRequest = config.transformRequest || $http.defaults.transformRequest;
		var formData = new FormData();
		var origTransformRequest = config.transformRequest;
		var origData = config.data;
		config.transformRequest = function(formData, headerGetter) {
			if (origData) {
				if (config.formDataAppender) {
					for (var key in origData) {
						var val = origData[key];
						config.formDataAppender(formData, key, val);
					}
				} else {
					for (var key in origData) {
						var val = origData[key];
						if (typeof origTransformRequest == 'function') {
							val = origTransformRequest(val, headerGetter);
						} else {
							for (var i = 0; i < origTransformRequest.length; i++) {
								var transformFn = origTransformRequest[i];
								if (typeof transformFn == 'function') {
									val = transformFn(val, headerGetter);
								}
							}
						}
						formData.append(key, val);
					}
				}
			}

			if (config.file != null) {
				var fileFormName = config.fileFormDataName || 'file';

				if (Object.prototype.toString.call(config.file) === '[object Array]') {
					var isFileFormNameString = Object.prototype.toString.call(fileFormName) === '[object String]';
					for (var i = 0; i < config.file.length; i++) {
						formData.append(isFileFormNameString ? fileFormName : fileFormName[i], config.file[i],
								(config.fileName && config.fileName[i]) || config.file[i].name);
					}
				} else {
					formData.append(fileFormName, config.file, config.fileName || config.file.name);
				}
			}
			return formData;
		};

		config.data = formData;

		return sendHttp(config);
	};

	this.http = function(config) {
		return sendHttp(config);
	}
}]);

angularFileUpload.directive('ngFileSelect', [ '$parse', '$timeout', function($parse, $timeout) {
	return function(scope, elem, attr) {
		var fn = $parse(attr['ngFileSelect']);
		if (elem[0].tagName.toLowerCase() !== 'input' || (elem.attr('type') && elem.attr('type').toLowerCase()) !== 'file') {
			var fileElem = angular.element('<input type="file">')
			for (var i = 0; i < elem[0].attributes.length; i++) {
				fileElem.attr(elem[0].attributes[i].name, elem[0].attributes[i].value);
			}
			if (attr["multiple"]) fileElem.attr("multiple", "true");
			fileElem.css("top", 0).css("bottom", 0).css("left", 0).css("right", 0).css("width", "100%").
					css("opacity", 0).css("position", "absolute").css('filter', 'alpha(opacity=0)');
			elem.append(fileElem);
			if (fileElem.parent()[0] != elem[0]) {
				//fix #298
				elem.wrap('<span>');
				elem.css("z-index", "-1000")
				elem.parent().append(fileElem);
				elem = elem.parent();
			}
			if (elem.css("position") === '' || elem.css("position") === 'static') {
				elem.css("position", "relative");
			}
			elem = fileElem;
		}
		elem.bind('change', function(evt) {
			var files = [], fileList, i;
			fileList = evt.__files_ || evt.target.files;
			if (fileList != null) {
				for (i = 0; i < fileList.length; i++) {
					files.push(fileList.item(i));
				}
			}
			$timeout(function() {
				fn(scope, {
					$files : files,
					$event : evt
				});
			});
		});
		// removed this since it was confusing if the user click on browse and then cancel #181
//		elem.bind('click', function(){
//			this.value = null;
//		});

		// removed because of #253 bug
		// touch screens
//		if (('ontouchstart' in window) ||
//				(navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) {
//			elem.bind('touchend', function(e) {
//				e.preventDefault();
//				e.target.click();
//			});
//		}
	};
} ]);

angularFileUpload.directive('ngFileDropAvailable', [ '$parse', '$timeout', function($parse, $timeout) {
	return function(scope, elem, attr) {
		if ('draggable' in document.createElement('span')) {
			var fn = $parse(attr['ngFileDropAvailable']);
			$timeout(function() {
				fn(scope);
			});
		}
	};
} ]);

angularFileUpload.directive('ngFileDrop', [ '$parse', '$timeout', '$location', function($parse, $timeout, $location) {
	return function(scope, elem, attr) {
		if ('draggable' in document.createElement('span')) {
			var leaveTimeout = null;
			elem[0].addEventListener("dragover", function(evt) {
				evt.preventDefault();
				$timeout.cancel(leaveTimeout);
				if (!elem[0].__drag_over_class_) {
					if (attr['ngFileDragOverClass'] && attr['ngFileDragOverClass'].search(/\) *$/) > -1) {
						var dragOverClass = $parse(attr['ngFileDragOverClass'])(scope, {
							$event : evt
						});
						elem[0].__drag_over_class_ = dragOverClass;
					} else {
						elem[0].__drag_over_class_ = attr['ngFileDragOverClass'] || "dragover";
					}
				}
				elem.addClass(elem[0].__drag_over_class_);
			}, false);
			elem[0].addEventListener("dragenter", function(evt) {
				evt.preventDefault();
			}, false);
			elem[0].addEventListener("dragleave", function(evt) {
				leaveTimeout = $timeout(function() {
					elem.removeClass(elem[0].__drag_over_class_);
					elem[0].__drag_over_class_ = null;
				}, attr['ngFileDragOverDelay'] || 1);
			}, false);
			var fn = $parse(attr['ngFileDrop']);
			elem[0].addEventListener("drop", function(evt) {
				evt.preventDefault();
				elem.removeClass(elem[0].__drag_over_class_);
				elem[0].__drag_over_class_ = null;
				extractFiles(evt, function(files) {
					fn(scope, {
						$files : files,
						$event : evt
					});
				});
			}, false);

			function isASCII(str) {
				return /^[\000-\177]*$/.test(str);
			}

			function extractFiles(evt, callback) {
				var files = [], items = evt.dataTransfer.items;
				if (items && items.length > 0 && items[0].webkitGetAsEntry && $location.protocol() != 'file' &&
						items[0].webkitGetAsEntry().isDirectory) {
					for (var i = 0; i < items.length; i++) {
						var entry = items[i].webkitGetAsEntry();
						if (entry != null) {
							//fix for chrome bug https://code.google.com/p/chromium/issues/detail?id=149735
							if (isASCII(entry.name)) {
								traverseFileTree(files, entry);
							} else if (!items[i].webkitGetAsEntry().isDirectory) {
								files.push(items[i].getAsFile());
							}
						}
					}
				} else {
					var fileList = evt.dataTransfer.files;
					if (fileList != null) {
						for (var i = 0; i < fileList.length; i++) {
							files.push(fileList.item(i));
						}
					}
				}
				(function waitForProcess(delay) {
					$timeout(function() {
						if (!processing) {
							callback(files);
						} else {
							waitForProcess(10);
						}
					}, delay || 0)
				})();
			}

			var processing = 0;
			function traverseFileTree(files, entry, path) {
				if (entry != null) {
					if (entry.isDirectory) {
						var dirReader = entry.createReader();
						processing++;
						dirReader.readEntries(function(entries) {
							for (var i = 0; i < entries.length; i++) {
								traverseFileTree(files, entries[i], (path ? path : "") + entry.name + "/");
							}
							processing--;
						});
					} else {
						processing++;
						entry.file(function(file) {
							processing--;
							file._relativePath = (path ? path : "") + file.name;
							files.push(file);
						});
					}
				}
			}
		}
	};
} ]);

})();
<commit_msg>fix for #336<commit_after>/**!
 * AngularJS file upload/drop directive with http post and progress
 * @author  Danial  <danial.farid@gmail.com>
 * @version 1.6.8
 */
(function() {

var angularFileUpload = angular.module('angularFileUpload', []);

angularFileUpload.service('$upload', ['$http', '$q', '$timeout', function($http, $q, $timeout) {
	function sendHttp(config) {
		config.method = config.method || 'POST';
		config.headers = config.headers || {};
		config.transformRequest = config.transformRequest || function(data, headersGetter) {
			if (window.ArrayBuffer && data instanceof window.ArrayBuffer) {
				return data;
			}
			return $http.defaults.transformRequest[0](data, headersGetter);
		};
		var deferred = $q.defer();

		if (window.XMLHttpRequest.__isShim) {
			config.headers['__setXHR_'] = function() {
				return function(xhr) {
					if (!xhr) return;
					config.__XHR = xhr;
					config.xhrFn && config.xhrFn(xhr);
					xhr.upload.addEventListener('progress', function(e) {
						deferred.notify(e);
					}, false);
					//fix for firefox not firing upload progress end, also IE8-9
					xhr.upload.addEventListener('load', function(e) {
						if (e.lengthComputable) {
							deferred.notify(e);
						}
					}, false);
				};
			};
		}

		$http(config).then(function(r){deferred.resolve(r)}, function(e){deferred.reject(e)}, function(n){deferred.notify(n)});

		var promise = deferred.promise;
		promise.success = function(fn) {
			promise.then(function(response) {
				fn(response.data, response.status, response.headers, config);
			});
			return promise;
		};

		promise.error = function(fn) {
			promise.then(null, function(response) {
				fn(response.data, response.status, response.headers, config);
			});
			return promise;
		};

		promise.progress = function(fn) {
			promise.then(null, null, function(update) {
				fn(update);
			});
			return promise;
		};
		promise.abort = function() {
			if (config.__XHR) {
				$timeout(function() {
					config.__XHR.abort();
				});
			}
			return promise;
		};
		promise.xhr = function(fn) {
			config.xhrFn = (function(origXhrFn) {
				return function() {
					origXhrFn && origXhrFn.apply(promise, arguments);
					fn.apply(promise, arguments);
				}
			})(config.xhrFn);
			return promise;
		};

		return promise;
	}

	this.upload = function(config) {
		config.headers = config.headers || {};
		config.headers['Content-Type'] = undefined;
		config.transformRequest = config.transformRequest || $http.defaults.transformRequest;
		var formData = new FormData();
		var origTransformRequest = config.transformRequest;
		var origData = config.data;
		config.transformRequest = function(formData, headerGetter) {
			if (origData) {
				if (config.formDataAppender) {
					for (var key in origData) {
						var val = origData[key];
						config.formDataAppender(formData, key, val);
					}
				} else {
					for (var key in origData) {
						var val = origData[key];
						if (typeof origTransformRequest == 'function') {
							val = origTransformRequest(val, headerGetter);
						} else {
							for (var i = 0; i < origTransformRequest.length; i++) {
								var transformFn = origTransformRequest[i];
								if (typeof transformFn == 'function') {
									val = transformFn(val, headerGetter);
								}
							}
						}
						formData.append(key, val);
					}
				}
			}

			if (config.file != null) {
				var fileFormName = config.fileFormDataName || 'file';

				if (Object.prototype.toString.call(config.file) === '[object Array]') {
					var isFileFormNameString = Object.prototype.toString.call(fileFormName) === '[object String]';
					for (var i = 0; i < config.file.length; i++) {
						formData.append(isFileFormNameString ? fileFormName : fileFormName[i], config.file[i],
								(config.fileName && config.fileName[i]) || config.file[i].name);
					}
				} else {
					formData.append(fileFormName, config.file, config.fileName || config.file.name);
				}
			}
			return formData;
		};

		config.data = formData;

		return sendHttp(config);
	};

	this.http = function(config) {
		return sendHttp(config);
	}
}]);

angularFileUpload.directive('ngFileSelect', [ '$parse', '$timeout', function($parse, $timeout) {
	return function(scope, elem, attr) {
		var fn = $parse(attr['ngFileSelect']);
		if (elem[0].tagName.toLowerCase() !== 'input' || (elem.attr('type') && elem.attr('type').toLowerCase()) !== 'file') {
			var fileElem = angular.element('<input type="file">')
			for (var i = 0; i < elem[0].attributes.length; i++) {
				fileElem.attr(elem[0].attributes[i].name, elem[0].attributes[i].value);
			}
			if (attr["multiple"]) fileElem.attr("multiple", "true");
			fileElem.css("top", 0).css("bottom", 0).css("left", 0).css("right", 0).css("width", "100%").
					css("opacity", 0).css("position", "absolute").css('filter', 'alpha(opacity=0)').
					css("padding", 0);
			elem.append(fileElem);
			if (fileElem.parent()[0] != elem[0]) {
				//fix #298
				elem.wrap('<span>');
				elem.css("z-index", "-1000")
				elem.parent().append(fileElem);
				elem = elem.parent();
			}
			if (elem.css("position") === '' || elem.css("position") === 'static') {
				elem.css("position", "relative");
			}
			elem = fileElem;
		}
		elem.bind('change', function(evt) {
			var files = [], fileList, i;
			fileList = evt.__files_ || evt.target.files;
			if (fileList != null) {
				for (i = 0; i < fileList.length; i++) {
					files.push(fileList.item(i));
				}
			}
			$timeout(function() {
				fn(scope, {
					$files : files,
					$event : evt
				});
			});
		});
		// removed this since it was confusing if the user click on browse and then cancel #181
//		elem.bind('click', function(){
//			this.value = null;
//		});

		// removed because of #253 bug
		// touch screens
//		if (('ontouchstart' in window) ||
//				(navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) {
//			elem.bind('touchend', function(e) {
//				e.preventDefault();
//				e.target.click();
//			});
//		}
	};
} ]);

angularFileUpload.directive('ngFileDropAvailable', [ '$parse', '$timeout', function($parse, $timeout) {
	return function(scope, elem, attr) {
		if ('draggable' in document.createElement('span')) {
			var fn = $parse(attr['ngFileDropAvailable']);
			$timeout(function() {
				fn(scope);
			});
		}
	};
} ]);

angularFileUpload.directive('ngFileDrop', [ '$parse', '$timeout', '$location', function($parse, $timeout, $location) {
	return function(scope, elem, attr) {
		if ('draggable' in document.createElement('span')) {
			var leaveTimeout = null;
			elem[0].addEventListener("dragover", function(evt) {
				evt.preventDefault();
				$timeout.cancel(leaveTimeout);
				if (!elem[0].__drag_over_class_) {
					if (attr['ngFileDragOverClass'] && attr['ngFileDragOverClass'].search(/\) *$/) > -1) {
						var dragOverClass = $parse(attr['ngFileDragOverClass'])(scope, {
							$event : evt
						});
						elem[0].__drag_over_class_ = dragOverClass;
					} else {
						elem[0].__drag_over_class_ = attr['ngFileDragOverClass'] || "dragover";
					}
				}
				elem.addClass(elem[0].__drag_over_class_);
			}, false);
			elem[0].addEventListener("dragenter", function(evt) {
				evt.preventDefault();
			}, false);
			elem[0].addEventListener("dragleave", function(evt) {
				leaveTimeout = $timeout(function() {
					elem.removeClass(elem[0].__drag_over_class_);
					elem[0].__drag_over_class_ = null;
				}, attr['ngFileDragOverDelay'] || 1);
			}, false);
			var fn = $parse(attr['ngFileDrop']);
			elem[0].addEventListener("drop", function(evt) {
				evt.preventDefault();
				elem.removeClass(elem[0].__drag_over_class_);
				elem[0].__drag_over_class_ = null;
				extractFiles(evt, function(files) {
					fn(scope, {
						$files : files,
						$event : evt
					});
				});
			}, false);

			function isASCII(str) {
				return /^[\000-\177]*$/.test(str);
			}

			function extractFiles(evt, callback) {
				var files = [], items = evt.dataTransfer.items;
				if (items && items.length > 0 && items[0].webkitGetAsEntry && $location.protocol() != 'file' &&
						items[0].webkitGetAsEntry().isDirectory) {
					for (var i = 0; i < items.length; i++) {
						var entry = items[i].webkitGetAsEntry();
						if (entry != null) {
							//fix for chrome bug https://code.google.com/p/chromium/issues/detail?id=149735
							if (isASCII(entry.name)) {
								traverseFileTree(files, entry);
							} else if (!items[i].webkitGetAsEntry().isDirectory) {
								files.push(items[i].getAsFile());
							}
						}
					}
				} else {
					var fileList = evt.dataTransfer.files;
					if (fileList != null) {
						for (var i = 0; i < fileList.length; i++) {
							files.push(fileList.item(i));
						}
					}
				}
				(function waitForProcess(delay) {
					$timeout(function() {
						if (!processing) {
							callback(files);
						} else {
							waitForProcess(10);
						}
					}, delay || 0)
				})();
			}

			var processing = 0;
			function traverseFileTree(files, entry, path) {
				if (entry != null) {
					if (entry.isDirectory) {
						var dirReader = entry.createReader();
						processing++;
						dirReader.readEntries(function(entries) {
							for (var i = 0; i < entries.length; i++) {
								traverseFileTree(files, entries[i], (path ? path : "") + entry.name + "/");
							}
							processing--;
						});
					} else {
						processing++;
						entry.file(function(file) {
							processing--;
							file._relativePath = (path ? path : "") + file.name;
							files.push(file);
						});
					}
				}
			}
		}
	};
} ]);

})();
<|endoftext|>


<commit_before>'use strict';

// Load requirements
const winston = require('winston'),
      path = require('path'),
      fs = require('fs');

// Add rotation to winston logs
require('winston-daily-rotate-file');

// Get log directory
let logDirectory = path.resolve(path.join(__base, '../logs'));

// Ensure the directory exists
fs.mkdir(logDirectory, (err) => { return; });

// Setup the logger interfaces for console, file and exception handling
const logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({
      level: process.env.ENV == 'test' ? 'error' : 'info',
      colorize: true
    })/*,
    new (winston.transports.DailyRotateFile)({
      filename: path.join(logDirectory, process.env.ENV + '.'),
      datePattern: 'yyyy-MM-dd.log',
      level: process.env.LOG_LEVEL
    })*/
  ]/*,
  exceptionHandlers: [
    new (winston.transports.DailyRotateFile)({
      filename: path.join(logDirectory, 'exceptions.'),
      datePattern: 'yyyy-MM-dd.log',
      humanReadableUnhandledException: true
    })
  ]*/
});

// Add colorize support
logger.filters.push((level, msg, meta) => {
  return __require('libs/utils/methods/color-string')(msg);
});

// Export for use
module.exports = logger;
<commit_msg>Improve log levels<commit_after>'use strict';

// Load requirements
const winston = require('winston'),
      path = require('path'),
      fs = require('fs');

// Add rotation to winston logs
require('winston-daily-rotate-file');

// Get log directory
let logDirectory = path.resolve(path.join(__base, '../logs'));

// Ensure the directory exists
fs.mkdir(logDirectory, (err) => { return; });

// Setup the logger interfaces for console, file and exception handling
const logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({
      level: process.env.ENV === 'test' ? 'debug' : 'info',
      colorize: true
    })/*,
    new (winston.transports.DailyRotateFile)({
      filename: path.join(logDirectory, process.env.ENV + '.'),
      datePattern: 'yyyy-MM-dd.log',
      level: process.env.LOG_LEVEL
    })*/
  ]/*,
  exceptionHandlers: [
    new (winston.transports.DailyRotateFile)({
      filename: path.join(logDirectory, 'exceptions.'),
      datePattern: 'yyyy-MM-dd.log',
      humanReadableUnhandledException: true
    })
  ]*/
});

// Add colorize support
logger.filters.push((level, msg, meta) => {
  return __require('libs/utils/methods/color-string')(msg);
});

// Export for use
module.exports = logger;
<|endoftext|>


<commit_before> /*
  * Specs for the Utils class
  */

describe("Utils", function() {

  var utils = new THREEGRAPHS.Utils( );

  it("should check if it's a touch device", function( ) {
    var uagent = navigator.userAgent.toLowerCase( );
    if ( uagent.search("iphone") > -1 ){
      expect( utils.isTouchDevice ( ) ).toBeTruthy();
    }else{
      expect( utils.isTouchDevice ( ) ).toBeFalsy();
    }
  });

  it("should calculate the luminance of a colour", function( ) {
    expect( utils.colorLuminance('d17100',0.5) ).toEqual( 'ffaa00' );
  });

  it("should get the maximal value in a 2-dimensional array", function( ) {
    expect( utils.getMaxArr([[5,3,1,12],[7,2,4]]) ).toEqual( 12 );
  });

  it("should get the minumal value in a 2-dimensional array", function( ) {
    expect( utils.getMinArr([[5,3,1,12],[7,2,4]]) ).toEqual( 1 );
  });

  it("should calculate the round of a max number", function( ) {
    expect( utils.getRoundMax(98) ).toEqual( 100 );
  });

  it("should count the sum of all elements in a two dimentional array", function( ) {
    expect( utils.getTotalArr([[5,3,1,12],[7,2,4]]) ).toEqual( 34 );
  });

  it("should initiate the legend div", function( ) {
    var data = {  cols: [ { name:"2010", color:"d17100" },
                          { name:"2011", color:"d9bd00" } ],
                  rows: [ { name: "Product 1" } ]
                };
    var el = document.createElement('div');
    utils.initLegend(el, data);
    var col1 = el.getElementsByTagName("div");
    expect( col1[0].style.backgroundColor ).toEqual( 'rgb(209, 113, 0)' );
  });

  it("should generate the Three.js mouse controls", function( ) {
    var renderer = new THREE.WebGLRenderer( { antialias: true } );
    var camera = new THREE.PerspectiveCamera( 60,
                                        window.innerWidth/window.innerHeight,
                                        1,
                                        5000 );
    var controls = utils.mouseControls ( renderer, camera, 100, 1000 );
    expect( controls.minDistance ).toEqual( 100 );
  });

  it("should detect the browser", function( ){
    var agent = navigator.userAgent;
    var canSupport = 0;
    if ( agent.indexOf('Firefox') != -1 ){
      canSupport = 1;
      if ( parseFloat(agent.substring(agent.indexOf('Firefox') + 8)) >= 4 ){
        canSupport = 2;
      }
    }
    if ( agent.indexOf('Chrome') != -1 ){
      canSupport = 1;
      if ( parseFloat(agent.substring(agent.indexOf('Chrome') + 7).split(' ')[0]) >= 7 ){
        canSupport = 2;
      }
    }
    if ( agent.indexOf('Safari') != -1 ){
      canSupport = 1;
      if ( parseFloat(agent.substring(agent.indexOf('Version') + 8).split(' ')[0]) >= 5.1 ){
        canSupport = 2;
      }
    }
    if ( navigator.appName.indexOf("Internet Explorer")!=-1 ){
      if ( navigator.appVersion.indexOf("MSIE 9") == -1 && navigator.appVersion.indexOf("MSIE 10") == -1 ) canSupport = 1;
      if ( navigator.appVersion.indexOf("MSIE 11") == -1 ) canSupport = 2;
    }

    if ( canSupport == 0 ){
      expect( utils.detectRenderer() ).toEqual( 'none' );
    } else if ( canSupport == 1 ){
      expect( utils.detectRenderer() ).toEqual( 'canvas' );
    } else if ( canSupport == 2 ){
      expect( utils.detectRenderer() ).toEqual( 'webgl' );
    }

  });

});

 /*
  * Specs for the Bar Cubes class
  */

describe("Bar Cube", function() {

  var scene = new THREE.Scene();
  var label = document.createElement('div');
  var nCube = new THREEGRAPHS.BarCube( "CC0000", 0, 0, 7, "ffffff", 'full', false, { row:"row", col:"col" }, 0, 10, 10 );
  nCube.addBar ( scene );

  it ( 'should create a new bar object', function () {
    expect ( nCube.barobj.geometry ).toBeDefined();
  });

  it ( 'should have a width equal to the sqare size defined', function () {
    expect ( nCube.barobj.geometry.width ).toEqual( THREEGRAPHS.Settings.squareSize );
  });

  it ( 'should have a height equal to value percentage ot the max value and the height of the scales', function () {
    expect ( nCube.barobj.geometry.height ).toEqual( 700 );
  });

  it ( 'should have an RGB colour equal to the hex one defined', function () {
    expect ( nCube.barobj.material.color.toString() ).toEqual( ({ r:0.8, g:0, b:0 }).toString() );
  });
});

 /*
  * Specs for the Bar Cubes class
  */

describe("Pie Parts", function() {

  var scene = new THREE.Scene();
  var label = document.createElement('div');
  var pieP = new THREEGRAPHS.PiePart( 7, 20, 500, 0, {x:0,y:0},
                                      "CC0000", "ffffff", 'full', false,
                                      { col:"col" } );
  pieP.addPie ( scene );

  it ( 'should create a new pie object', function () {
    expect ( pieP.pieobj.geometry ).toBeDefined();
  });

  it ( 'should have an RGB colour equal to the hex one defined', function () {
    expect ( pieP.pieobj.material.color.toString() ).toEqual( ({ r:0.8, g:0, b:0 }).toString() );
  });

});

describe("Area Pollies", function() {

  var scene = new THREE.Scene();
  var label = document.createElement('div');
  var nArea = new THREEGRAPHS.AreaPoly( "CC0000", 0, [3,7,2], "ffffff", 'full', false, { row:"row", col:"col" }, 0, 10, 10 );
  nArea.addArea ( scene );

  it ( 'should create a new area object', function () {
    expect ( nArea.areaobj.geometry ).toBeDefined();
  });

  it ( 'should have an RGB colour equal to the hex one defined', function () {
    expect ( nArea.areaobj.material.color.toString() ).toEqual( ({ r:0.8, g:0, b:0 }).toString() );
  });

});

describe("Bar charts", function () {

  var sData;
  var newBarChart;
  var sData = {
          cols: [ { name:"col1", color:"CC0000" },
                 { name:"col2", color:"00CC00" }
               ],
         rows: [ { name: "row 1", values: [5,6] },
                 { name: "row 2", values: [3,9] }
               ]
    };

  it ( 'should instantiate the data variables', function () {
    newBarChart = new THREEGRAPHS.BarChart ( sData );
    expect( newBarChart.dataValues[0][0] ).toEqual(5);
  });

  it ( ' should instantiate the scene variables ', function (){
    newBarChart.initSceneVars();
    expect( newBarChart.scene.visible ).toEqual(true);
    expect( newBarChart.camera.position.x ).toEqual(500);
    expect( THREEGRAPHS.Settings.zDeviation ).toEqual(-200);
  });

  it ( 'should instantiate the WebGL renderer', function () {
    newBarChart.initWebGLScene();
    expect( newBarChart.renderer.domElement ).toBeDefined();
  });

  it ( 'should add 3 grounds', function () {
    expect( newBarChart.scene.children[0].geometry.vertices.length ).toEqual(4);
    expect( newBarChart.scene.children[1].geometry.vertices.length ).toEqual(4);
    expect( newBarChart.scene.children[2].geometry.vertices.length ).toEqual(4);
  });

  it( 'should add text for the scales', function () {
    expect( newBarChart.sTextCols[0].txtobj.geometry ).toBeDefined();
  });

  it( 'should create bars with the same amount as the data itmes', function () {
    expect( newBarChart.bars.length ).toEqual(4);
  });

  it( 'should create lights', function () {
    expect( newBarChart.scene.__lights[2].position.x).toEqual(600);
  });

  it( 'should init the controls', function () {
    newBarChart = null;
    newBarChart = new THREEGRAPHS.BarChart ( sData );
    newBarChart.init();
    expect( newBarChart.controls ).not.toEqual( null );
  });

  it ( 'should instantiate the Canvas renderer', function () {
    newBarChart = null;
    newBarChart = new THREEGRAPHS.BarChart ( sData );
    newBarChart.initSceneVars();
    newBarChart.initCanvasScene();
    expect( newBarChart.renderer.domElement ).toBeDefined();
  });

});<commit_msg>Added first specs for the pie charts<commit_after> /*
  * Specs for the Utils class
  */

describe("Utils", function() {

  var utils = new THREEGRAPHS.Utils( );

  it("should check if it's a touch device", function( ) {
    var uagent = navigator.userAgent.toLowerCase( );
    if ( uagent.search("iphone") > -1 ){
      expect( utils.isTouchDevice ( ) ).toBeTruthy();
    }else{
      expect( utils.isTouchDevice ( ) ).toBeFalsy();
    }
  });

  it("should calculate the luminance of a colour", function( ) {
    expect( utils.colorLuminance('d17100',0.5) ).toEqual( 'ffaa00' );
  });

  it("should get the maximal value in a 2-dimensional array", function( ) {
    expect( utils.getMaxArr([[5,3,1,12],[7,2,4]]) ).toEqual( 12 );
  });

  it("should get the minumal value in a 2-dimensional array", function( ) {
    expect( utils.getMinArr([[5,3,1,12],[7,2,4]]) ).toEqual( 1 );
  });

  it("should calculate the round of a max number", function( ) {
    expect( utils.getRoundMax(98) ).toEqual( 100 );
  });

  it("should count the sum of all elements in a two dimentional array", function( ) {
    expect( utils.getTotalArr([[5,3,1,12],[7,2,4]]) ).toEqual( 34 );
  });

  it("should initiate the legend div", function( ) {
    var data = {  cols: [ { name:"2010", color:"d17100" },
                          { name:"2011", color:"d9bd00" } ],
                  rows: [ { name: "Product 1" } ]
                };
    var el = document.createElement('div');
    utils.initLegend(el, data);
    var col1 = el.getElementsByTagName("div");
    expect( col1[0].style.backgroundColor ).toEqual( 'rgb(209, 113, 0)' );
  });

  it("should generate the Three.js mouse controls", function( ) {
    var renderer = new THREE.WebGLRenderer( { antialias: true } );
    var camera = new THREE.PerspectiveCamera( 60,
                                        window.innerWidth/window.innerHeight,
                                        1,
                                        5000 );
    var controls = utils.mouseControls ( renderer, camera, 100, 1000 );
    expect( controls.minDistance ).toEqual( 100 );
  });

  it("should detect the browser", function( ){
    var agent = navigator.userAgent;
    var canSupport = 0;
    if ( agent.indexOf('Firefox') != -1 ){
      canSupport = 1;
      if ( parseFloat(agent.substring(agent.indexOf('Firefox') + 8)) >= 4 ){
        canSupport = 2;
      }
    }
    if ( agent.indexOf('Chrome') != -1 ){
      canSupport = 1;
      if ( parseFloat(agent.substring(agent.indexOf('Chrome') + 7).split(' ')[0]) >= 7 ){
        canSupport = 2;
      }
    }
    if ( agent.indexOf('Safari') != -1 ){
      canSupport = 1;
      if ( parseFloat(agent.substring(agent.indexOf('Version') + 8).split(' ')[0]) >= 5.1 ){
        canSupport = 2;
      }
    }
    if ( navigator.appName.indexOf("Internet Explorer")!=-1 ){
      if ( navigator.appVersion.indexOf("MSIE 9") == -1 && navigator.appVersion.indexOf("MSIE 10") == -1 ) canSupport = 1;
      if ( navigator.appVersion.indexOf("MSIE 11") == -1 ) canSupport = 2;
    }

    if ( canSupport == 0 ){
      expect( utils.detectRenderer() ).toEqual( 'none' );
    } else if ( canSupport == 1 ){
      expect( utils.detectRenderer() ).toEqual( 'canvas' );
    } else if ( canSupport == 2 ){
      expect( utils.detectRenderer() ).toEqual( 'webgl' );
    }

  });

});

 /*
  * Specs for the Bar Cubes class
  */

describe("Bar Cube", function() {

  var scene = new THREE.Scene();
  var label = document.createElement('div');
  var nCube = new THREEGRAPHS.BarCube( "CC0000", 0, 0, 7, "ffffff", 'full', false, { row:"row", col:"col" }, 0, 10, 10 );
  nCube.addBar ( scene );

  it ( 'should create a new bar object', function () {
    expect ( nCube.barobj.geometry ).toBeDefined();
  });

  it ( 'should have a width equal to the sqare size defined', function () {
    expect ( nCube.barobj.geometry.width ).toEqual( THREEGRAPHS.Settings.squareSize );
  });

  it ( 'should have a height equal to value percentage ot the max value and the height of the scales', function () {
    expect ( nCube.barobj.geometry.height ).toEqual( 700 );
  });

  it ( 'should have an RGB colour equal to the hex one defined', function () {
    expect ( nCube.barobj.material.color.toString() ).toEqual( ({ r:0.8, g:0, b:0 }).toString() );
  });
});

 /*
  * Specs for the Bar Cubes class
  */

describe("Pie Parts", function() {

  var scene = new THREE.Scene();
  var label = document.createElement('div');
  var pieP = new THREEGRAPHS.PiePart( 7, 20, 500, 0, {x:0,y:0},
                                      "CC0000", "ffffff", 'full', false,
                                      { col:"col" } );
  pieP.addPie ( scene );

  it ( 'should create a new pie object', function () {
    expect ( pieP.pieobj.geometry ).toBeDefined();
  });

  it ( 'should have an RGB colour equal to the hex one defined', function () {
    expect ( pieP.pieobj.material.color.toString() ).toEqual( ({ r:0.8, g:0, b:0 }).toString() );
  });

});

describe("Area Pollies", function() {

  var scene = new THREE.Scene();
  var label = document.createElement('div');
  var nArea = new THREEGRAPHS.AreaPoly( "CC0000", 0, [3,7,2], "ffffff", 'full', false, { row:"row", col:"col" }, 0, 10, 10 );
  nArea.addArea ( scene );

  it ( 'should create a new area object', function () {
    expect ( nArea.areaobj.geometry ).toBeDefined();
  });

  it ( 'should have an RGB colour equal to the hex one defined', function () {
    expect ( nArea.areaobj.material.color.toString() ).toEqual( ({ r:0.8, g:0, b:0 }).toString() );
  });

});

describe("Bar charts", function () {

  var sData;
  var newBarChart;
  var sData = {
          cols: [ { name:"col1", color:"CC0000" },
                 { name:"col2", color:"00CC00" }
               ],
         rows: [ { name: "row 1", values: [5,6] },
                 { name: "row 2", values: [3,9] }
               ]
    };

  it ( 'should instantiate the data variables', function () {
    newBarChart = new THREEGRAPHS.BarChart ( sData );
    expect( newBarChart.dataValues[0][0] ).toEqual(5);
  });

  it ( ' should instantiate the scene variables ', function (){
    newBarChart.initSceneVars();
    expect( newBarChart.scene.visible ).toEqual(true);
    expect( newBarChart.camera.position.x ).toEqual(500);
    expect( THREEGRAPHS.Settings.zDeviation ).toEqual(-200);
  });

  it ( 'should instantiate the WebGL renderer', function () {
    newBarChart.initWebGLScene();
    expect( newBarChart.renderer.domElement ).toBeDefined();
  });

  it ( 'should add 3 grounds', function () {
    expect( newBarChart.scene.children[0].geometry.vertices.length ).toEqual(4);
    expect( newBarChart.scene.children[1].geometry.vertices.length ).toEqual(4);
    expect( newBarChart.scene.children[2].geometry.vertices.length ).toEqual(4);
  });

  it( 'should add text for the scales', function () {
    expect( newBarChart.sTextCols[0].txtobj.geometry ).toBeDefined();
  });

  it( 'should create bars with the same amount as the data itmes', function () {
    expect( newBarChart.bars.length ).toEqual(4);
  });

  it( 'should create lights', function () {
    expect( newBarChart.scene.__lights[2].position.x).toEqual(600);
  });

  it( 'should init the controls', function () {
    newBarChart = null;
    newBarChart = new THREEGRAPHS.BarChart ( sData );
    newBarChart.init();
    expect( newBarChart.controls ).not.toEqual( null );
  });

  it ( 'should instantiate the Canvas renderer', function () {
    newBarChart = null;
    newBarChart = new THREEGRAPHS.BarChart ( sData );
    newBarChart.initSceneVars();
    newBarChart.initCanvasScene();
    expect( newBarChart.renderer.domElement ).toBeDefined();
  });

});

describe("Bar charts", function () {

  var sData;
  var newPieChart;
  var sData = {
          cols: [ { name:"col1", color:"CC0000" },
                 { name:"col2", color:"00CC00" },
                 { name:"col3", color:"0000CC" }
               ],
         rows: [ { name: "row 1", values: [5,6,8] } ]
    };

  it ( 'should instantiate the data variables', function () {
    newPieChart = new THREEGRAPHS.PieChart ( sData );
    expect( newBarChart.dataValues[0][0] ).toEqual(5);
  });

});<|endoftext|>