<commit_before>Crafty.extend({

	randRange: function(from, to) {
		return Math.round(Math.random() * (to - from) + from);
	},

	/**
	* Sprite generator.
	*
	* Extends Crafty for producing components
	* based on sprites and tiles
	*/
	sprite: function(tile, url, map) {
		var pos, temp, x, y, w, h;

		//if no tile value, default to 16
		if(typeof tile === "string") {
			map = url;
			url = tile;
			tile = 1;
		}

		for(pos in map) {
			if(!map.hasOwnProperty(pos)) continue;

			temp = map[pos];
			x = temp[0] * tile;
			y = temp[1] * tile;
			w = temp[2] * tile || tile;
			h = temp[3] * tile || tile;

			//create a component for the sprite
			Crafty.c(pos, {
				__image: url,
				__coord: [x,y,w,h],
				__tile: tile,

				init: function() {
					this.addComponent("sprite");
					if(this.has("canvas")) {
						this.img = new Image();
						this.img.src = this.__image;
						//draw when ready
						Crafty.addEvent(this, this.img, 'load', function() {
							DrawBuffer.add(this); //send to buffer to keep Z order
						});
					}
					this.w = this.__coord[2];
					this.h = this.__coord[3];
				},

				sprite: function(x,y,w,h) {
					this.__coord = [x*this.__tile,y*this.__tile,w*this.__tile || this.__tile,h*this.__tile || this.__tile];
					if(this.has("canvas")) DrawBuffer.add(this);
					else if(this.has("DOM")) this.draw();
				}
			});
		}

		return this;
	},

	_events: {},

	/**
	* Window Events credited to John Resig
	* http://ejohn.org/projects/flexible-javascript-events
	*/
	addEvent: function(ctx, obj, type, fn) {
		if(arguments.length === 3) {
			fn = type;
			type = obj;
			obj = window.document;
		}

		//save anonymous function to be able to remove
		var afn = function(e) { var e = e || window.event; fn.call(ctx,e) };
		if(!this._events[obj+type+fn]) this._events[obj+type+fn] = afn;
		else return;

		if (obj.attachEvent) { //IE
			obj.attachEvent('on'+type, afn);
		} else { //Everyone else
			obj.addEventListener(type, afn, false);
		}
	},

	removeEvent: function(ctx, obj, type, fn) {
		if(arguments.length === 3) {
			fn = type;
			type = obj;
			obj = window.document;
		}

		//retrieve anonymouse function
		var afn = this._events[obj+type+fn];

		if(afn) {
			if (obj.detachEvent) {
				obj.detachEvent('on'+type, afn);
			} else obj.removeEventListener(type, afn, false);
			delete this._events[obj+type+fn];
		}
	},

	window: {
		width: window.innerWidth || (window.document.documentElement.clientWidth || window.document.body.clientWidth),
		height: window.innerHeight || (window.document.documentElement.clientHeight || window.document.body.clientHeight)
	},

	background: function(color) {
		Crafty.stage.elem.style.background = color;
	},

	viewport: {
		width: 0,
		height: 0,
		_x: 0,
		_y: 0,

		scroll: function(axis, v) {
			var old = this[axis],
				q,
				i = 0, j = 0, l, m,
				box,
				dupes = {},
				rect,
				sorted = [];

			//clear screen
			if(Crafty.context) Crafty.context.clearRect(0,0, this.width, this.height);

			rect = {x: axis == '_x' ? old : this._x, y: axis == '_y' ? old : this._y, w: this.width, h:this.height};
			q = Crafty.map.search(rect, false);

			for(l=q.length;i<l;++i) {
				box = q[i];

				if(!dupes[box[0]]) {
					dupes[box[0]] = true;
					if(!sorted[box._z]) sorted[box._z] = [];

					sorted[box._z].push(box);
				}
			}

			Crafty("2D obj").each(function() {
				var oldposition = this.pos();

				this[axis] -= old - v;
				//if no setter available
				if(Crafty.support.setter === false) {
					this[axis.substr(1)] = this[axis];
					this.trigger("change", oldposition);
				}
				this.trigger("move",oldposition);
			});

			m = sorted.length;
			for(;j<m;j++) {
				if(!sorted[j]) continue;
				var k = 0, n = sorted[j].length;
				for(;k<n;k++) {
					if('draw' in sorted[j][k])
						sorted[j][k].draw();
				}
			}

			this[axis] = v;
		},

		rect: function() {
			return {x: this._x, y: this._y, w: this.width, h: this.height};
		},

		init: function(w,h) {
			this.width = w || Crafty.window.width;
			this.height = h || Crafty.window.height;

			//stop scrollbars
			if(!w && !h) {
				document.body.style.overflow = "hidden";
			}

			//check if stage exists
			var crstage = document.getElementById("cr-stage");

			//create stage div to contain everything
			Crafty.stage = {
				x: 0,
				y: 0,
				elem: (crstage ? crstage : document.createElement("div"))
			};

			//add to the body and give it an ID if not exists
			if(!crstage) {
				document.body.appendChild(Crafty.stage.elem);
				Crafty.stage.elem.id = "cr-stage";
			}

			var elem = Crafty.stage.elem.style,
				offset;

			//css style
			elem.width = this.width + "px";
			elem.height = this.height + "px";
			elem.overflow = "hidden";
			elem.position = "relative";

			//find out the offset position of the stage
			offset = Crafty.inner(Crafty.stage.elem);
			Crafty.stage.x = offset.x;
			Crafty.stage.y = offset.y;

			if('__defineSetter__' in this && '__defineGetter__' in this) {
				//define getters and setters to scroll the viewport
				this.__defineSetter__('x', function(v) { this.scroll('_x', v); });
				this.__defineSetter__('y', function(v) { this.scroll('_y', v); });
				this.__defineGetter__('x', function() { return this._x; });
				this.__defineGetter__('y', function() { return this._y; });
			} else {
				//create empty entity waiting for enterframe
				this.x = this._x;
				this.y = this._y;
				Crafty.e("viewport");
			}
		}
	},

	support: {},

	/**
	* Map key names to key codes
	*/
	keys: {'BSP':8, 'TAB':9, 'ENT':13, 'SHF':16, 'CTR':17, 'ALT':18, 'PAU':19, 'CAP':20, 'ESC':27, 'SP':32, 'PGU':33, 'PGD':34, 'END':35, 'HOM':36, 'LA':37, 'UA':38, 'RA':39, 'DA':40, 'INS':45, 'DEL':46, 'D0':48, 'D1':49, 'D2':50, 'D3':51, 'D4':52, 'D5':53, 'D6':54, 'D7':55, 'D8':56, 'D9':57, 'SEM':59, 'EQL':61, 'A':65, 'B':66, 'C':67, 'D':68, 'E':69, 'F':70, 'G':71, 'H':72, 'I':73, 'J':74, 'K':75, 'L':76, 'M':77, 'N':78, 'O':79, 'P':80, 'Q':81, 'R':82, 'S':83, 'T':84, 'U':85, 'V':86, 'W':87, 'X':88, 'Y':89, 'Z':90, 'LWN':91, 'RWN':92, 'SEL':93, 'N0':96, 'N1':97, 'N2':98, 'N3':99, 'N4':100, 'N5':101, 'N6':102, 'N7':103, 'N8':104, 'N9':105, 'MUL':106, 'ADD':107, 'SUB':109, 'DEC':110, 'DIV':111, 'F1':112, 'F2':113, 'F3':114, 'F4':115, 'F5':116, 'F6':117, 'F7':118, 'F8':119, 'F9':120, 'F10':121, 'F11':122, 'F12':123, 'NUM':144, 'SCR':145, 'COM':188, 'PER':190, 'FSL':191, 'ACC':192, 'OBR':219, 'BSL':220, 'CBR':221, 'QOT':222}
});

/**
* Entity fixes the lack of setter support
*/
Crafty.c("viewport", {
	init: function() {
		this.bind("enterframe", function() {
			if(Crafty.viewport._x !== Crafty.viewport.x) {
				Crafty.viewport.scroll('_x', Crafty.viewport.x);
			}

			if(Crafty.viewport._y !== Crafty.viewport.y) {
				Crafty.viewport.scroll('_y', Crafty.viewport.y);
			}
		});
	}
});

var DrawBuffer = {

	add: function add(obj, old) {
		//redraw old position that was cleared
		this.redraw(obj,old);

		//redraw obj in new position
		this.redraw(obj);
	},

	/**
	* Find all objects intersected by this
	* and redraw them in order of Z
	*/
	redraw: function redraw(obj, old) {
		var q,
			i = 0,
			j = 0,
			keylength,
			zlength,
			box,
			z,
			layer,
			total = 0,
			redrawSelf = false,
			dupes = {}, //lookup of dupes
			sorted = []; //bucket sort

		if(!old) redrawSelf = true; //redraw self if no old param passed
		old = old || obj; //default old x & y to obj

		q = Crafty.map.search({x: old._x, y: old._y, w: old._w, h: old._h},false);

		for(i=0;i<q.length;++i) {
			box = q[i];

			//if found is canvas, not a duplicate and intersects (inlined for performance)
			if(box.isCanvas && !dupes[box[0]] && box._x < old._x + old._w && box._x + box._w > old._x &&
												 box._y < old._y + old._h && box._h + box._y > old._y) {
				dupes[box[0]] = true; //don't search again
				if(box === obj && !redrawSelf) continue; //TAKE HEED, don't return dear lord
				if(!sorted[box._z]) sorted[box._z] = [];

				sorted[box._z].push(box);
				++total;
			}
		};

		//skip if nothing added
		if(total == 0) return;
		//only draw self
		if(total == 1 && redrawSelf) {
			obj.draw();
			return;
		}

		//loop over sorted Z keys
		for(i=0, keylength = sorted.length; i < keylength; ++i) {
			if(!sorted[i]) continue; //skip if undefined
			layer = sorted[i];
			zlength = layer.length;

			//loop over all objects with current Z index
			for(j=0;j<zlength;++j) {
				var todraw = layer[j];

				//only draw visible area
				if(todraw[0] !== obj[0]) { //don't redraw partial self
					var x = (old._x - todraw._x <= 0) ? 0 : (old._x - todraw._x),
						y = Math.ceil(old._y - todraw._y < 0 ? 0 : (old._y - todraw._y)),
						w = Math.min(todraw._w - x, old._w - (todraw._x - old._x), old._w),
						h = Math.ceil(Math.min(todraw._h - y, old._h - (todraw._y - old._y), old._h));

					if(h === 0 || w === 0) continue; //don't bother drawing with h or w as 0
					todraw.draw(x,y,w,h);

				} else todraw.draw(); //redraw self
			}
		}
	},

	remove: function(obj) {
		this.redraw(obj,obj);
	}
};
<commit_msg>* Added padding to sprite<commit_after>Crafty.extend({

	randRange: function(from, to) {
		return Math.round(Math.random() * (to - from) + from);
	},

	/**
	* Sprite generator.
	*
	* Extends Crafty for producing components
	* based on sprites and tiles
	*/
	sprite: function(tile, url, map, paddingX, paddingY) {
		var pos, temp, x, y, w, h;

		//if no tile value, default to 16
		if(typeof tile === "string") {
			map = url;
			url = tile;
			tile = 1;
		}

		//if no paddingY, use paddingX
		if(!paddingY && paddingX) paddingY = paddingX;
		paddingX = parseInt(paddingX, 10); //just incase
		paddingY = parseInt(paddingY, 10);

		for(pos in map) {
			if(!map.hasOwnProperty(pos)) continue;

			temp = map[pos];
			x = (temp[0] + paddingX) * tile;
			y = (temp[1] + paddingY) * tile;
			w = temp[2] * tile || tile;
			h = temp[3] * tile || tile;

			//create a component for the sprite
			Crafty.c(pos, {
				__image: url,
				__coord: [x,y,w,h],
				__tile: tile,
				__padding: [paddingX, paddingY],

				init: function() {
					this.addComponent("sprite");
					if(this.has("canvas")) {
						this.img = new Image();
						this.img.src = this.__image;
						//draw when ready
						Crafty.addEvent(this, this.img, 'load', function() {
							DrawBuffer.add(this); //send to buffer to keep Z order
						});
					}
					this.w = this.__coord[2];
					this.h = this.__coord[3];
				},

				sprite: function(x,y,w,h) {
					x += this.__padding[0];
					y += this.__padding[1];
					this.__coord = [x*this.__tile,y*this.__tile,w*this.__tile || this.__tile,h*this.__tile || this.__tile];
					if(this.has("canvas")) DrawBuffer.add(this);
					else if(this.has("DOM")) this.draw();
				}
			});
		}

		return this;
	},

	_events: {},

	/**
	* Window Events credited to John Resig
	* http://ejohn.org/projects/flexible-javascript-events
	*/
	addEvent: function(ctx, obj, type, fn) {
		if(arguments.length === 3) {
			fn = type;
			type = obj;
			obj = window.document;
		}

		//save anonymous function to be able to remove
		var afn = function(e) { var e = e || window.event; fn.call(ctx,e) };
		if(!this._events[obj+type+fn]) this._events[obj+type+fn] = afn;
		else return;

		if (obj.attachEvent) { //IE
			obj.attachEvent('on'+type, afn);
		} else { //Everyone else
			obj.addEventListener(type, afn, false);
		}
	},

	removeEvent: function(ctx, obj, type, fn) {
		if(arguments.length === 3) {
			fn = type;
			type = obj;
			obj = window.document;
		}

		//retrieve anonymouse function
		var afn = this._events[obj+type+fn];

		if(afn) {
			if (obj.detachEvent) {
				obj.detachEvent('on'+type, afn);
			} else obj.removeEventListener(type, afn, false);
			delete this._events[obj+type+fn];
		}
	},

	window: {
		width: window.innerWidth || (window.document.documentElement.clientWidth || window.document.body.clientWidth),
		height: window.innerHeight || (window.document.documentElement.clientHeight || window.document.body.clientHeight)
	},

	background: function(color) {
		Crafty.stage.elem.style.background = color;
	},

	viewport: {
		width: 0,
		height: 0,
		_x: 0,
		_y: 0,

		scroll: function(axis, v) {
			var old = this[axis],
				q,
				i = 0, j = 0, l, m,
				box,
				dupes = {},
				rect,
				sorted = [];

			//clear screen
			if(Crafty.context) Crafty.context.clearRect(0,0, this.width, this.height);

			rect = {x: axis == '_x' ? old : this._x, y: axis == '_y' ? old : this._y, w: this.width, h:this.height};
			q = Crafty.map.search(rect, false);

			for(l=q.length;i<l;++i) {
				box = q[i];

				if(!dupes[box[0]]) {
					dupes[box[0]] = true;
					if(!sorted[box._z]) sorted[box._z] = [];

					sorted[box._z].push(box);
				}
			}

			Crafty("2D obj").each(function() {
				var oldposition = this.pos();

				this[axis] -= old - v;
				//if no setter available
				if(Crafty.support.setter === false) {
					this[axis.substr(1)] = this[axis];
					this.trigger("change", oldposition);
				}
				this.trigger("move",oldposition);
			});

			m = sorted.length;
			for(;j<m;j++) {
				if(!sorted[j]) continue;
				var k = 0, n = sorted[j].length;
				for(;k<n;k++) {
					if('draw' in sorted[j][k])
						sorted[j][k].draw();
				}
			}

			this[axis] = v;
		},

		rect: function() {
			return {x: this._x, y: this._y, w: this.width, h: this.height};
		},

		init: function(w,h) {
			this.width = w || Crafty.window.width;
			this.height = h || Crafty.window.height;

			//stop scrollbars
			if(!w && !h) {
				document.body.style.overflow = "hidden";
			}

			//check if stage exists
			var crstage = document.getElementById("cr-stage");

			//create stage div to contain everything
			Crafty.stage = {
				x: 0,
				y: 0,
				elem: (crstage ? crstage : document.createElement("div"))
			};

			//add to the body and give it an ID if not exists
			if(!crstage) {
				document.body.appendChild(Crafty.stage.elem);
				Crafty.stage.elem.id = "cr-stage";
			}

			var elem = Crafty.stage.elem.style,
				offset;

			//css style
			elem.width = this.width + "px";
			elem.height = this.height + "px";
			elem.overflow = "hidden";
			elem.position = "relative";

			//find out the offset position of the stage
			offset = Crafty.inner(Crafty.stage.elem);
			Crafty.stage.x = offset.x;
			Crafty.stage.y = offset.y;

			if('__defineSetter__' in this && '__defineGetter__' in this) {
				//define getters and setters to scroll the viewport
				this.__defineSetter__('x', function(v) { this.scroll('_x', v); });
				this.__defineSetter__('y', function(v) { this.scroll('_y', v); });
				this.__defineGetter__('x', function() { return this._x; });
				this.__defineGetter__('y', function() { return this._y; });
			} else {
				//create empty entity waiting for enterframe
				this.x = this._x;
				this.y = this._y;
				Crafty.e("viewport");
			}
		}
	},

	support: {},

	/**
	* Map key names to key codes
	*/
	keys: {'BSP':8, 'TAB':9, 'ENT':13, 'SHF':16, 'CTR':17, 'ALT':18, 'PAU':19, 'CAP':20, 'ESC':27, 'SP':32, 'PGU':33, 'PGD':34, 'END':35, 'HOM':36, 'LA':37, 'UA':38, 'RA':39, 'DA':40, 'INS':45, 'DEL':46, 'D0':48, 'D1':49, 'D2':50, 'D3':51, 'D4':52, 'D5':53, 'D6':54, 'D7':55, 'D8':56, 'D9':57, 'SEM':59, 'EQL':61, 'A':65, 'B':66, 'C':67, 'D':68, 'E':69, 'F':70, 'G':71, 'H':72, 'I':73, 'J':74, 'K':75, 'L':76, 'M':77, 'N':78, 'O':79, 'P':80, 'Q':81, 'R':82, 'S':83, 'T':84, 'U':85, 'V':86, 'W':87, 'X':88, 'Y':89, 'Z':90, 'LWN':91, 'RWN':92, 'SEL':93, 'N0':96, 'N1':97, 'N2':98, 'N3':99, 'N4':100, 'N5':101, 'N6':102, 'N7':103, 'N8':104, 'N9':105, 'MUL':106, 'ADD':107, 'SUB':109, 'DEC':110, 'DIV':111, 'F1':112, 'F2':113, 'F3':114, 'F4':115, 'F5':116, 'F6':117, 'F7':118, 'F8':119, 'F9':120, 'F10':121, 'F11':122, 'F12':123, 'NUM':144, 'SCR':145, 'COM':188, 'PER':190, 'FSL':191, 'ACC':192, 'OBR':219, 'BSL':220, 'CBR':221, 'QOT':222}
});

/**
* Entity fixes the lack of setter support
*/
Crafty.c("viewport", {
	init: function() {
		this.bind("enterframe", function() {
			if(Crafty.viewport._x !== Crafty.viewport.x) {
				Crafty.viewport.scroll('_x', Crafty.viewport.x);
			}

			if(Crafty.viewport._y !== Crafty.viewport.y) {
				Crafty.viewport.scroll('_y', Crafty.viewport.y);
			}
		});
	}
});

var DrawBuffer = {

	add: function add(obj, old) {
		//redraw old position that was cleared
		this.redraw(obj,old);

		//redraw obj in new position
		this.redraw(obj);
	},

	/**
	* Find all objects intersected by this
	* and redraw them in order of Z
	*/
	redraw: function redraw(obj, old) {
		var q,
			i = 0,
			j = 0,
			keylength,
			zlength,
			box,
			z,
			layer,
			total = 0,
			redrawSelf = false,
			dupes = {}, //lookup of dupes
			sorted = []; //bucket sort

		if(!old) redrawSelf = true; //redraw self if no old param passed
		old = old || obj; //default old x & y to obj

		q = Crafty.map.search({x: old._x, y: old._y, w: old._w, h: old._h},false);

		for(i=0;i<q.length;++i) {
			box = q[i];

			//if found is canvas, not a duplicate and intersects (inlined for performance)
			if(box.isCanvas && !dupes[box[0]] && box._x < old._x + old._w && box._x + box._w > old._x &&
												 box._y < old._y + old._h && box._h + box._y > old._y) {
				dupes[box[0]] = true; //don't search again
				if(box === obj && !redrawSelf) continue; //TAKE HEED, don't return dear lord
				if(!sorted[box._z]) sorted[box._z] = [];

				sorted[box._z].push(box);
				++total;
			}
		};

		//skip if nothing added
		if(total == 0) return;
		//only draw self
		if(total == 1 && redrawSelf) {
			obj.draw();
			return;
		}

		//loop over sorted Z keys
		for(i=0, keylength = sorted.length; i < keylength; ++i) {
			if(!sorted[i]) continue; //skip if undefined
			layer = sorted[i];
			zlength = layer.length;

			//loop over all objects with current Z index
			for(j=0;j<zlength;++j) {
				var todraw = layer[j];

				//only draw visible area
				if(todraw[0] !== obj[0]) { //don't redraw partial self
					var x = (old._x - todraw._x <= 0) ? 0 : (old._x - todraw._x),
						y = Math.ceil(old._y - todraw._y < 0 ? 0 : (old._y - todraw._y)),
						w = Math.min(todraw._w - x, old._w - (todraw._x - old._x), old._w),
						h = Math.ceil(Math.min(todraw._h - y, old._h - (todraw._y - old._y), old._h));

					if(h === 0 || w === 0) continue; //don't bother drawing with h or w as 0
					todraw.draw(x,y,w,h);

				} else todraw.draw(); //redraw self
			}
		}
	},

	remove: function(obj) {
		this.redraw(obj,obj);
	}
};
<|endoftext|>


<commit_before>import { extractWithRegex } from './util';
import {
  hashRegex,
  hostnameRegex,
  pathnameRegex,
  portRegex,
  protocolRegex,
} from './regex';

export const extractHash = extractWithRegex(hashRegex());

export const extractHostname = extractWithRegex(hostnameRegex());

export const extractPathname = extractWithRegex(pathnameRegex());

export const extractPort = extractWithRegex(portRegex());

export const extractProtocol = extractWithRegex(protocolRegex());

export const extractQuery = (url) => {
  if (url.split('?').length !== 2) { return {}; }
  return url.split('?')[1]
    .split('#')
    .filter(pair => !!pair)
    .map(pair => pair.split('='))
    .reduce((query, [key, value]) =>
      Object.assign({}, query, { [key]: (value || true) }), {});
};
<commit_msg>Fix: eslint style issue<commit_after>import { extractWithRegex } from './util';
import {
  hashRegex,
  hostnameRegex,
  pathnameRegex,
  portRegex,
  protocolRegex,
} from './regex';

export const extractHash = extractWithRegex(hashRegex());

export const extractHostname = extractWithRegex(hostnameRegex());

export const extractPathname = extractWithRegex(pathnameRegex());

export const extractPort = extractWithRegex(portRegex());

export const extractProtocol = extractWithRegex(protocolRegex());

export const extractQuery = (url) => {
  if (url.split('?').length !== 2) { return {}; }
  return url.split('?')[1]
    .split('#')
    .filter(pair => !!pair)
    .map(pair => pair.split('='))
    .reduce((query, [key, value]) =>
      Object.assign({}, query, { [key]: value || true }), {});
};
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var exec = require('child_process').exec;

/**
 * Asyncronous function to remove all files and (including non-empty) directories from path
 *
 * @param path
 * @param callback(err)
 */
module.exports.removeDirectoryContents = function (path, callback)
{
    if (path.substr(-1, 1) !== '/') {
        path += '/';
    }

    exec('rm -r ' + path + '*', function (err) {
        callback(err);
    });
};

/**
 * Synchronous function for recursively walking through a directory and returning an array of files inside the directory
 * and is subdirectories
 *
 * @param {String} dir
 * @returns {Array}
 */
module.exports.walkSync = function walkSync(dir)
{
    var results = [];
    var list = fs.readdirSync(dir);

    list.forEach(function(file) {
        file = dir + '/' + file;
        var stat = fs.statSync(file);

        if (stat && stat.isDirectory()) {
            results = results.concat(walkSync(file));
        } else {
            results.push(file)
        }
    });

    return results
};
<commit_msg>@param types<commit_after>'use strict';

var fs = require('fs');
var exec = require('child_process').exec;

/**
 * Asyncronous function to remove all files and (including non-empty) directories from path
 *
 * @param {String} path
 * @param {Function} callback(err)
 */
module.exports.removeDirectoryContents = function (path, callback)
{
    if (path.substr(-1, 1) !== '/') {
        path += '/';
    }

    exec('rm -r ' + path + '*', function (err) {
        callback(err);
    });
};

/**
 * Synchronous function for recursively walking through a directory and returning an array of files inside the directory
 * and is subdirectories
 *
 * @param {String} dir
 * @returns {Array}
 */
module.exports.walkSync = function walkSync(dir)
{
    var results = [];
    var list = fs.readdirSync(dir);

    list.forEach(function(file) {
        file = dir + '/' + file;
        var stat = fs.statSync(file);

        if (stat && stat.isDirectory()) {
            results = results.concat(walkSync(file));
        } else {
            results.push(file)
        }
    });

    return results
};
<|endoftext|>


<commit_before>/*globals define*/
/*jshint node:true, browser:true*/

/**
 * Generated by PluginGenerator from webgme on Thu Jun 11 2015 09:00:58 GMT-0500 (Central Daylight Time).
 */

define([
    'plugin/PluginConfig',
    'plugin/PluginBase',
    'common/util/xmljsonconverter'
], function (PluginConfig, PluginBase, Converters) {
    'use strict';

    /**
     * Initializes a new instance of MetaGMEParadigmImporter.
     * @class
     * @augments {PluginBase}
     * @classdesc This class represents the plugin MetaGMEParadigmImporter.
     * @constructor
     */
    var MetaGMEParadigmImporter = function () {
        // Call base class' constructor.
        PluginBase.call(this);
    };

    // Prototypal inheritance from PluginBase.
    MetaGMEParadigmImporter.prototype = Object.create(PluginBase.prototype);
    MetaGMEParadigmImporter.prototype.constructor = MetaGMEParadigmImporter;

    /**
     * Gets the name of the MetaGMEParadigmImporter.
     * @returns {string} The name of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getName = function () {
        return 'MetaGME Paradigm Importer';
    };

    /**
     * Gets the semantic version (semver.org) of the MetaGMEParadigmImporter.
     * @returns {string} The version of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getVersion = function () {
        return '0.1.0';
    };

    /**
     * Gets the description of the MetaGMEParadigmImporter.
     * @returns {string} The description of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getDescription = function () {
        return 'Imports a desktop GME XMP file into the meta sheet.';
    };

    /**
     * Gets the configuration structure for the MetaGMEParadigmImporter.
     * The ConfigurationStructure defines the configuration for the plugin
     * and will be used to populate the GUI when invoking the plugin from webGME.
     * @returns {object} The version of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getConfigStructure = function () {
        return [
            {
                name: 'xmpFile',
                displayName: 'XMP file',
                description: 'Flat desktop GME meta model',
                value: '', //'0afba05ea2640d9ebc2af8223b7a24cff95c5e20',
                valueType: 'asset',
                readOnly: false
            }
        ];
    };

    /**
     * Main function for the plugin to execute. This will perform the execution.
     * Notes:
     * - Always log with the provided logger.[error,warning,info,debug].
     * - Do NOT put any user interaction logic UI, etc. inside this method.
     * - callback always has to be called even if error happened.
     *
     * @param {function(string, plugin.PluginResult)} callback - the result callback
     */
    MetaGMEParadigmImporter.prototype.main = function (callback) {
        var self = this,
            config = self.getCurrentConfig(),
            xml2json = new Converters.Xml2json({
                skipWSText: true,
                arrayElements: {
                    attrdef: true,
                    folder: true,
                    atom: true,
                    connection: true,
                    model: true,
                    aspect: true,
                    role: true,
                    constraint: true,
                    pointerspec: true,
                    regnode: true,
                    enumitem: true
                    //TODO: Complete this list
                }
            }),
            xmpData;

        self.logger.debug('Checking configuration');

        if (!config.xmpFile) {
            self.createMessage(null, 'An XMP file must be provided.', 'error');
            callback(null, self.result);
            return;
        }

        self.logger.debug('Getting xmp file content');

        self.blobClient.getObject(config.xmpFile, function (err, xmlArrayBuffer) {
            var error;

            if (err) {
                callback(err, self.result);
                return;
            }

            self.logger.debug('Got xmp file content, converting it to json');
            if (typeof xmlArrayBuffer === 'string') {
                xmpData = xml2json.convertFromString(xmlArrayBuffer);
            } else {
                xmpData = xml2json.convertFromBuffer(xmlArrayBuffer);
            }

            error = self.processParadigm(xmpData);

            if (error) {
                self.result.setSuccess(false);
                self.result.setError(error.message);
                callback(error, self.result);
                return;
            }

            // FIXME: commit message is not respected by PluginBase, should be appended to the default base message.
            self.save('Imported meta model ' + xmpData.paradigm['@name'], function (err) {
                if (err) {
                    self.result.setSuccess(false);
                    self.result.setError(err);
                }
                callback(null, self.result);
            });
        });
    };

    MetaGMEParadigmImporter.prototype.processParadigm = function (xmpData) {
        var self = this,
            paradigm,
            rootFolder,
            error,
            i,
            attrdef;

        self.logger.debug('Processing given xmp', {metadata: xmpData});

        self.result.setSuccess(true);

        self.cache = {
            languageNode: null, // reference to the language node in webgme
            nodes: {},          // references by name to the node objects
            xmpMetaNode: {},    // references by name to xmp descriptors
            attributes: {}      // references by name to xmp attribute definitions
        };

        self.logger.debug('Checking for important key values in xmp');
        if (xmpData.hasOwnProperty('paradigm')) {
            // create Language object in root
            paradigm = xmpData.paradigm;
            error = self.createLanguageNode(paradigm);
            if (error) {
                return error;
            }
        } else {
            return new Error('Invalid xmpData: paradigm key does not exist.');
        }

        if (paradigm.hasOwnProperty('folder') === false) {
            return new Error('Invalid xmpData.paradigm: folder key does not exist.');
        }

        if (typeof paradigm.folder[0] === 'object') {
            rootFolder = paradigm.folder[0];
        } else {
            return new Error('Invalid xmpData.paradigm.folder: does not have a valid first element in the array.');
        }

        if (typeof rootFolder.hasOwnProperty('attrdef') === false) {
            return new Error('Invalid xmpData.paradigm.folder[0]: attrdef key does not exist.');
        }

        // cache attributes
        self.logger.debug('Caching attributes ...');
        for (i = 0; i < rootFolder.attrdef.length; i += 1) {
            attrdef = rootFolder.attrdef[i];
            self.cache.attributes[attrdef['@name']] = attrdef;
            self.logger.debug('Cached: ' + attrdef['@name'], {metadata: attrdef});
        }
        self.logger.debug('Caching attributes done.');

        // add objects to the language object including attributes
        //  folders
        //  atoms
        //  connections
        //  references
        //  sets
        error = self.createNodes(rootFolder);
        if (error) {
            return error;
        }

        // TODO: add meta rules
        error = self.createMetaRules(rootFolder);
        if (error) {
            return error;
        }

        // TODO: add objects to meta sheets

    };

    MetaGMEParadigmImporter.prototype.createLanguageNode = function (paradigm) {
        var self = this,
            languageNode;

        self.logger.debug('Creating language node ...');

        languageNode = self.core.createNode({
            parent: self.rootNode,
            base: self.META.FCO
        });

        self.core.setAttributeMeta(languageNode, 'cdate', {type: 'string', default: ''});
        self.core.setAttributeMeta(languageNode, 'mdate', {type: 'string', default: ''});
        // TODO: comment field
        // TODO: author field

        self.core.setAttribute(languageNode, 'name', 'Language [' + paradigm['@name'] + ']');
        self.core.setAttribute(languageNode, 'cdate', paradigm['@cdate']);
        self.core.setAttribute(languageNode, 'mdate', paradigm['@mdate']);

        // TODO: set default view to META

        self.core.setRegistry(languageNode, 'position', {x: 100, y: 200});

        self.cache.languageNode = languageNode;

        self.logger.debug('Created language node: ' + self.core.getPath(languageNode));
    };

    MetaGMEParadigmImporter.prototype.createNodes = function (rootFolder) {
        var self = this,
            i,
            j,
            type,
            types = ['atom', 'folder', 'model', 'set', 'connection', 'reference'],
            error;

        self.logger.debug('Creating nodes ...');

        self.createNode(rootFolder);

        for (j = 0; j < types.length; j += 1) {
            type = types[j];
            if (rootFolder.hasOwnProperty(type)) {
                for (i = 0; i < rootFolder[type].length; i += 1) {
                    self.createNode(rootFolder[type][i]);
                }
            }
        }

        self.logger.debug('Created ' + Object.keys(self.cache.nodes).length + ' nodes.');
    };

    MetaGMEParadigmImporter.prototype.createNode = function (xmpMetaNode) {
        var self = this,
            node,
            name = xmpMetaNode['@name'],
            x,
            y,
            attributeNames,
            attributeName,
            xmpAttribute,
            i;

        self.logger.debug('Creating node: ' + name);

        node = self.core.createNode({
            parent: self.cache.languageNode,
            base: self.META.FCO
        });

        self.core.setAttributeMeta(node, 'metaref', {type: 'string', default: '0'});

        if (xmpMetaNode.hasOwnProperty('@attributes')) {
            // add attributes
            attributeNames = xmpMetaNode['@attributes'].split(' ');
            for (i = 0; i < attributeNames.length; i += 1) {
                attributeName = attributeNames[i];
                xmpAttribute = self.cache.attributes[attributeName];
                if (xmpAttribute) {
                    // TODO: handle parameter type appropriately
                    self.core.setAttributeMeta(node,
                        xmpAttribute['@name'],
                        {
                            type: 'string',
                            default: xmpAttribute['@defvalue']
                        });
                    self.core.setAttribute(node, xmpAttribute['@name'], xmpAttribute['@defvalue']);
                } else {
                    self.logger.error('Attribute was not found in global cache: ',
                        {metadata: {attrName: attributeName, xmpMetaNode: xmpMetaNode}});
                }
            }
        }

        self.core.setAttribute(node, 'name', name);
        self.core.setAttribute(node, 'metaref', xmpMetaNode['@metaref']);

        // FIXME: improve the auto layout of the nodes
        x = 100;
        y = Object.keys(self.cache.nodes).length * 80 + 80;

        self.core.setRegistry(node, 'position', {x: x, y: y});

        self.cache.nodes[name] = node;
        self.cache.xmpMetaNode[name] = xmpMetaNode;

        self.logger.debug('Created node: ' + name + ' - ' + self.core.getPath(node));

        return node;
    };

    MetaGMEParadigmImporter.prototype.createMetaRules = function () {
        var self = this,
            xmpMetaNames = Object.keys(self.cache.xmpMetaNode),
            xmpMetaName,
            xmpNode,
            childObjectNames,
            i;

        // use cache to create meta rules
        self.logger.debug('Creating meta rules ...');

        for (i = 0; i < xmpMetaNames.length; i += 1) {
            xmpMetaName = xmpMetaNames[i];
            xmpNode = self.cache.xmpMetaNode[xmpMetaName];
            if (xmpNode.hasOwnProperty('@subfolders')) {
                childObjectNames = xmpNode['@subfolders'].split(' ');
                self.addValidChildren(self.cache.nodes[xmpMetaName], childObjectNames);
            }

            if (xmpNode.hasOwnProperty('@rootobjects')) {
                childObjectNames = xmpNode['@rootobjects'].split(' ');
                self.addValidChildren(self.cache.nodes[xmpMetaName], childObjectNames);
            }

            if (xmpNode.hasOwnProperty('role')) {
                // TODO: add possible child objects
            }

            if (xmpNode.hasOwnProperty('connjoint')) {
                // TODO: add possible connection rules

            }

            // TODO: references

            // TODO: sets
        }

        // TODO: add elements to meta sheets

        self.logger.debug('Created meta rules.');
    };

    MetaGMEParadigmImporter.prototype.addValidChildren = function (parentNode, childObjectNames) {
        var self = this,
            childNode,
            i;

        for (i = 0; i < childObjectNames.length; i += 1) {
            childNode = self.cache.nodes[childObjectNames[i]];
            self.core.setChildMeta(parentNode, childNode);
            self.logger.debug(self.core.getAttribute(parentNode, 'name') + ' can contain ' + childObjectNames[i]);
        }
    };

    return MetaGMEParadigmImporter;
});
<commit_msg>#388 add elements to MetaSheet.<commit_after>/*globals define*/
/*jshint node:true, browser:true*/

/**
 * Generated by PluginGenerator from webgme on Thu Jun 11 2015 09:00:58 GMT-0500 (Central Daylight Time).
 */

define([
    'plugin/PluginConfig',
    'plugin/PluginBase',
    'common/util/xmljsonconverter'
], function (PluginConfig, PluginBase, Converters) {
    'use strict';

    /**
     * Initializes a new instance of MetaGMEParadigmImporter.
     * @class
     * @augments {PluginBase}
     * @classdesc This class represents the plugin MetaGMEParadigmImporter.
     * @constructor
     */
    var MetaGMEParadigmImporter = function () {
        // Call base class' constructor.
        PluginBase.call(this);
    };

    // Prototypal inheritance from PluginBase.
    MetaGMEParadigmImporter.prototype = Object.create(PluginBase.prototype);
    MetaGMEParadigmImporter.prototype.constructor = MetaGMEParadigmImporter;

    /**
     * Gets the name of the MetaGMEParadigmImporter.
     * @returns {string} The name of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getName = function () {
        return 'MetaGME Paradigm Importer';
    };

    /**
     * Gets the semantic version (semver.org) of the MetaGMEParadigmImporter.
     * @returns {string} The version of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getVersion = function () {
        return '0.1.0';
    };

    /**
     * Gets the description of the MetaGMEParadigmImporter.
     * @returns {string} The description of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getDescription = function () {
        return 'Imports a desktop GME XMP file into the meta sheet.';
    };

    /**
     * Gets the configuration structure for the MetaGMEParadigmImporter.
     * The ConfigurationStructure defines the configuration for the plugin
     * and will be used to populate the GUI when invoking the plugin from webGME.
     * @returns {object} The version of the plugin.
     * @public
     */
    MetaGMEParadigmImporter.prototype.getConfigStructure = function () {
        return [
            {
                name: 'xmpFile',
                displayName: 'XMP file',
                description: 'Flat desktop GME meta model',
                value: '', //'0afba05ea2640d9ebc2af8223b7a24cff95c5e20',
                valueType: 'asset',
                readOnly: false
            }
        ];
    };

    /**
     * Main function for the plugin to execute. This will perform the execution.
     * Notes:
     * - Always log with the provided logger.[error,warning,info,debug].
     * - Do NOT put any user interaction logic UI, etc. inside this method.
     * - callback always has to be called even if error happened.
     *
     * @param {function(string, plugin.PluginResult)} callback - the result callback
     */
    MetaGMEParadigmImporter.prototype.main = function (callback) {
        var self = this,
            config = self.getCurrentConfig(),
            xml2json = new Converters.Xml2json({
                skipWSText: true,
                arrayElements: {
                    attrdef: true,
                    folder: true,
                    atom: true,
                    connection: true,
                    model: true,
                    aspect: true,
                    role: true,
                    constraint: true,
                    pointerspec: true,
                    regnode: true,
                    enumitem: true
                    //TODO: Complete this list
                }
            }),
            xmpData;

        self.logger.debug('Checking configuration');

        if (!config.xmpFile) {
            self.createMessage(null, 'An XMP file must be provided.', 'error');
            callback(null, self.result);
            return;
        }

        self.logger.debug('Getting xmp file content');

        self.blobClient.getObject(config.xmpFile, function (err, xmlArrayBuffer) {
            var error;

            if (err) {
                callback(err, self.result);
                return;
            }

            self.logger.debug('Got xmp file content, converting it to json');
            if (typeof xmlArrayBuffer === 'string') {
                xmpData = xml2json.convertFromString(xmlArrayBuffer);
            } else {
                xmpData = xml2json.convertFromBuffer(xmlArrayBuffer);
            }

            error = self.processParadigm(xmpData);

            if (error) {
                self.result.setSuccess(false);
                self.result.setError(error.message);
                callback(error, self.result);
                return;
            }

            // FIXME: commit message is not respected by PluginBase, should be appended to the default base message.
            self.save('Imported meta model ' + xmpData.paradigm['@name'], function (err) {
                if (err) {
                    self.result.setSuccess(false);
                    self.result.setError(err);
                }
                callback(null, self.result);
            });
        });
    };

    MetaGMEParadigmImporter.prototype.processParadigm = function (xmpData) {
        var self = this,
            paradigm,
            rootFolder,
            error,
            i,
            attrdef;

        self.logger.debug('Processing given xmp', {metadata: xmpData});

        self.result.setSuccess(true);

        self.cache = {
            languageNode: null, // reference to the language node in webgme
            nodes: {},          // references by name to the node objects
            xmpMetaNode: {},    // references by name to xmp descriptors
            attributes: {}      // references by name to xmp attribute definitions
        };

        self.logger.debug('Checking for important key values in xmp');
        if (xmpData.hasOwnProperty('paradigm')) {
            // create Language object in root
            paradigm = xmpData.paradigm;
            error = self.createLanguageNode(paradigm);
            if (error) {
                return error;
            }
        } else {
            return new Error('Invalid xmpData: paradigm key does not exist.');
        }

        if (paradigm.hasOwnProperty('folder') === false) {
            return new Error('Invalid xmpData.paradigm: folder key does not exist.');
        }

        if (typeof paradigm.folder[0] === 'object') {
            rootFolder = paradigm.folder[0];
        } else {
            return new Error('Invalid xmpData.paradigm.folder: does not have a valid first element in the array.');
        }

        if (typeof rootFolder.hasOwnProperty('attrdef') === false) {
            return new Error('Invalid xmpData.paradigm.folder[0]: attrdef key does not exist.');
        }

        // cache attributes
        self.logger.debug('Caching attributes ...');
        for (i = 0; i < rootFolder.attrdef.length; i += 1) {
            attrdef = rootFolder.attrdef[i];
            self.cache.attributes[attrdef['@name']] = attrdef;
            self.logger.debug('Cached: ' + attrdef['@name'], {metadata: attrdef});
        }
        self.logger.debug('Caching attributes done.');

        // add objects to the language object including attributes
        //  folders
        //  atoms
        //  connections
        //  references
        //  sets
        error = self.createNodes(rootFolder);
        if (error) {
            return error;
        }

        // TODO: add meta rules
        error = self.createMetaRules(rootFolder);
        if (error) {
            return error;
        }
    };

    MetaGMEParadigmImporter.prototype.createLanguageNode = function (paradigm) {
        var self = this,
            languageNode;

        self.logger.debug('Creating language node ...');

        languageNode = self.core.createNode({
            parent: self.rootNode,
            base: self.META.FCO
        });

        self.core.setAttributeMeta(languageNode, 'cdate', {type: 'string', default: ''});
        self.core.setAttributeMeta(languageNode, 'mdate', {type: 'string', default: ''});
        // TODO: comment field
        // TODO: author field

        self.core.setAttribute(languageNode, 'name', 'Language [' + paradigm['@name'] + ']');
        self.core.setAttribute(languageNode, 'cdate', paradigm['@cdate']);
        self.core.setAttribute(languageNode, 'mdate', paradigm['@mdate']);

        // TODO: set default view to META

        self.core.setRegistry(languageNode, 'position', {x: 100, y: 200});

        self.cache.languageNode = languageNode;

        self.logger.debug('Created language node: ' + self.core.getPath(languageNode));
    };

    MetaGMEParadigmImporter.prototype.createNodes = function (rootFolder) {
        var self = this,
            i,
            j,
            type,
            types = ['atom', 'folder', 'model', 'set', 'connection', 'reference'],
            error;

        self.logger.debug('Creating nodes ...');

        self.createNode(rootFolder);

        for (j = 0; j < types.length; j += 1) {
            type = types[j];
            if (rootFolder.hasOwnProperty(type)) {
                for (i = 0; i < rootFolder[type].length; i += 1) {
                    self.createNode(rootFolder[type][i]);
                }
            }
        }

        self.logger.debug('Created ' + Object.keys(self.cache.nodes).length + ' nodes.');
    };

    MetaGMEParadigmImporter.prototype.createNode = function (xmpMetaNode) {
        var self = this,
            node,
            name = xmpMetaNode['@name'],
            x,
            y,
            attributeNames,
            attributeName,
            xmpAttribute,
            i;

        self.logger.debug('Creating node: ' + name);

        node = self.core.createNode({
            parent: self.cache.languageNode,
            base: self.META.FCO
        });

        self.core.setAttributeMeta(node, 'metaref', {type: 'string', default: '0'});

        if (xmpMetaNode.hasOwnProperty('@attributes')) {
            // add attributes
            attributeNames = xmpMetaNode['@attributes'].split(' ');
            for (i = 0; i < attributeNames.length; i += 1) {
                attributeName = attributeNames[i];
                xmpAttribute = self.cache.attributes[attributeName];
                if (xmpAttribute) {
                    // TODO: handle parameter type appropriately
                    self.core.setAttributeMeta(node,
                        xmpAttribute['@name'],
                        {
                            type: 'string',
                            default: xmpAttribute['@defvalue']
                        });
                    self.core.setAttribute(node, xmpAttribute['@name'], xmpAttribute['@defvalue']);
                } else {
                    self.logger.error('Attribute was not found in global cache: ',
                        {metadata: {attrName: attributeName, xmpMetaNode: xmpMetaNode}});
                }
            }
        }

        self.core.setAttribute(node, 'name', name);
        self.core.setAttribute(node, 'metaref', xmpMetaNode['@metaref']);

        // FIXME: improve the auto layout of the nodes
        x = 100;
        y = Object.keys(self.cache.nodes).length * 80 + 80;

        self.core.setRegistry(node, 'position', {x: x, y: y});

        self.cache.nodes[name] = node;
        self.cache.xmpMetaNode[name] = xmpMetaNode;

        self.logger.debug('Created node: ' + name + ' - ' + self.core.getPath(node));

        return node;
    };

    MetaGMEParadigmImporter.prototype.createMetaRules = function () {
        var self = this,
            xmpMetaNames = Object.keys(self.cache.xmpMetaNode),
            xmpMetaName,
            xmpNode,
            node,
            childObjectNames,
            i,
            j,
            position,
            x,
            y,
            setNames = self.core.getSetNames(self.rootNode);

        // use cache to create meta rules
        self.logger.debug('Creating meta rules ...');

        for (i = 0; i < xmpMetaNames.length; i += 1) {
            xmpMetaName = xmpMetaNames[i];
            node = self.cache.nodes[xmpMetaName];
            xmpNode = self.cache.xmpMetaNode[xmpMetaName];

            if (xmpNode.hasOwnProperty('@subfolders')) {
                childObjectNames = xmpNode['@subfolders'].split(' ');
                self.addValidChildren(node, childObjectNames);
            }

            if (xmpNode.hasOwnProperty('@rootobjects')) {
                childObjectNames = xmpNode['@rootobjects'].split(' ');
                self.addValidChildren(node, childObjectNames);
            }

            if (xmpNode.hasOwnProperty('role')) {
                // TODO: add possible child objects
                //for (j = 0; j < xmpNode.role.length; j += 1) {
                //
                //}
            }

            if (xmpNode.hasOwnProperty('connjoint')) {
                // TODO: add possible connection rules

            }

            // TODO: references

            // TODO: sets

            x = 100 + (i % 10) * 150;
            y = 300 + Math.floor(i / 10) * 200;

            position = {
                x: x,
                y: y
            };

            // add element to meta sheets
            for (j = 0; j < setNames.length; j += 1) {
                if (setNames[j].indexOf('MetaAspectSet') > -1) {
                    self.core.addMember(self.rootNode, setNames[j], node);
                    self.core.setMemberRegistry(self.rootNode,
                        setNames[j],
                        self.core.getPath(node),
                        'position',
                        position);
                }
            }
        }

        self.logger.debug('Created meta rules.');
    };

    MetaGMEParadigmImporter.prototype.addValidChildren = function (parentNode, childObjectNames) {
        var self = this,
            childNode,
            i;

        for (i = 0; i < childObjectNames.length; i += 1) {
            childNode = self.cache.nodes[childObjectNames[i]];
            self.core.setChildMeta(parentNode, childNode);
            self.logger.debug(self.core.getAttribute(parentNode, 'name') + ' can contain ' + childObjectNames[i]);
        }
    };

    return MetaGMEParadigmImporter;
});
<|endoftext|>


<commit_before>/**
 * KBase widget to display table and boxplot of BIOM data
 */
define([
    'jquery',
    'kb_common/html',
    'kb_service/client/workspace',

    'kbaseUI/widget/legacy/authenticatedWidget',
    'datatables_bootstrap'
], function ($, html, Workspace) {
    'use strict';
    $.KBWidget({
        name: 'AnnotationSetTable',
        parent: 'kbaseAuthenticatedWidget',
        version: '1.0.0',
        options: {
            id: null,
            ws: null
        },
        init: function (options) {
            this._super(options);
            return this;
        },
        render: function () {
            var self = this;
            var container = this.$elem;
            container.empty();
            if (!this.runtime.service('session').isLoggedIn()) {
                container.append('
[Error] You\'re not logged in
');
                return;
            }
            container.append(html.loading('loading data...'));

            var kbws = new Workspace(this.runtime.getConfig('services.workspace.url'), {
                token: this.runtime.service('session').getAuthToken()
            });
            kbws.get_objects(
                [{ ref: self.options.ws + '/' + self.options.id }],
                function (data) {
                    container.empty();
                    // parse data
                    if (data.length === 0) {
                        //var msg = "[Error] Object "+self.options.id+" does not exist in workspace "+self.options.ws;

                        // We are moving away from "workspace"
                        var msg = '[Error] Object ' + self.options.id + ' can not be found';
                        container.append('

' + msg + '>/p>
');
                    } else {
                        var otus = data[0].data.otus,
                            rows = [],
                            o,
                            funcs,
                            f;
                        for (o = 0; o < otus.length; o += 1) {
                            funcs = otus[o].functions;
                            for (f = 0; f < funcs.length; f += 1) {
                                rows.push([
                                    funcs[f].reference_genes.join('
'),
                                    funcs[f].functional_role,
                                    funcs[f].abundance,
                                    funcs[f].confidence,
                                    otus[o].name
                                ]);
                            }
                        }

                        // container.append('

');
                        var options = {
                            columns: ['features', 'functional role', 'abundance', 'avg e-value', 'otu'],
                            rows: rows,
                            class: 'table table-striped'
                        };
                        var table = html.makeTable(options);
                        container.html(table);
                        $('#' + options.generated.id).dataTable();
                    }
                },
                function (data) {
                    container.empty();
                    var main = $('
');
                    main.append(
                        $('
')
                            .css({ padding: '10px 20px' })
                            .text('[Error] ' + data.error.message)
                    );
                    container.append(main);
                }
            );
            return self;
        },
        loggedInCallback: function (event, auth) {
            this.render();
            return this;
        },
        loggedOutCallback: function (event, auth) {
            this.render();
            return this;
        }
    });
});
<commit_msg>make usage of table in html() safer and mark so [UFI-16]<commit_after>/**
 * KBase widget to display table and boxplot of BIOM data
 */
define([
    'jquery',
    'kb_common/html',
    'kb_service/client/workspace',
    'lib/domUtils',

    'kbaseUI/widget/legacy/authenticatedWidget',
    'datatables_bootstrap'
], ($, html, Workspace, {domSafeText, domSafeValue}) => {
    $.KBWidget({
        name: 'AnnotationSetTable',
        parent: 'kbaseAuthenticatedWidget',
        version: '1.0.0',
        options: {
            id: null,
            ws: null
        },
        init(options) {
            this._super(options);
            return this;
        },
        render() {
            const self = this;
            const container = this.$elem;
            container.empty();
            if (!this.runtime.service('session').isLoggedIn()) {
                container.append('
[Error] You\'re not logged in
');
                return;
            }
            container.append(html.loading('loading data...'));

            const kbws = new Workspace(this.runtime.getConfig('services.workspace.url'), {
                token: this.runtime.service('session').getAuthToken()
            });
            kbws.get_objects(
                [{ref: `${self.options.ws  }/${  self.options.id}`}],
                (data) => {
                    container.empty();
                    // parse data
                    if (data.length === 0) {
                        //var msg = "[Error] Object "+self.options.id+" does not exist in workspace "+self.options.ws;

                        // We are moving away from "workspace"
                        const msg = `[Error] Object ${  self.options.id  } can not be found`;
                        container.append(`<div><p>${  msg  }>/p></div>`);
                    } else {
                        const otus = data[0].data.otus;
                        const rows = [];
                        let o,
                            funcs,
                            f;
                        for (o = 0; o < otus.length; o += 1) {
                            funcs = otus[o].functions;
                            for (f = 0; f < funcs.length; f += 1) {
                                rows.push([
                                    funcs[f].reference_genes.map((value) => {return domSafeValue(value);}).join('
'),
                                    domSafeValue(funcs[f].functional_role),
                                    domSafeValue(funcs[f].abundance),
                                    domSafeValue(funcs[f].confidence),
                                    domSafeText(otus[o].name)
                                ]);
                            }
                        }

                        // container.append('

');
                        const options = {
                            columns: ['features', 'functional role', 'abundance', 'avg e-value', 'otu'],
                            rows,
                            class: 'table table-striped'
                        };
                        const table = html.makeTable(options);
                        // safe useage of html(), as determined by the table created above
                        container.html(table);
                        $(`#${  options.generated.id}`).dataTable();
                    }
                },
                (data) => {
                    container.empty();
                    const main = $('
');
                    main.append(
                        $('
')
                            .css({padding: '10px 20px'})
                            .text(`[Error] ${  data.error.message}`)
                    );
                    container.append(main);
                }
            );
            return self;
        },
        loggedInCallback() {
            this.render();
            return this;
        },
        loggedOutCallback() {
            this.render();
            return this;
        }
    });
});
<|endoftext|>


<commit_before>/*jshint globalstrict: true*/
'use strict';
(function(window, idbModules){
    if (typeof window.openDatabase !== "undefined") {
        window.shimIndexedDB = idbModules.shimIndexedDB;
        if (window.shimIndexedDB) {
            window.shimIndexedDB.__useShim = function(){
                window.indexedDB = idbModules.shimIndexedDB;
                window.IDBDatabase = idbModules.IDBDatabase;
                window.IDBTransaction = idbModules.IDBTransaction;
                window.IDBCursor = idbModules.IDBCursor;
                window.IDBKeyRange = idbModules.IDBKeyRange;
                // On some browsers the assignment fails, overwrite with the defineProperty method
                if (window.indexedDB !== idbModules.shimIndexedDB && Object.defineProperty) {
                    Object.defineProperty(window, 'indexedDB', {
                        value: idbModules.shimIndexedDB
                    });
                }
            };
            window.shimIndexedDB.__debug = function(val){
                idbModules.DEBUG = val;
            };
        }
    }

    /*
    prevent error in Firefox
    */
    if(!('indexedDB' in window)) {
        window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.oIndexedDB || window.msIndexedDB;
    }

    if (typeof window.indexedDB === "undefined" && typeof window.openDatabase !== "undefined") {
        window.shimIndexedDB.__useShim();
    }
    else {
        window.IDBDatabase = window.IDBDatabase || window.webkitIDBDatabase;
        window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
        window.IDBCursor = window.IDBCursor || window.webkitIDBCursor;
        window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
        if(!window.IDBTransaction){
            window.IDBTransaction = {};
        }
        window.IDBTransaction.READ_ONLY = window.IDBTransaction.READ_ONLY || "readonly";
        window.IDBTransaction.READ_WRITE = window.IDBTransaction.READ_WRITE || "readwrite";
    }

}(window, idbModules));

<commit_msg>Added Android pre-4.4 shimming.<commit_after>/*jshint globalstrict: true*/
'use strict';
(function(window, idbModules){
    if (typeof window.openDatabase !== "undefined") {
        window.shimIndexedDB = idbModules.shimIndexedDB;
        if (window.shimIndexedDB) {
            window.shimIndexedDB.__useShim = function(){
                window.indexedDB = idbModules.shimIndexedDB;
                window.IDBDatabase = idbModules.IDBDatabase;
                window.IDBTransaction = idbModules.IDBTransaction;
                window.IDBCursor = idbModules.IDBCursor;
                window.IDBKeyRange = idbModules.IDBKeyRange;
                // On some browsers the assignment fails, overwrite with the defineProperty method
                if (window.indexedDB !== idbModules.shimIndexedDB && Object.defineProperty) {
                    Object.defineProperty(window, 'indexedDB', {
                        value: idbModules.shimIndexedDB
                    });
                }
            };
            window.shimIndexedDB.__debug = function(val){
                idbModules.DEBUG = val;
            };
        }
    }

    /*
    prevent error in Firefox
    */
    if(!('indexedDB' in window)) {
        window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.oIndexedDB || window.msIndexedDB;
    }

    /*
    detect browsers with known IndexedDb issues (e.g. Android pre-4.4)
    */
    var poorIndexedDbSupport = false;
    if (navigator.userAgent.match(/Android 2/) || navigator.userAgent.match(/Android 3/) || navigator.userAgent.match(/Android 4\.[0-3]/)) {
        /* Chrome is an exception. It supports IndexedDb */
        if (!navigator.userAgent.match(/Chrome/)) {
            poorIndexedDbSupport = true;
        }
    }

    if ((typeof window.indexedDB === "undefined" || poorIndexedDbSupport) && typeof window.openDatabase !== "undefined") {
        window.shimIndexedDB.__useShim();
    }
    else {
        window.IDBDatabase = window.IDBDatabase || window.webkitIDBDatabase;
        window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
        window.IDBCursor = window.IDBCursor || window.webkitIDBCursor;
        window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
        if(!window.IDBTransaction){
            window.IDBTransaction = {};
        }
        window.IDBTransaction.READ_ONLY = window.IDBTransaction.READ_ONLY || "readonly";
        window.IDBTransaction.READ_WRITE = window.IDBTransaction.READ_WRITE || "readwrite";
    }

}(window, idbModules));

<|endoftext|>


<commit_before>const getGmailLocationToInject = () => {
  // where we want to put the search quick links
  // this has be be defined after the page loads and becomes ready
  return document.querySelector('div.wT')
}

const gmailAccountName = () =>
  document
    .querySelector('a[class="gb_y gb_Ea gb_f"]')
    .attributes['aria-label'].nodeValue.match(/\(([^)]+)\)/)[1]

//inside gmail controls container - contains labels such as inbox/starred/drafts/etc
const labelControlsContainer = () =>
  document.getElementsByClassName('ajl aib aZ6')[0]

const widgetMainPanel = () => document.querySelector('div.akc.aZ6')

const widgetInsidePanel = () => document.querySelector('div.T0.pp.saH2Ef')

const gmailSideBar = () => document.querySelector('div.nH.oy8Mbf.nn.aeN')

const gmailHoverSideBar = () =>
  document.querySelector('div.nH.oy8Mbf.nn.aeN.bhZ.bym')

const quickLinksContainer = () =>
  document.querySelector('#gmailQuickLinksContainer')

export {
  gmailSideBar,
  gmailHoverSideBar,
  getGmailLocationToInject,
  gmailAccountName,
  widgetInsidePanel,
  labelControlsContainer,
  quickLinksContainer
}
<commit_msg>add robust gmail account detector instead of using class style due to constant gmail style changes<commit_after>const getGmailLocationToInject = () => {
  // where we want to put the search quick links
  // this has be be defined after the page loads and becomes ready
  return document.querySelector('div.wT')
}

const gmailAccountName = () =>
  Array.from(document.querySelectorAll('a[aria-label]'))
    .map(n => n.attributes['aria-label'].nodeValue)
    .find(t => /\(.+@.+\)/.test(t))
    .match(/\((.+@.+)\)/)[1]

//inside gmail controls container - contains labels such as inbox/starred/drafts/etc
const labelControlsContainer = () =>
  document.getElementsByClassName('ajl aib aZ6')[0]

const widgetMainPanel = () => document.querySelector('div.akc.aZ6')

const widgetInsidePanel = () => document.querySelector('div.T0.pp.saH2Ef')

const gmailSideBar = () => document.querySelector('div.nH.oy8Mbf.nn.aeN')

const gmailHoverSideBar = () =>
  document.querySelector('div.nH.oy8Mbf.nn.aeN.bhZ.bym')

const quickLinksContainer = () =>
  document.querySelector('#gmailQuickLinksContainer')

export {
  gmailSideBar,
  gmailHoverSideBar,
  getGmailLocationToInject,
  gmailAccountName,
  widgetInsidePanel,
  labelControlsContainer,
  quickLinksContainer
}
<|endoftext|>


<commit_before>import React from 'react';
import _ from 'lodash';

const axisTickOptions = [
  1000000,
  500000,
  200000,
  100000,
  50000,
  20000,
  10000,
  5000,
  2000,
  1000,
  500,
  200,
  100,
  50,
  20,
  10,
  5,
  2,
  1,
  0.1,
  0.01,
  0.001,
  0.0001
];

const getTickSize = (distance) => {
  const tickSize = axisTickOptions.find(tick => tick * 2 <= distance);
  return tickSize ? tickSize : 0.0001;
};

const calculateTicks = (min, max, minVal, maxVal) => {
  const dVal = maxVal - minVal;
  const d = max - min;
  const tickSize = getTickSize(dVal);
  const firstTick = Math.ceil(minVal / tickSize) * tickSize;
  const tickVals = _.range(firstTick, maxVal, tickSize);
  const valToCoord = val => (val - minVal) * (d / dVal) + min;
  return tickVals.map(val => ({
    val: val,
    coord: valToCoord(val)
  }));
};

export const YAxis = ({x, width, yMin, yMax, yMinVal, yMaxVal}) => {
  const ticks = calculateTicks(yMin, yMax, yMinVal, yMaxVal);
  const tickElements = ticks.map(({val, coord}) => (
    <g key={val}>
      <line x1={x - width * 0.5} y1={coord} x2={x + width * 0.5} y2={coord} />
      <text x={x} y={coord} fontSize="10">
        {val}
      </text>
    </g>
  ));

  return <g stroke="black" fill="black" strokeWidth="0.5">
    <line x1={x} y1={yMin} x2={x} y2={yMax} />
      {tickElements}
  </g>
};

export const XAxis = ({y, width, xMin, xMax, xMinVal, xMaxVal}) => {
  const ticks = calculateTicks(xMin, xMax, xMinVal, xMaxVal);
  const tickElements = ticks.map(({val, coord}) => (
    <g key={val}>
      <line x1={coord} y1={y - width * 0.5} x2={coord} y2={y + width * 0.5} />
      <text x={coord} y={y + 10} fontSize="10">
        {val}
      </text>
    </g>
  ));

  return <g stroke="black" fill="black" strokeWidth="0.5">
    <line x1={xMin} y1={y} x2={xMax} y2={y} />
      {tickElements}
  </g>
};
<commit_msg>Tweak axis tick marks<commit_after>import React from 'react';
import _ from 'lodash';

const axisTickOptions = [
  1000000,
  500000,
  200000,
  100000,
  50000,
  20000,
  10000,
  5000,
  2000,
  1000,
  500,
  200,
  100,
  50,
  20,
  10,
  5,
  2,
  1,
  0.5,
  0.2,
  0.1
];

const getTickSize = (distance) => {
  const tickSize = axisTickOptions.find(tick => tick * 2 <= distance);
  return tickSize ? tickSize : 0.05;
};

const calculateTicks = (min, max, minVal, maxVal) => {
  const dVal = maxVal - minVal;
  const d = max - min;
  const tickSize = getTickSize(dVal);
  const firstTick = Math.ceil(minVal / tickSize) * tickSize;
  const tickVals = _.range(firstTick, maxVal, tickSize);
  const valToCoord = val => (val - minVal) * (d / dVal) + min;
  return tickVals.map(val => ({
    val: val,
    coord: valToCoord(val)
  }));
};

export const YAxis = ({x, width, yMin, yMax, yMinVal, yMaxVal}) => {
  const ticks = calculateTicks(yMin, yMax, yMinVal, yMaxVal);
  const tickElements = ticks.map(({val, coord}) => (
    <g key={val}>
      <line x1={x - width * 0.5} y1={coord} x2={x + width * 0.5} y2={coord} />
      <text x={x} y={coord} fontSize="10">
        {val}
      </text>
    </g>
  ));

  return <g stroke="black" fill="black" strokeWidth="0.5">
    <line x1={x} y1={yMin} x2={x} y2={yMax} />
      {tickElements}
  </g>
};

export const XAxis = ({y, width, xMin, xMax, xMinVal, xMaxVal}) => {
  const ticks = calculateTicks(xMin, xMax, xMinVal, xMaxVal);
  const tickElements = ticks.map(({val, coord}) => (
    <g key={val}>
      <line x1={coord} y1={y - width * 0.5} x2={coord} y2={y + width * 0.5} />
      <text x={coord} y={y + 10} fontSize="10">
        {val}
      </text>
    </g>
  ));

  return <g stroke="black" fill="black" strokeWidth="0.5">
    <line x1={xMin} y1={y} x2={xMax} y2={y} />
      {tickElements}
  </g>
};
<|endoftext|>


<commit_before>;(function($, window, document) {
    'use strict';

    var $document = $(document);

    /**
     * Rounds the given value to the chosen base.
     *
     * Example: 5.46 with a base of 0.5 will round to 5.5
     *
     * @param value
     * @param base
     * @param method | round / floor / ceil
     * @returns {number}
     */
    function round(value, base, method) {
        var rounding = method || 'round',
            b = base || 1,
            factor = 1 / b;

        return Math[rounding](value * factor) / factor;
    }

    /**
     * Rounds an integer to the next 5er brake
     * based on the sum of digits.
     *
     * @param value
     * @param method
     * @returns {number}
     */
    function roundPretty(value, method) {
        var rounding = method || 'round',
            digits = countDigits(value),
            step = (digits > 1) ? 2 : 1,
            base = 5 * Math.pow(10, digits - step);

        return round(value, base, rounding);
    }

    /**
     * Get the sum of digits before the comma of a number.
     *
     * @param value
     * @returns {number}
     */
    function countDigits(value) {
        return ~~(Math.log(Math.floor(value)) / Math.LN10 + 1);
    }

    /**
     * Clamps a number between a min and a max value.
     *
     * @param value
     * @param min
     * @param max
     * @returns {number}
     */
    function clamp(value, min, max) {
        return Math.max(min, Math.min(max, value));
    }

    /**
     * Converts a value to an integer.
     *
     * @param value
     * @returns {Number}
     */
    function int(value) {
        return parseFloat(value);
    }

    $.plugin('rangeSlider', {

        defaults: {
            /**
             * The css class for the range slider container element.
             */
            sliderContainerCls: 'range-slider--container',

            /**
             * The css class for the range bar element.
             */
            rangeBarCls: 'range-slider--range-bar',

            /**
             * The css class for the handle elements at the start and end of the range bar.
             */
            handleCls: 'range-slider--handle',

            /**
             * The css class for the handle element at the min position.
             */
            handleMinCls: 'is--min',

            /**
             * The css class for the handle element at the max position.
             */
            handleMaxCls: 'is--max',

            /**
             * The css class for active handle elements which get dragged.
             */
            activeDraggingCls: 'is--dragging',

            /**
             * The selector for the hidden input field which holds the min value.
             */
            minInputElSelector: '*[data-range-input="min"]',

            /**
             * The selector for the hidden input field which holds the max value.
             */
            maxInputElSelector: '*[data-range-input="max"]',

            /**
             * The selector for the label which displays the min value.
             */
            minLabelElSelector: '*[data-range-label="min"]',

            /**
             * The selector for the label which displays the max value.
             */
            maxLabelElSelector: '*[data-range-label="max"]',

            /**
             * An example string for the format of the value label.
             */
            labelFormat: '',

            /**
             * Turn pretty rounding for cleaner steps on and off.
             */
            roundPretty: false,

            /**
             * The min value which the slider should show on start.
             */
            startMin: 20,

            /**
             * The max value which the slider should show on start.
             */
            startMax: 80,

            /**
             * The minimal value you can slide to.
             */
            rangeMin: 0,

            /**
             * The maximum value you can slide to.
             */
            rangeMax: 100,

            /**
             * The number of steps the slider is divided in.
             */
            stepCount: 20
        },

        init: function() {
            var me = this;

            me.applyDataAttributes();

            me.$minInputEl = me.$el.find(me.opts.minInputElSelector);
            me.$maxInputEl = me.$el.find(me.opts.maxInputElSelector);

            me.$minLabel = me.$el.find(me.opts.minLabelElSelector);
            me.$maxLabel = me.$el.find(me.opts.maxLabelElSelector);

            me.dragState = false;
            me.dragType = 'min';

            me.createSliderTemplate();

            me.computeBaseValues();
            me.registerEvents();
        },

        registerEvents: function() {
            var me = this;

            me._on(me.$minHandle, 'mousedown touchstart', $.proxy(me.onStartDrag, me, 'min', me.$minHandle));
            me._on(me.$maxHandle, 'mousedown touchstart', $.proxy(me.onStartDrag, me, 'max', me.$maxHandle));

            me._on($document, 'mouseup touchend', $.proxy(me.onEndDrag, me));
            me._on($document, 'mousemove touchmove', $.proxy(me.slide, me));
        },

        createSliderTemplate: function() {
            var me = this;

            me.$rangeBar = me.createRangeBar();
            me.$container = me.createRangeContainer();

            me.$minHandle = me.createHandle('min');
            me.$maxHandle = me.createHandle('max');

            me.$minHandle.appendTo(me.$rangeBar);
            me.$maxHandle.appendTo(me.$rangeBar);
            me.$rangeBar.appendTo(me.$container);
            me.$container.prependTo(me.$el);
        },

        createRangeContainer: function() {
            var me = this;

            return $('<div>', {
                'class': me.opts.sliderContainerCls
            });
        },

        createRangeBar: function() {
            var me = this;

            return $('<div>', {
                'class': me.opts.rangeBarCls
            });
        },

        createHandle: function(type) {
            var me = this,
                typeClass = (type == 'max') ? me.opts.handleMaxCls : me.opts.handleMinCls;

            return $('<div>', {
                'class': me.opts.handleCls + ' ' + typeClass
            });
        },

        computeBaseValues: function() {
            var me = this;

            me.minRange = int(me.opts.rangeMin);
            me.maxRange = int(me.opts.rangeMax);

            if (me.opts.roundPretty) {
                me.minRange = roundPretty(me.minRange, 'floor');
                me.maxRange = roundPretty(me.maxRange, 'ceil');
            }

            me.range = me.maxRange - me.minRange;
            me.stepSize = me.range / int(me.opts.stepCount);
            me.stepWidth = 100 / int(me.opts.stepCount);

            me.minValue = (me.opts.startMin == me.opts.rangeMin || me.opts.startMin <= me.minRange) ? me.minRange : int(me.opts.startMin);
            me.maxValue = (me.opts.startMax == me.opts.rangeMax || me.opts.startMax >= me.maxRange) ? me.maxRange : int(me.opts.startMax);

            me.setRangeBarPosition(me.minValue, me.maxValue);
            me.updateLayout();
        },

        setRangeBarPosition: function(minValue, maxValue) {
            var me = this,
                min = minValue || me.minValue,
                max = maxValue || me.maxValue,
                left = 100 / me.range * (min - me.minRange),
                width = 100 / me.range * (max - min);

            me.$rangeBar.css({
                'left': left + '%',
                'width': width + '%'
            });
        },

        getMin: function() {
            return this.minValue;
        },

        getMax: function() {
            return this.maxValue;
        },

        setMin: function(min, updateInput) {
            var me = this,
                update = updateInput || false;

            me.minValue = min;

            if (update) {
                me.updateMinInput(min);
            }

            me.setRangeBarPosition();
            me.updateLayout();

            $.publish('plugin/rangeSlider/changeMin', min);
        },

        setMax: function(max, updateInput) {
            var me = this,
                update = updateInput || false;

            me.maxValue = max;

            if (update) {
                me.updateMaxInput(max);
            }

            me.setRangeBarPosition();
            me.updateLayout();

            $.publish('plugin/rangeSlider/changeMax', max);
        },

        reset: function(param) {
            var me = this;

            if (param == 'max') {
                me.maxValue = me.maxRange;
                me.$maxInputEl.attr('disabled', 'disabled')
                    .val(me.maxRange)
                    .trigger('change');
            } else {
                me.minValue = me.minRange;
                me.$minInputEl.attr('disabled', 'disabled')
                    .val(me.minRange)
                    .trigger('change');
            }

            me.setRangeBarPosition();
            me.updateLayout();

            $.publish('plugin/rangeSlider/reset');
        },

        onStartDrag: function(type, $handle) {
            var me = this;

            $handle.addClass(me.opts.activeDraggingCls);

            me.dragState = true;
            me.dragType = type;
        },

        onEndDrag: function() {
            var me = this;

            if (me.dragState) {
                me.dragState = false;

                me.updateLayout();

                me.$minHandle.removeClass(me.opts.activeDraggingCls);
                me.$maxHandle.removeClass(me.opts.activeDraggingCls);

                if (me.dragType == 'max') {
                    me.updateMaxInput(me.maxValue);
                } else {
                    me.updateMinInput(me.minValue);
                }

                $(me).trigger('rangeChange', me);

                $.publish('plugin/rangeSlider/onChange', me);
            }
        },

        slide: function(event) {
            var me = this;

            if (me.dragState) {
               var pageX = (event.originalEvent.touches) ? event.originalEvent.touches[0].pageX : event.pageX,
                   offset = me.$container.offset(),
                   width = me.$container.innerWidth(),
                   mouseX = pageX - offset.left,
                   xPercent = clamp(round((100 / width * mouseX), me.stepWidth, 'round'), 0, 100),
                   value = (me.range / 100 * xPercent) + me.minRange;

               event.preventDefault();

               if (me.dragType == 'max') {
                   me.setMax(clamp(value, me.minValue + me.stepSize * 2, me.maxRange));
               } else {
                   me.setMin(clamp(value, me.minRange, me.maxValue - me.stepSize * 2));
               }
            }
        },

        updateMinInput: function(value) {
            var me = this;

            if (me.$minInputEl.length) {
                me.$minInputEl.val(value.toFixed(2))
                    .removeAttr('disabled')
                    .trigger('change');
            }
        },

        updateMaxInput: function(value) {
            var me = this;

            if (me.$maxInputEl.length) {
                me.$maxInputEl.val(value.toFixed(2))
                    .removeAttr('disabled')
                    .trigger('change');
            }
        },

        updateMinLabel: function(value) {
            var me = this;

            if (me.$minLabel.length) {
                me.$minLabel.html(me.formatValue(value));
            }
        },

        updateMaxLabel: function(value) {
            var me = this;

            if (me.$maxLabel.length) {
                me.$maxLabel.html(me.formatValue(value));
            }
        },

        updateLayout: function(minValue, maxValue) {
            var me = this,
                min = minValue || me.minValue,
                max = maxValue || me.maxValue;

            me.updateMinLabel(min);
            me.updateMaxLabel(max);
        },

        formatValue: function(value) {
            var me = this;

            if (!me.opts.labelFormat.length) {
                return value.toFixed(2);
            }

            value = Math.round(value * 100) / 100;
            value = value.toFixed(2);

            if (me.opts.labelFormat.indexOf('0.00') > 0) {
                value = me.opts.labelFormat.replace('0.00', value);
            } else {
                value = value.replace('.', ',');
                value = me.opts.labelFormat.replace('0,00', value);
            }

            return value;
        },

        destroy: function() {
            var me = this;

            me._destroy();
        }
    });
})(jQuery, window, document);<commit_msg>SW-10709 - fixed slider max range<commit_after>;(function($, window, document) {
    'use strict';

    var $document = $(document);

    /**
     * Rounds the given value to the chosen base.
     *
     * Example: 5.46 with a base of 0.5 will round to 5.5
     *
     * @param value
     * @param base
     * @param method | round / floor / ceil
     * @returns {number}
     */
    function round(value, base, method) {
        var rounding = method || 'round',
            b = base || 1,
            factor = 1 / b;

        return Math[rounding](value * factor) / factor;
    }

    /**
     * Rounds an integer to the next 5er brake
     * based on the sum of digits.
     *
     * @param value
     * @param method
     * @returns {number}
     */
    function roundPretty(value, method) {
        var rounding = method || 'round',
            digits = countDigits(value),
            step = (digits > 1) ? 2 : 1,
            base = 5 * Math.pow(10, digits - step);

        return round(value, base, rounding);
    }

    /**
     * Get the sum of digits before the comma of a number.
     *
     * @param value
     * @returns {number}
     */
    function countDigits(value) {
        return ~~(Math.log(Math.floor(value)) / Math.LN10 + 1);
    }

    /**
     * Clamps a number between a min and a max value.
     *
     * @param value
     * @param min
     * @param max
     * @returns {number}
     */
    function clamp(value, min, max) {
        return Math.max(min, Math.min(max, value));
    }

    /**
     * Converts a value to an integer.
     *
     * @param value
     * @returns {Number}
     */
    function int(value) {
        return parseFloat(value);
    }

    $.plugin('rangeSlider', {

        defaults: {
            /**
             * The css class for the range slider container element.
             */
            sliderContainerCls: 'range-slider--container',

            /**
             * The css class for the range bar element.
             */
            rangeBarCls: 'range-slider--range-bar',

            /**
             * The css class for the handle elements at the start and end of the range bar.
             */
            handleCls: 'range-slider--handle',

            /**
             * The css class for the handle element at the min position.
             */
            handleMinCls: 'is--min',

            /**
             * The css class for the handle element at the max position.
             */
            handleMaxCls: 'is--max',

            /**
             * The css class for active handle elements which get dragged.
             */
            activeDraggingCls: 'is--dragging',

            /**
             * The selector for the hidden input field which holds the min value.
             */
            minInputElSelector: '*[data-range-input="min"]',

            /**
             * The selector for the hidden input field which holds the max value.
             */
            maxInputElSelector: '*[data-range-input="max"]',

            /**
             * The selector for the label which displays the min value.
             */
            minLabelElSelector: '*[data-range-label="min"]',

            /**
             * The selector for the label which displays the max value.
             */
            maxLabelElSelector: '*[data-range-label="max"]',

            /**
             * An example string for the format of the value label.
             */
            labelFormat: '',

            /**
             * Turn pretty rounding for cleaner steps on and off.
             */
            roundPretty: false,

            /**
             * The min value which the slider should show on start.
             */
            startMin: 20,

            /**
             * The max value which the slider should show on start.
             */
            startMax: 80,

            /**
             * The minimal value you can slide to.
             */
            rangeMin: 0,

            /**
             * The maximum value you can slide to.
             */
            rangeMax: 100,

            /**
             * The number of steps the slider is divided in.
             */
            stepCount: 20
        },

        init: function() {
            var me = this;

            me.applyDataAttributes();

            me.$minInputEl = me.$el.find(me.opts.minInputElSelector);
            me.$maxInputEl = me.$el.find(me.opts.maxInputElSelector);

            me.$minLabel = me.$el.find(me.opts.minLabelElSelector);
            me.$maxLabel = me.$el.find(me.opts.maxLabelElSelector);

            me.dragState = false;
            me.dragType = 'min';

            me.createSliderTemplate();

            me.computeBaseValues();
            me.registerEvents();
        },

        registerEvents: function() {
            var me = this;

            me._on(me.$minHandle, 'mousedown touchstart', $.proxy(me.onStartDrag, me, 'min', me.$minHandle));
            me._on(me.$maxHandle, 'mousedown touchstart', $.proxy(me.onStartDrag, me, 'max', me.$maxHandle));

            me._on($document, 'mouseup touchend', $.proxy(me.onEndDrag, me));
            me._on($document, 'mousemove touchmove', $.proxy(me.slide, me));
        },

        createSliderTemplate: function() {
            var me = this;

            me.$rangeBar = me.createRangeBar();
            me.$container = me.createRangeContainer();

            me.$minHandle = me.createHandle('min');
            me.$maxHandle = me.createHandle('max');

            me.$minHandle.appendTo(me.$rangeBar);
            me.$maxHandle.appendTo(me.$rangeBar);
            me.$rangeBar.appendTo(me.$container);
            me.$container.prependTo(me.$el);
        },

        createRangeContainer: function() {
            var me = this;

            return $('<div>', {
                'class': me.opts.sliderContainerCls
            });
        },

        createRangeBar: function() {
            var me = this;

            return $('<div>', {
                'class': me.opts.rangeBarCls
            });
        },

        createHandle: function(type) {
            var me = this,
                typeClass = (type == 'max') ? me.opts.handleMaxCls : me.opts.handleMinCls;

            return $('<div>', {
                'class': me.opts.handleCls + ' ' + typeClass
            });
        },

        computeBaseValues: function() {
            var me = this;

            me.minRange = int(me.opts.rangeMin);
            me.maxRange = int(me.opts.rangeMax);

            if (me.opts.roundPretty) {
                me.minRange = roundPretty(me.minRange, 'floor');
                me.maxRange = roundPretty(me.maxRange, 'ceil');
            }

            me.range = me.maxRange - me.minRange;
            me.stepSize = me.range / int(me.opts.stepCount);
            me.stepWidth = 100 / int(me.opts.stepCount);

            if (me.maxValue == me.minValue) {
                me.maxValue = me.rangeMax;
            }

            me.minValue = (me.opts.startMin == me.opts.rangeMin || me.opts.startMin <= me.minRange) ? me.minRange : int(me.opts.startMin);
            me.maxValue = (me.opts.startMax == me.opts.rangeMax || me.opts.startMax >= me.maxRange) ? me.maxRange : int(me.opts.startMax);

            me.setRangeBarPosition(me.minValue, me.maxValue);
            me.updateLayout();
        },

        setRangeBarPosition: function(minValue, maxValue) {
            var me = this,
                min = minValue || me.minValue,
                max = maxValue || me.maxValue,
                left = 100 / me.range * (min - me.minRange),
                width = 100 / me.range * (max - min);

            me.$rangeBar.css({
                'left': left + '%',
                'width': width + '%'
            });
        },

        getMin: function() {
            return this.minValue;
        },

        getMax: function() {
            return this.maxValue;
        },

        setMin: function(min, updateInput) {
            var me = this,
                update = updateInput || false;

            me.minValue = min;

            if (update) {
                me.updateMinInput(min);
            }

            me.setRangeBarPosition();
            me.updateLayout();

            $.publish('plugin/rangeSlider/changeMin', min);
        },

        setMax: function(max, updateInput) {
            var me = this,
                update = updateInput || false;

            me.maxValue = max;

            if (update) {
                me.updateMaxInput(max);
            }

            me.setRangeBarPosition();
            me.updateLayout();

            $.publish('plugin/rangeSlider/changeMax', max);
        },

        reset: function(param) {
            var me = this;

            if (param == 'max') {
                me.maxValue = me.maxRange;
                me.$maxInputEl.attr('disabled', 'disabled')
                    .val(me.maxRange)
                    .trigger('change');
            } else {
                me.minValue = me.minRange;
                me.$minInputEl.attr('disabled', 'disabled')
                    .val(me.minRange)
                    .trigger('change');
            }

            me.setRangeBarPosition();
            me.updateLayout();

            $.publish('plugin/rangeSlider/reset');
        },

        onStartDrag: function(type, $handle) {
            var me = this;

            $handle.addClass(me.opts.activeDraggingCls);

            me.dragState = true;
            me.dragType = type;
        },

        onEndDrag: function() {
            var me = this;

            if (me.dragState) {
                me.dragState = false;

                me.updateLayout();

                me.$minHandle.removeClass(me.opts.activeDraggingCls);
                me.$maxHandle.removeClass(me.opts.activeDraggingCls);

                if (me.dragType == 'max') {
                    me.updateMaxInput(me.maxValue);
                } else {
                    me.updateMinInput(me.minValue);
                }

                $(me).trigger('rangeChange', me);

                $.publish('plugin/rangeSlider/onChange', me);
            }
        },

        slide: function(event) {
            var me = this;

            if (me.dragState) {
               var pageX = (event.originalEvent.touches) ? event.originalEvent.touches[0].pageX : event.pageX,
                   offset = me.$container.offset(),
                   width = me.$container.innerWidth(),
                   mouseX = pageX - offset.left,
                   xPercent = clamp(round((100 / width * mouseX), me.stepWidth, 'round'), 0, 100),
                   value = (me.range / 100 * xPercent) + me.minRange;

               event.preventDefault();

               if (me.dragType == 'max') {
                   me.setMax(clamp(value, me.minValue + me.stepSize * 2, me.maxRange));
               } else {
                   me.setMin(clamp(value, me.minRange, me.maxValue - me.stepSize * 2));
               }
            }
        },

        updateMinInput: function(value) {
            var me = this;

            if (me.$minInputEl.length) {
                me.$minInputEl.val(value.toFixed(2))
                    .removeAttr('disabled')
                    .trigger('change');
            }
        },

        updateMaxInput: function(value) {
            var me = this;

            if (me.$maxInputEl.length) {
                me.$maxInputEl.val(value.toFixed(2))
                    .removeAttr('disabled')
                    .trigger('change');
            }
        },

        updateMinLabel: function(value) {
            var me = this;

            if (me.$minLabel.length) {
                me.$minLabel.html(me.formatValue(value));
            }
        },

        updateMaxLabel: function(value) {
            var me = this;

            if (me.$maxLabel.length) {
                me.$maxLabel.html(me.formatValue(value));
            }
        },

        updateLayout: function(minValue, maxValue) {
            var me = this,
                min = minValue || me.minValue,
                max = maxValue || me.maxValue;

            me.updateMinLabel(min);
            me.updateMaxLabel(max);
        },

        formatValue: function(value) {
            var me = this;

            if (!me.opts.labelFormat.length) {
                return value.toFixed(2);
            }

            value = Math.round(value * 100) / 100;
            value = value.toFixed(2);

            if (me.opts.labelFormat.indexOf('0.00') > 0) {
                value = me.opts.labelFormat.replace('0.00', value);
            } else {
                value = value.replace('.', ',');
                value = me.opts.labelFormat.replace('0,00', value);
            }

            return value;
        },

        destroy: function() {
            var me = this;

            me._destroy();
        }
    });
})(jQuery, window, document);<|endoftext|>