<commit_before>/*
A view that displays notification (messages).

Currently a single notification is displayed as an Alert on top of the screen, each notification in a time.
*/

(function() {
  Bootstrap.NotificationsView = Ember.CollectionView.extend({
    classNames: ['notifications'],
    attributeBindings: ['style'],
    contentBinding: 'Bootstrap.NM.content',
    showTime: 2000,
    fadeInTime: 500,
    fadeOutTime: 3000,
    showTimeTimeoutId: null,
    /*
    itemViewClass: Bootstrap.BsAlertComponent.extend(
        messageBinding: 'content.message'
        typeBinding: 'content.type'
        fadeInTimeBinding: 'parentView.fadeInTime'
        isVisible: false

        didInsertElement: ->
            @$().fadeIn(@get('fadeInTime'))
    )
    */

    itemViewClass: Ember.View.extend({
      classNames: ['alert', 'notification'],
      template: Ember.Handlebars.compile('{{view.content.message}}'),
      classNameBindings: ["alertType"],
      isVisible: false,
      alertType: (function() {
        return this.get('content').get('classType');
      }).property('content'),
      didInsertElement: function() {
        return this.$().fadeIn(this.get('fadeInTime'));
      }
    }),
    contentChanged: (function() {
      if (this.get('content').length > 0) {
        return this.resetShowTime();
      }
    }).observes('content.length'),
    resetShowTime: function() {
      var _this = this;
      this.$().css({
        display: 'block'
      });
      if (this.$().is(":animated")) {
        this.$().stop().animate({
          opacity: "100"
        });
      }
      if (this.showTimeTimeoutId != null) {
        clearTimeout(this.showTimeTimeoutId);
      }
      return this.showTimeTimeoutId = setTimeout(function() {
        return _this.fadeOut(_this);
      }, this.showTime);
    },
    fadeOut: function(that) {
      return that.$().fadeOut(that.fadeOutTime, function() {
        return that.get('content').clear();
      });
    },
    mouseEnter: function() {
      if (this.$().is(":animated")) {
        return this.$().stop().animate({
          opacity: "100"
        });
      }
    },
    mouseLeave: function() {
      return this.resetShowTime();
    }
  });

  Ember.Handlebars.helper('bs-notifications', Bootstrap.NotificationsView);

  Bootstrap.NM = Bootstrap.NotificationManager = Ember.Object.create({
    content: Ember.A(),
    push: function(message, type) {
      var notif;
      type = type != null ? type : type = 'info';
      notif = Bootstrap.Notification.create({
        message: message,
        type: type
      });
      return this.get('content').pushObject(notif);
    }
  });

  /*
  This object represents a notification to be displayed.
  Notification(s) are added into the NotificationQueue by the pushNotification function.
  */

  Bootstrap.Notification = Ember.Object.extend({
    classType: (function() {
      if (this.type != null) {
        return "alert-" + this.type;
      } else {
        return null;
      }
    }).property('type').cacheable()
  });

}).call(this);
<commit_msg>Solve random problem on testing because of bs notifications<commit_after>/*
A view that displays notification (messages).

Currently a single notification is displayed as an Alert on top of the screen, each notification in a time.
*/

(function() {
  Bootstrap.NotificationsView = Ember.CollectionView.extend({
    classNames: ['notifications'],
    attributeBindings: ['style'],
    contentBinding: 'Bootstrap.NM.content',
    showTime: 2000,
    fadeInTime: 500,
    fadeOutTime: 3000,
    showTimeTimeoutId: null,
    /*
    itemViewClass: Bootstrap.BsAlertComponent.extend(
        messageBinding: 'content.message'
        typeBinding: 'content.type'
        fadeInTimeBinding: 'parentView.fadeInTime'
        isVisible: false

        didInsertElement: ->
            @$().fadeIn(@get('fadeInTime'))
    )
    */

    itemViewClass: Ember.View.extend({
      classNames: ['alert', 'notification'],
      template: Ember.Handlebars.compile('{{view.content.message}}'),
      classNameBindings: ["alertType"],
      isVisible: false,
      alertType: (function() {
        return this.get('content').get('classType');
      }).property('content'),
      didInsertElement: function() {
        return this.$().fadeIn(this.get('fadeInTime'));
      }
    }),
    contentChanged: (function() {
      if (this.get('content').length > 0) {
        //return this.resetShowTime();
      }
    }).observes('content.length'),
    resetShowTime: function() {
      var _this = this;
      this.$().css({
        display: 'block'
      });
      if (this.$().is(":animated")) {
        this.$().stop().animate({
          opacity: "100"
        });
      }
      if (this.showTimeTimeoutId != null) {
        clearTimeout(this.showTimeTimeoutId);
      }
      return this.showTimeTimeoutId = setTimeout(function() {
        return _this.fadeOut(_this);
      }, this.showTime);
    },
    fadeOut: function(that) {
      return that.$().fadeOut(that.fadeOutTime, function() {
        return that.get('content').clear();
      });
    },
    mouseEnter: function() {
      if (this.$().is(":animated")) {
        return this.$().stop().animate({
          opacity: "100"
        });
      }
    },
    mouseLeave: function() {
      return this.resetShowTime();
    }
  });

  Ember.Handlebars.helper('bs-notifications', Bootstrap.NotificationsView);

  Bootstrap.NM = Bootstrap.NotificationManager = Ember.Object.create({
    content: Ember.A(),
    push: function(message, type) {
      var notif;
      type = type != null ? type : type = 'info';
      notif = Bootstrap.Notification.create({
        message: message,
        type: type
      });
      return this.get('content').pushObject(notif);
    }
  });

  /*
  This object represents a notification to be displayed.
  Notification(s) are added into the NotificationQueue by the pushNotification function.
  */

  Bootstrap.Notification = Ember.Object.extend({
    classType: (function() {
      if (this.type != null) {
        return "alert-" + this.type;
      } else {
        return null;
      }
    }).property('type').cacheable()
  });

}).call(this);
<|endoftext|>


<commit_before>var DynmapProjection = L.Class.extend({
	initialize: function(options) {
		L.Util.setOptions(this, options);
	},
	fromLocationToLatLng: function(location) {
		throw "fromLocationToLatLng not implemented";
	},
	fromLatLngToLocation: function(location) {
		return null;
	}
});

if (!Array.prototype.indexOf) { // polyfill for IE < 9
	    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
	        "use strict";
	        if (this === void 0 || this === null) {
	            throw new TypeError();
	        }
	        var t = Object(this);
	        var len = t.length >>> 0;
	        if (len === 0) {
	            return -1;
	        }
	        var n = 0;
	        if (arguments.length > 0) {
	            n = Number(arguments[1]);
	            if (n !== n) { // shortcut for verifying if it's NaN
	                n = 0;
	            } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
	                n = (n > 0 || -1) * Math.floor(Math.abs(n));
	            }
	        }
	        if (n >= len) {
	            return -1;
	        }
	        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
	        for (; k < len; k++) {
	            if (k in t && t[k] === searchElement) {
	                return k;
	            }
	        }
	        return -1;
	    }
}

var DynmapLayerControl = L.Control.Layers.extend({
	getPosition: function() {
		return 'topleft';
	},

	// Function override to include pos
	addOverlay: function(layer, name, pos) {
		this._addLayer(layer, name, true, pos);
		this._update();
		return this;
	},

	// Function override to order layers by pos
	_addLayer: function (layer, name, overlay, pos) {
		var id = L.stamp(layer);

		this._layers[pos] = {
			layer: layer,
			name: name,
			overlay: overlay,
			id: id
		};

		if (this.options.autoZIndex && layer.setZIndex) {
			this._lastZIndex++;
			layer.setZIndex(this._lastZIndex);
		}
	},

	// Function override to convert the position-based ordering into the id-based ordering
	_onInputClick: function () {
		var i, input, obj,
		    inputs = this._form.getElementsByTagName('input'),
		    inputsLen = inputs.length,
		    baseLayer;

		this._handlingClick = true;

		// Convert ID to pos
		var id2pos = {};
		for (i in this._layers) {
			id2pos[this._layers[i].id] = i;
		}

		for (i = 0; i < inputsLen; i++) {
			input = inputs[i];
			obj = this._layers[id2pos[input.layerId]];

			if (input.checked && !this._map.hasLayer(obj.layer)) {
				this._map.addLayer(obj.layer);
				if (!obj.overlay) {
					baseLayer = obj.layer;
				}
			} else if (!input.checked && this._map.hasLayer(obj.layer)) {
				this._map.removeLayer(obj.layer);
			}
		}

		if (baseLayer) {
			this._map.setZoom(this._map.getZoom());
			this._map.fire('baselayerchange', {layer: baseLayer});
		}

		this._handlingClick = false;
	},
});

var DynmapTileLayer = L.TileLayer.extend({
	_namedTiles: {},
	_cachedTileUrls: {},
	_loadQueue: [],
	_loadingTiles: [],

	getTileUrl: function(coords) {
		var tileName = this.getTileName(coords),
			url = this._cachedTileUrls[tileName];

		if (!url) {
			this._cachedTileUrls[tileName] = url = this.options.dynmap.getTileUrl(tileName);
		}

		return url;
	},

	createTile: function(coords, done) {
		var me = this,
			tile = document.createElement('img');

  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
  			tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
  		}

  		tile.alt = '';
  		tile.setAttribute('role', 'presentation');

  		//Dynmap - Tile names
  		tile.tileName = this.getTileName(coords);
  		this._namedTiles[tile.tileName] = tile;

		tile.onload = function() {
			me._tileOnLoad(done, tile);

			//Dynmap - Update load queue
			me._loadingTiles.splice(me._loadingTiles.indexOf(tile), 1);
			me._tickLoadQueue();
		};

		tile.onerror = function() {
			me._tileOnError(done, tile);

			//Dynmap - Update load queue
			me._loadingTiles.splice(me._loadingTiles.indexOf(tile), 1);
			me._tickLoadQueue();
		};

		//Dynmap - Queue for loading
		tile.url = this.getTileUrl(coords);
		this._loadQueue.push(tile);
		this._tickLoadQueue();

		return tile;
	},

	_abortLoading: function() {
		var tile;

		for (var i in this._tiles) {
			if (!Object.prototype.hasOwnProperty.call(this._tiles, i)) {
				continue;
			}

			tile = this._tiles[i];

			//Dynmap - remove namedTiles entry
			if (tile.coords.z !== this._tileZoom) {
				if (tile.loaded && tile.el && tile.el.tileName) {
					delete this._namedTiles[tile.el.tileName];
				}

				if(this._loadQueue.indexOf(tile.el) > -1) {
					this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1);
				}

				if(this._loadingTiles.indexOf(tile.el) > -1) {
					this._loadingTiles.splice(this._loadingTiles.indexOf(tile.el), 1);
				}
			}
		}

		L.TileLayer.prototype._abortLoading.call(this);
	},

	_removeTile: function(key) {
		var tile = this._tiles[key];

		if (!tile) {
			return;
		}

		//Dynmap - remove namedTiles entry
		var tileName = tile.el.tileName;

		if (tileName) {
			delete this._namedTiles[tileName];
		}

		//Dynmap - remove from load queue
		if(this._loadingTiles.indexOf(tile.el) > -1) {
			this._loadingTiles.splice(this._loadingTiles.indexOf(tile.el), 1);
		}

		if(this._loadQueue.indexOf(tile.el) > -1) {
			this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1);
		}

		tile.el.onerror = null;
		tile.el.onload = null;

		L.TileLayer.prototype._removeTile.call(this, key);
	},

	getProjection: function() {
		return this.projection;
	},

	_tickLoadQueue: function() {
		if (this._loadingTiles.length > 4) {
			return;
		}

		var next = this._loadQueue.shift();

		if (!next) {
			return;
		}

		this._loadingTiles.push(next);
		next.src = next.url;
	},

	onTileUpdated: function(tile, tileName) {
		var src = this.dynmap.getTileUrl(tileName);
		tile.attr('src', src);
		tile.show();
	},

	getTileName: function(coords) {
		throw "getTileName not implemented";
	},

	updateNamedTile: function(name) {
		var tile = this._namedTiles[name];
		delete this._cachedTileUrls[name];
		if (tile) {
			this.updateTile(tile);
		}
	},

	updateTile: function(tile) {
		this._loadTile(tile, tile.tilePoint, this._map.getZoom());
	},

	// Some helper functions.
	zoomprefix: function(amount) {
		return 'zzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount);
	},

	getTileInfo: function(coords) {
		// zoom: max zoomed in = this.options.maxZoom, max zoomed out = 0
		// izoom: max zoomed in = 0, max zoomed out = this.options.maxZoom
		// zoomoutlevel: izoom < mapzoomin -> 0, else -> izoom - mapzoomin (which ranges from 0 till mapzoomout)
		var izoom = this._getZoomForUrl(),
			zoomoutlevel = Math.max(0, izoom - this.options.mapzoomin),
			scale = 1 << zoomoutlevel,
			x = scale * coords.x,
			y = scale * coords.y;

		return {
			prefix: this.options.prefix,
			nightday: (this.options.nightandday && this.options.dynmap.serverday) ? '_day' : '',
			scaledx: x >> 5,
			scaledy: y >> 5,
			zoom: this.zoomprefix(zoomoutlevel),
			zoomprefix: (zoomoutlevel==0)?"":(this.zoomprefix(zoomoutlevel)+"_"),
			x: x,
			y: y,
			fmt: this.options['image-format'] || 'png'
		};
	}
});

function loadjs(url, completed) {
	var script = document.createElement('script');
	script.setAttribute('src', url);
	script.setAttribute('type', 'text/javascript');
	var isloaded = false;
	script.onload = function() {
		if (isloaded) { return; }
		isloaded = true;
		completed();
	};

	// Hack for IE, don't know whether this still applies to IE9.
	script.onreadystatechange = function() {
		if (script.readyState == 'loaded' || script.readyState == 'complete')
			script.onload();
	};
	(document.head || document.getElementsByTagName('head')[0]).appendChild(script);
}

function loadcss(url, completed) {
	var link = document.createElement('link');
	link.setAttribute('href', url);
	link.setAttribute('rel', 'stylesheet');
	var isloaded = false;
	if (completed) {
		link.onload = function() {
			if (isloaded) { return; }
			isloaded = true;
			completed();
		};

		// Hack for IE, don't know whether this still applies to IE9.
		link.onreadystatechange = function() {
			link.onload();
		};
	}

	(document.head || document.getElementsByTagName('head')[0]).appendChild(link);
}

function splitArgs(s) {
	var r = s.split(' ');
	delete arguments[0];
	var obj = {};
	var index = 0;
	$.each(arguments, function(argumentIndex, argument) {
		if (!argumentIndex) { return; }
		var value = r[argumentIndex-1];
		obj[argument] = value;
	});
	return obj;
}

function swtch(value, options, defaultOption) {
	return (options[value] || defaultOption || function(){})(value);
}
(function( $ ){
	$.fn.scrollHeight = function(height) {
		return this[0].scrollHeight;
	};
})($);

function Location(world, x, y, z) {
	this.world = world;
	this.x = x;
	this.y = y;
	this.z = z;
}

function namedReplace(str, obj)
{
	var startIndex = 0;
	var result = '';
	while(true) {
		var variableBegin = str.indexOf('{', startIndex);
		var variableEnd = str.indexOf('}', variableBegin+1);
		if (variableBegin < 0 || variableEnd < 0) {
			result += str.substr(startIndex);
			break;
		}
		if (variableBegin < variableEnd) {
			var variableName = str.substring(variableBegin+1, variableEnd);
			result += str.substring(startIndex, variableBegin);
			result += obj[variableName];
		} else /* found '{}' */ {
			result += str.substring(startIndex, variableBegin-1);
			result += '';
		}
		startIndex = variableEnd+1;
	}
	return result;
}

function concatURL(base, addition) {
	if(base.indexOf('?') >= 0)
		return base + escape(addition);

	return base + addition;
}
<commit_msg>Fix layer control<commit_after>var DynmapProjection = L.Class.extend({
	initialize: function(options) {
		L.Util.setOptions(this, options);
	},
	fromLocationToLatLng: function(location) {
		throw "fromLocationToLatLng not implemented";
	},
	fromLatLngToLocation: function(location) {
		return null;
	}
});

if (!Array.prototype.indexOf) { // polyfill for IE < 9
	    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
	        "use strict";
	        if (this === void 0 || this === null) {
	            throw new TypeError();
	        }
	        var t = Object(this);
	        var len = t.length >>> 0;
	        if (len === 0) {
	            return -1;
	        }
	        var n = 0;
	        if (arguments.length > 0) {
	            n = Number(arguments[1]);
	            if (n !== n) { // shortcut for verifying if it's NaN
	                n = 0;
	            } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
	                n = (n > 0 || -1) * Math.floor(Math.abs(n));
	            }
	        }
	        if (n >= len) {
	            return -1;
	        }
	        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
	        for (; k < len; k++) {
	            if (k in t && t[k] === searchElement) {
	                return k;
	            }
	        }
	        return -1;
	    }
}

var DynmapLayerControl = L.Control.Layers.extend({
	getPosition: function() {
		return 'topleft';
	},

	// Function override to include pos
	addOverlay: function(layer, name, pos) {
		this._addLayer(layer, name, true, pos);
		this._update();
		return this;
	},

	// Function override to order layers by pos
	_addLayer: function (layer, name, overlay, pos) {
		var id = L.stamp(layer);

		this._layers[pos] = {
			layer: layer,
			name: name,
			overlay: overlay,
			id: id
		};

		if (this.options.autoZIndex && layer.setZIndex) {
			this._lastZIndex++;
			layer.setZIndex(this._lastZIndex);
		}
	}
});

var DynmapTileLayer = L.TileLayer.extend({
	_namedTiles: {},
	_cachedTileUrls: {},
	_loadQueue: [],
	_loadingTiles: [],

	getTileUrl: function(coords) {
		var tileName = this.getTileName(coords),
			url = this._cachedTileUrls[tileName];

		if (!url) {
			this._cachedTileUrls[tileName] = url = this.options.dynmap.getTileUrl(tileName);
		}

		return url;
	},

	createTile: function(coords, done) {
		var me = this,
			tile = document.createElement('img');

  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
  			tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
  		}

  		tile.alt = '';
  		tile.setAttribute('role', 'presentation');

  		//Dynmap - Tile names
  		tile.tileName = this.getTileName(coords);
  		this._namedTiles[tile.tileName] = tile;

		tile.onload = function() {
			me._tileOnLoad(done, tile);

			//Dynmap - Update load queue
			me._loadingTiles.splice(me._loadingTiles.indexOf(tile), 1);
			me._tickLoadQueue();
		};

		tile.onerror = function() {
			me._tileOnError(done, tile);

			//Dynmap - Update load queue
			me._loadingTiles.splice(me._loadingTiles.indexOf(tile), 1);
			me._tickLoadQueue();
		};

		//Dynmap - Queue for loading
		tile.url = this.getTileUrl(coords);
		this._loadQueue.push(tile);
		this._tickLoadQueue();

		return tile;
	},

	_abortLoading: function() {
		var tile;

		for (var i in this._tiles) {
			if (!Object.prototype.hasOwnProperty.call(this._tiles, i)) {
				continue;
			}

			tile = this._tiles[i];

			//Dynmap - remove namedTiles entry
			if (tile.coords.z !== this._tileZoom) {
				if (tile.loaded && tile.el && tile.el.tileName) {
					delete this._namedTiles[tile.el.tileName];
				}

				if(this._loadQueue.indexOf(tile.el) > -1) {
					this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1);
				}

				if(this._loadingTiles.indexOf(tile.el) > -1) {
					this._loadingTiles.splice(this._loadingTiles.indexOf(tile.el), 1);
				}
			}
		}

		L.TileLayer.prototype._abortLoading.call(this);
	},

	_removeTile: function(key) {
		var tile = this._tiles[key];

		if (!tile) {
			return;
		}

		//Dynmap - remove namedTiles entry
		var tileName = tile.el.tileName;

		if (tileName) {
			delete this._namedTiles[tileName];
		}

		//Dynmap - remove from load queue
		if(this._loadingTiles.indexOf(tile.el) > -1) {
			this._loadingTiles.splice(this._loadingTiles.indexOf(tile.el), 1);
		}

		if(this._loadQueue.indexOf(tile.el) > -1) {
			this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1);
		}

		tile.el.onerror = null;
		tile.el.onload = null;

		L.TileLayer.prototype._removeTile.call(this, key);
	},

	getProjection: function() {
		return this.projection;
	},

	_tickLoadQueue: function() {
		if (this._loadingTiles.length > 4) {
			return;
		}

		var next = this._loadQueue.shift();

		if (!next) {
			return;
		}

		this._loadingTiles.push(next);
		next.src = next.url;
	},

	onTileUpdated: function(tile, tileName) {
		var src = this.dynmap.getTileUrl(tileName);
		tile.attr('src', src);
		tile.show();
	},

	getTileName: function(coords) {
		throw "getTileName not implemented";
	},

	updateNamedTile: function(name) {
		var tile = this._namedTiles[name];
		delete this._cachedTileUrls[name];
		if (tile) {
			this.updateTile(tile);
		}
	},

	updateTile: function(tile) {
		this._loadTile(tile, tile.tilePoint, this._map.getZoom());
	},

	// Some helper functions.
	zoomprefix: function(amount) {
		return 'zzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount);
	},

	getTileInfo: function(coords) {
		// zoom: max zoomed in = this.options.maxZoom, max zoomed out = 0
		// izoom: max zoomed in = 0, max zoomed out = this.options.maxZoom
		// zoomoutlevel: izoom < mapzoomin -> 0, else -> izoom - mapzoomin (which ranges from 0 till mapzoomout)
		var izoom = this._getZoomForUrl(),
			zoomoutlevel = Math.max(0, izoom - this.options.mapzoomin),
			scale = 1 << zoomoutlevel,
			x = scale * coords.x,
			y = scale * coords.y;

		return {
			prefix: this.options.prefix,
			nightday: (this.options.nightandday && this.options.dynmap.serverday) ? '_day' : '',
			scaledx: x >> 5,
			scaledy: y >> 5,
			zoom: this.zoomprefix(zoomoutlevel),
			zoomprefix: (zoomoutlevel==0)?"":(this.zoomprefix(zoomoutlevel)+"_"),
			x: x,
			y: y,
			fmt: this.options['image-format'] || 'png'
		};
	}
});

function loadjs(url, completed) {
	var script = document.createElement('script');
	script.setAttribute('src', url);
	script.setAttribute('type', 'text/javascript');
	var isloaded = false;
	script.onload = function() {
		if (isloaded) { return; }
		isloaded = true;
		completed();
	};

	// Hack for IE, don't know whether this still applies to IE9.
	script.onreadystatechange = function() {
		if (script.readyState == 'loaded' || script.readyState == 'complete')
			script.onload();
	};
	(document.head || document.getElementsByTagName('head')[0]).appendChild(script);
}

function loadcss(url, completed) {
	var link = document.createElement('link');
	link.setAttribute('href', url);
	link.setAttribute('rel', 'stylesheet');
	var isloaded = false;
	if (completed) {
		link.onload = function() {
			if (isloaded) { return; }
			isloaded = true;
			completed();
		};

		// Hack for IE, don't know whether this still applies to IE9.
		link.onreadystatechange = function() {
			link.onload();
		};
	}

	(document.head || document.getElementsByTagName('head')[0]).appendChild(link);
}

function splitArgs(s) {
	var r = s.split(' ');
	delete arguments[0];
	var obj = {};
	var index = 0;
	$.each(arguments, function(argumentIndex, argument) {
		if (!argumentIndex) { return; }
		var value = r[argumentIndex-1];
		obj[argument] = value;
	});
	return obj;
}

function swtch(value, options, defaultOption) {
	return (options[value] || defaultOption || function(){})(value);
}
(function( $ ){
	$.fn.scrollHeight = function(height) {
		return this[0].scrollHeight;
	};
})($);

function Location(world, x, y, z) {
	this.world = world;
	this.x = x;
	this.y = y;
	this.z = z;
}

function namedReplace(str, obj)
{
	var startIndex = 0;
	var result = '';
	while(true) {
		var variableBegin = str.indexOf('{', startIndex);
		var variableEnd = str.indexOf('}', variableBegin+1);
		if (variableBegin < 0 || variableEnd < 0) {
			result += str.substr(startIndex);
			break;
		}
		if (variableBegin < variableEnd) {
			var variableName = str.substring(variableBegin+1, variableEnd);
			result += str.substring(startIndex, variableBegin);
			result += obj[variableName];
		} else /* found '{}' */ {
			result += str.substring(startIndex, variableBegin-1);
			result += '';
		}
		startIndex = variableEnd+1;
	}
	return result;
}

function concatURL(base, addition) {
	if(base.indexOf('?') >= 0)
		return base + escape(addition);

	return base + addition;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

"use strict";

jest.autoMockOff();

var source = [
  'var React = require("React");',
  'var PropTypes = React.PropTypes;',
  '/**',
  ' * Example component description',
  ' */',
  'var Component = React.createClass({',
  '  propTypes: {',
  '    /**',
  '     * Example prop description',
  '     */',
  '    foo: PropTypes.bool',
  '  },',
  '  getDefaultProps: function() {',
  '    return {',
  '      foo: true',
  '    };',
  '  }',
  '});',
  'module.exports = Component;'
].join('\n');

describe('main', () => {
  var utils;
  var docgen;

  beforeEach(() => {
    utils = require('../../tests/utils');
    docgen = require('../main');
  });

  it('parses with default resolver/handlers', () => {
    var docs = docgen.parse(source);
    expect(docs).toEqual({
      description: 'Example component description',
      props: {
        foo: {
          type: {
            name: 'bool'
          },
          defaultValue: {
            computed: false,
            value: 'true'
          },
          description: 'Example prop description',
          required: false
        }
      }
    });
  });

  it('parses with custom handlers', () => {
    var docs = docgen.parse(source, null, [
      docgen.handlers.componentDocblockHandler,
    ]);
    expect(docs).toEqual({
      description: 'Example component description',
      props: {}
    });
  });
});
<commit_msg>Extend main test with class definition<commit_after>/*
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

/*global jest, describe, beforeEach, it, expect*/

jest.autoMockOff();

describe('main', () => {
  var docgen;

  beforeEach(() => {
    docgen = require('../main');
  });

  function test(source) {
    it('parses with default resolver/handlers', () => {
      var docs = docgen.parse(source);
      expect(docs).toEqual({
        description: 'Example component description',
        props: {
          foo: {
            type: {
              name: 'bool',
            },
            defaultValue: {
              computed: false,
              value: 'true',
            },
            description: 'Example prop description',
            required: false,
          },
        },
      });
    });

    it('parses with custom handlers', () => {
      var docs = docgen.parse(source, null, [
        docgen.handlers.componentDocblockHandler,
      ]);
      expect(docs).toEqual({
        description: 'Example component description',
        props: {},
      });
    });
  }

  describe('React.createClass', () => {
    test(`
      var React = require("React");
      var PropTypes = React.PropTypes;
      /**
       * Example component description
       */
      var Component = React.createClass({
        propTypes: {
          /**
           * Example prop description
           */
          foo: PropTypes.bool
        },
        getDefaultProps: function() {
          return {
            foo: true
          };
        }
      });
      module.exports = Component
    `);
  });

  describe('Class definition', () => {
    test(`
      var React = require("React");
      var PropTypes = React.PropTypes;
      /**
       * Example component description
       */
      export default class Component extends React.Component {
        static propTypes = {
          /**
           * Example prop description
           */
          foo: PropTypes.bool
        };
        // ...
      }
      Component.defaultProps = {
        foo: true,
      };
    `);
  });

});
<|endoftext|>


<commit_before>(function(global) {
  global.S3MP = (function() {

    // Wrap this into underscore library extension
    _.mixin({
      findIndex : function (collection, filter) {
        for (var i = 0; i < collection.length; i++) {
          if (filter(collection[i], i, collection)) {
            return i;
          }
        }
        return -1;
      }
    });
// S3MP Constructor
function S3MP(options) {
  var files
    , progress_timer = []
    , S3MP = this;

  _.extend(this, options);
  this.headers = _.object(_.map(options.headers, function(v,k) { return ["x-amz-" + k.toLowerCase(), v] }));

  this.uploadList = [];

  // Handles all of the success/failure events, and
  // progress notifiers
  this.handler = {

    // Activate an appropriate number of parts (number = pipes)
    // when all of the parts have been successfully initialized
    beginUpload: function() {
      var i = [];
      function beginUpload(pipes, uploadObj) {
        var key = uploadObj.key
          , num_parts = uploadObj.parts.length;

        if (typeof i[key] === "undefined") {
          i[key] = 0;
        }

        i[key]++;

        for (var j=0; j<pipes; j++) {
          uploadObj.parts[j].activate();
        }
        S3MP.handler.startProgressTimer(key);
        S3MP.onStart(uploadObj); // This probably needs to go somewhere else.
      }
      return beginUpload;
    }(),

    // called when an upload is paused or the network connection cuts out
    onError: function(uploadObj, part) {
      S3MP.onError(uploadObj, part);
    },

    // called when a single part has successfully uploaded
    onPartSuccess: function(uploadObj, finished_part) {
      var parts, i, ETag;

      parts = uploadObj.parts;
      finished_part.status = "complete";

      // Append the ETag (in the response header) to the ETags array
      ETag = finished_part.xhr.getResponseHeader("ETag");
      uploadObj.Etags.push({ ETag: ETag.replace(/\"/g, ''), partNum: finished_part.num });

      // Increase the uploaded count and delete the finished part
      uploadObj.uploaded += finished_part.size;
      uploadObj.inprogress[finished_part.num] = 0;
      i = _.indexOf(parts, finished_part);
      parts.splice(i,1);

      // activate one of the remaining parts
      if (parts.length) {
        i = _.findIndex(parts, function(el, index, collection) {
          if (el.status !== "active") {
            return true;
          }
        });
        if (i !== -1){
          parts[i].activate();
        }
      }

      // If no parts remain then the upload has finished
      if (!parts.length) {
        this.onComplete(uploadObj);
      }
    },

    // called when all parts have successfully uploaded
    onComplete: function(uploadObj) {
      var key = _.indexOf(S3MP.uploadList, uploadObj);

      // Stop the onprogress timer
      this.clearProgressTimer(key);

      // Tell the server to put together the pieces
      S3MP.completeMultipart(uploadObj, function(obj) {
        // Notify the client that the upload has succeeded when we
        // get confirmation from the server
        if (obj.location) {
          obj.extra_data ? S3MP.onComplete(uploadObj, obj.extra_data) : S3MP.onComplete(uploadObj);
        }
      });

    },

    // Called by progress_timer
    onProgress: function(key, size, done, percent, speed) {
      S3MP.onProgress(key, size, done, percent, speed);
    },

    startProgressTimer: function() {
      var last_upload_chunk = [];
      var fn = function(key) {
        progress_timer[key] = global.setInterval(function() {
          var upload, size, done, percent, speed;

          if (typeof last_upload_chunk[key] === "undefined") {
            last_upload_chunk[key] = 0;
          }

          upload = S3MP.uploadList[key];
          size = upload.size;
          done = upload.uploaded;

          _.each(upload.inprogress,function(val, index) {
            part_available = _.find(upload.parts, function(part){
              return part.num == index
            })
            if(part_available && val !== undefined) done += val;
          });

          percent = done/size * 100;
          speed = done - last_upload_chunk[key];
          last_upload_chunk[key] = done;

          upload.handler.onProgress(key, size, done, percent, speed);
        }, 1000);
      };
      return fn;
    }(),

    clearProgressTimer: function(key) {
      global.clearInterval(progress_timer[key]);
    }

  };

  // List of files may come from a FileList object or an array of files
  if (this.fileSelector) {
    files = $(this.fileSelector).get(0).files; // FileList object
  } else {
    files = this.fileList; // array specified in configuration
  }

  _.each(files, function(file, key) {
    var upload = new Upload(file, S3MP, key);
    S3MP.uploadList.push(upload);
    upload.init();
  });

};

S3MP.prototype.initiateMultipart = function(upload, cb) {
  var url, body, xhr;

  url = '/s3_multipart/uploads';
  body = JSON.stringify({ object_name  : upload.name,
                          content_type : upload.type,
                          content_size : upload.size,
                          headers      : this.headers,
                          context      : $(this.fileInputElement).data("context"),
                          uploader     : $(this.fileInputElement).data("uploader")
                        });

  xhr = this.createXhrRequest('POST', url);
  this.deliverRequest(xhr, body, cb);

};

S3MP.prototype.signPartRequest = function(id, object_name, upload_id, part, cb) {
  var content_lengths, url, body, xhr;

  content_length = part.size;
  url = "/s3_multipart/uploads/"+id;
  body = JSON.stringify({ object_name     : object_name,
    upload_id       : upload_id,
    content_length : content_length,
    part_number : part.num
  });
  xhr = this.createXhrRequest('PUT', url);
  this.deliverRequest(xhr, body, cb);
};

S3MP.prototype.completeMultipart = function(uploadObj, cb) {
  var url, body, xhr;

  url = '/s3_multipart/uploads/'+uploadObj.id;
  body = JSON.stringify({ object_name    : uploadObj.object_name,
                          upload_id      : uploadObj.upload_id,
                          content_length : uploadObj.size,
                          parts          : uploadObj.Etags
                        });

  xhr = this.createXhrRequest('PUT', url);
  this.deliverRequest(xhr, body, cb);
};

// Specify callbacks, request body, and settings for requests that contact
// the site server, and send the request.
S3MP.prototype.deliverRequest = function(xhr, body, cb) {
  var self = this;

  xhr.onload = function() {
    response = JSON.parse(this.responseText);
    if (response.error) {
      return self.onError({
        name: "ServerResponse",
        message: response.error
      });
    }
    cb(response);
  };

  xhr.onerror = function() {
    // To-do: Handle communication errors
  };

  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));

  xhr.send(body);
}

S3MP.prototype.createXhrRequest = function() {
  var xhrRequest;

  // Sniff for xhr object
  if (typeof XMLHttpRequest.constructor === "function") {
    xhrRequest = XMLHttpRequest;
  } else if (typeof XDomainRequest !== "undefined") {
    xhrRequest = XDomainRequest;
  } else {
    xhrRequest = null; // Error out to the client (To-do)
  }

  return function(method, url, cb, open) { // open defaults to true
    var args, xhr, open = true;

    args = Array.prototype.slice.call(arguments);
    if (typeof args[0] === "undefined") {
      cb = null;
      open = false;
    }

    xhr = new xhrRequest();
    if (open) { // open the request unless specified otherwise
      xhr.open(method, url, true);
    }
    xhr.onreadystatechange = cb;

    return xhr;
  };

}();

S3MP.prototype.sliceBlob = function() {
  try {
    var test_blob = new Blob();
  } catch(e) {
    return "Unsupported";
  }

  if (test_blob.slice) {
    return function(blob, start, end) {
      return blob.slice(start, end);
    }
  } else if (test_blob.mozSlice) {
    return function(blob, start, end) {
      return blob.mozSlice(start, end);
    }
  } else if (test_blob.webkitSlice) {
    return function(blob, start, end) {
      return blob.webkitSlice(start, end);
    }
  } else {
    return "Unsupported";
  }
}();

// utility function to return an upload object given a file
S3MP.prototype._returnUploadObj = function(key) {
  var uploadObj = _.find(this.uploadList, function(uploadObj) {
    return uploadObj.key === key;
  });
  return uploadObj;
};

// cancel a given file upload
S3MP.prototype.cancel = function(key) {
  var uploadObj, i;

  uploadObj = this._returnUploadObj(key);
  i = _.indexOf(this.uploadList, uploadObj);

  this.uploadList.splice(i,i+1);
  this.onCancel(key);
  this.handler.clearProgressTimer(key);
};

// pause a given file upload
S3MP.prototype.pause = function(key) {
  var uploadObj = this._returnUploadObj(key);

  _.each(uploadObj.parts, function(part, key, list) {
    if (part.status == "active") {
      part.pause();
    }
  });

  this.onPause(key);
  this.handler.clearProgressTimer(key);
};

// resume a given file upload
S3MP.prototype.resume = function(key) {
  var uploadObj = this._returnUploadObj(key);

  _.each(uploadObj.parts, function(part, key, list) {
    if (part.status == "paused") {
      part.activate();
    }
  });
  this.handler.startProgressTimer(key);
  this.onResume(key);
};

// Upload constructor
function Upload(file, o, key) {
  function Upload() {
    var upload, id, parts, part, segs, chunk_segs, chunk_lens, pipes, blob;

    upload = this;

    this.key = key;
    this.file = file;
    this.name = file.name;
    this.size = file.size;
    this.type = file.type;
    this.Etags = [];
    this.inprogress = [];
    this.uploaded = 0;
    this.status = "";

    // Break the file into an appropriate amount of chunks
    // This needs to be optimized for various browsers types/versions
    if (this.size > 1000000000) { // size greater than 1gb
      num_segs = 200;
      pipes = 2;
    } else if (this.size > 500000000) { // greater than 500mb
      num_segs = 140;
      pipes = 2;
    } else if (this.size > 100000000) { // greater than 100 mb
      num_segs = 20;
      pipes = 5;
    } else if (this.size > 50000000) { // greater than 50 mb
      num_segs = 5;
      pipes = 2;
    } else if (this.size > 10000000) { // greater than 10 mb
      num_segs = 2;
      pipes = 2;
    } else { // greater than 5 mb (S3 does not allow multipart uploads < 5 mb)
      num_segs = 1;
      pipes = 1;
    }

    chunk_segs = _.range(num_segs + 1);
    chunk_lens = _.map(chunk_segs, function(seg) {
      return Math.round(seg * (file.size/num_segs));
    });

    if (upload.sliceBlob == "Unsupported") {
      this.parts = [new UploadPart(file, 0, upload)];
    } else {
      this.parts = _.map(chunk_lens, function(len, i) {
        blob = upload.sliceBlob(file, len, chunk_lens[i+1]);
        return new UploadPart(blob, i+1, upload);
      });
      this.parts.pop(); // Remove the empty blob at the end of the array
    }

    // init function will initiate the multipart upload, sign all the parts, and
    // start uploading some parts in parallel
    this.init = function() {
      upload.initiateMultipart(upload, function(obj) {
        var id = upload.id = obj.id
          , upload_id = upload.upload_id = obj.upload_id
          , object_name = upload.object_name = obj.key // uuid generated by the server, different from name
          , parts = upload.parts;

        //upload.signPartRequests(id, object_name, upload_id, parts, function(response) {
        //  _.each(parts, function(part, key) {
        //    part.date = response.uploads[key].date;
        //    part.auth = response.uploads[key].authorization;
        //
        //    // Notify handler that an xhr request has been opened
        //    upload.handler.beginUpload(pipes, upload);
        //  });
        //});
        upload.handler.beginUpload(pipes, upload);
      });
    }
  };
  // Inherit the properties and prototype methods of the passed in S3MP instance object
  Upload.prototype = o;
  return new Upload();
}

// Upload part constructor
function UploadPart(blob, key, upload) {
  var part, xhr;

  part = this;

  this.size = blob.size;
  this.blob = blob;
  this.num = key;
  this.upload = upload;

  this.xhr = xhr = upload.createXhrRequest();
  xhr.onload = function() {
    if (part.xhr.getResponseHeader("ETag") === null) {
      upload.handler.onError(upload, part);
    } else {
      upload.handler.onPartSuccess(upload, part);
    }
  };
  xhr.onerror = function() {
    upload.handler.onError(upload, part);
  };
  xhr.upload.onprogress = _.throttle(function(e) {
    if (e.lengthComputable) {
      upload.inprogress[key] = e.loaded;
    }
  }, 1000);

};

UploadPart.prototype.activate = function() {
  var upload_part = this;
  this.upload.signPartRequest(this.upload.id, this.upload.object_name, this.upload.upload_id, this, function(response) {
    upload_part.xhr.open('PUT', '//'+upload_part.upload.bucket+'.s3.amazonaws.com/'+upload_part.upload.object_name+'?partNumber='+upload_part.num+'&uploadId='+upload_part.upload.upload_id, true);

    upload_part.xhr.setRequestHeader('x-amz-date', response.date);
    upload_part.xhr.setRequestHeader('Authorization', response.authorization);

    upload_part.xhr.send(upload_part.blob);
    upload_part.status = "active";
  });
};

UploadPart.prototype.pause = function() {
  this.xhr.abort();
  this.status = "paused";
};

return S3MP;

  }());

}(this));<commit_msg>changes in pipe config<commit_after>(function(global) {
  global.S3MP = (function() {

    // Wrap this into underscore library extension
    _.mixin({
      findIndex : function (collection, filter) {
        for (var i = 0; i < collection.length; i++) {
          if (filter(collection[i], i, collection)) {
            return i;
          }
        }
        return -1;
      }
    });
// S3MP Constructor
function S3MP(options) {
  var files
    , progress_timer = []
    , S3MP = this;

  _.extend(this, options);
  this.headers = _.object(_.map(options.headers, function(v,k) { return ["x-amz-" + k.toLowerCase(), v] }));

  this.uploadList = [];

  // Handles all of the success/failure events, and
  // progress notifiers
  this.handler = {

    // Activate an appropriate number of parts (number = pipes)
    // when all of the parts have been successfully initialized
    beginUpload: function() {
      var i = [];
      function beginUpload(pipes, uploadObj) {
        var key = uploadObj.key
          , num_parts = uploadObj.parts.length;

        if (typeof i[key] === "undefined") {
          i[key] = 0;
        }

        i[key]++;

        for (var j=0; j<pipes; j++) {
          uploadObj.parts[j].activate();
        }
        S3MP.handler.startProgressTimer(key);
        S3MP.onStart(uploadObj); // This probably needs to go somewhere else.
      }
      return beginUpload;
    }(),

    // called when an upload is paused or the network connection cuts out
    onError: function(uploadObj, part) {
      S3MP.onError(uploadObj, part);
    },

    // called when a single part has successfully uploaded
    onPartSuccess: function(uploadObj, finished_part) {
      var parts, i, ETag;

      parts = uploadObj.parts;
      finished_part.status = "complete";

      // Append the ETag (in the response header) to the ETags array
      ETag = finished_part.xhr.getResponseHeader("ETag");
      uploadObj.Etags.push({ ETag: ETag.replace(/\"/g, ''), partNum: finished_part.num });

      // Increase the uploaded count and delete the finished part
      uploadObj.uploaded += finished_part.size;
      uploadObj.inprogress[finished_part.num] = 0;
      i = _.indexOf(parts, finished_part);
      parts.splice(i,1);

      // activate one of the remaining parts
      if (parts.length) {
        i = _.findIndex(parts, function(el, index, collection) {
          if (el.status !== "active") {
            return true;
          }
        });
        if (i !== -1){
          parts[i].activate();
        }
      }

      // If no parts remain then the upload has finished
      if (!parts.length) {
        this.onComplete(uploadObj);
      }
    },

    // called when all parts have successfully uploaded
    onComplete: function(uploadObj) {
      var key = _.indexOf(S3MP.uploadList, uploadObj);

      // Stop the onprogress timer
      this.clearProgressTimer(key);

      // Tell the server to put together the pieces
      S3MP.completeMultipart(uploadObj, function(obj) {
        // Notify the client that the upload has succeeded when we
        // get confirmation from the server
        if (obj.location) {
          obj.extra_data ? S3MP.onComplete(uploadObj, obj.extra_data) : S3MP.onComplete(uploadObj);
        }
      });

    },

    // Called by progress_timer
    onProgress: function(key, size, done, percent, speed) {
      S3MP.onProgress(key, size, done, percent, speed);
    },

    startProgressTimer: function() {
      var last_upload_chunk = [];
      var fn = function(key) {
        progress_timer[key] = global.setInterval(function() {
          var upload, size, done, percent, speed;

          if (typeof last_upload_chunk[key] === "undefined") {
            last_upload_chunk[key] = 0;
          }

          upload = S3MP.uploadList[key];
          size = upload.size;
          done = upload.uploaded;

          _.each(upload.inprogress,function(val, index) {
            part_available = _.find(upload.parts, function(part){
              return part.num == index
            })
            if(part_available && val !== undefined) done += val;
          });

          percent = done/size * 100;
          speed = done - last_upload_chunk[key];
          last_upload_chunk[key] = done;

          upload.handler.onProgress(key, size, done, percent, speed);
        }, 1000);
      };
      return fn;
    }(),

    clearProgressTimer: function(key) {
      global.clearInterval(progress_timer[key]);
    }

  };

  // List of files may come from a FileList object or an array of files
  if (this.fileSelector) {
    files = $(this.fileSelector).get(0).files; // FileList object
  } else {
    files = this.fileList; // array specified in configuration
  }

  _.each(files, function(file, key) {
    var upload = new Upload(file, S3MP, key);
    S3MP.uploadList.push(upload);
    upload.init();
  });

};

S3MP.prototype.initiateMultipart = function(upload, cb) {
  var url, body, xhr;

  url = '/s3_multipart/uploads';
  body = JSON.stringify({ object_name  : upload.name,
                          content_type : upload.type,
                          content_size : upload.size,
                          headers      : this.headers,
                          context      : $(this.fileInputElement).data("context"),
                          uploader     : $(this.fileInputElement).data("uploader")
                        });

  xhr = this.createXhrRequest('POST', url);
  this.deliverRequest(xhr, body, cb);

};

S3MP.prototype.signPartRequest = function(id, object_name, upload_id, part, cb) {
  var content_lengths, url, body, xhr;

  content_length = part.size;
  url = "/s3_multipart/uploads/"+id;
  body = JSON.stringify({ object_name     : object_name,
    upload_id       : upload_id,
    content_length : content_length,
    part_number : part.num
  });
  xhr = this.createXhrRequest('PUT', url);
  this.deliverRequest(xhr, body, cb);
};

S3MP.prototype.completeMultipart = function(uploadObj, cb) {
  var url, body, xhr;

  url = '/s3_multipart/uploads/'+uploadObj.id;
  body = JSON.stringify({ object_name    : uploadObj.object_name,
                          upload_id      : uploadObj.upload_id,
                          content_length : uploadObj.size,
                          parts          : uploadObj.Etags
                        });

  xhr = this.createXhrRequest('PUT', url);
  this.deliverRequest(xhr, body, cb);
};

// Specify callbacks, request body, and settings for requests that contact
// the site server, and send the request.
S3MP.prototype.deliverRequest = function(xhr, body, cb) {
  var self = this;

  xhr.onload = function() {
    response = JSON.parse(this.responseText);
    if (response.error) {
      return self.onError({
        name: "ServerResponse",
        message: response.error
      });
    }
    cb(response);
  };

  xhr.onerror = function() {
    // To-do: Handle communication errors
  };

  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));

  xhr.send(body);
}

S3MP.prototype.createXhrRequest = function() {
  var xhrRequest;

  // Sniff for xhr object
  if (typeof XMLHttpRequest.constructor === "function") {
    xhrRequest = XMLHttpRequest;
  } else if (typeof XDomainRequest !== "undefined") {
    xhrRequest = XDomainRequest;
  } else {
    xhrRequest = null; // Error out to the client (To-do)
  }

  return function(method, url, cb, open) { // open defaults to true
    var args, xhr, open = true;

    args = Array.prototype.slice.call(arguments);
    if (typeof args[0] === "undefined") {
      cb = null;
      open = false;
    }

    xhr = new xhrRequest();
    if (open) { // open the request unless specified otherwise
      xhr.open(method, url, true);
    }
    xhr.onreadystatechange = cb;

    return xhr;
  };

}();

S3MP.prototype.sliceBlob = function() {
  try {
    var test_blob = new Blob();
  } catch(e) {
    return "Unsupported";
  }

  if (test_blob.slice) {
    return function(blob, start, end) {
      return blob.slice(start, end);
    }
  } else if (test_blob.mozSlice) {
    return function(blob, start, end) {
      return blob.mozSlice(start, end);
    }
  } else if (test_blob.webkitSlice) {
    return function(blob, start, end) {
      return blob.webkitSlice(start, end);
    }
  } else {
    return "Unsupported";
  }
}();

// utility function to return an upload object given a file
S3MP.prototype._returnUploadObj = function(key) {
  var uploadObj = _.find(this.uploadList, function(uploadObj) {
    return uploadObj.key === key;
  });
  return uploadObj;
};

// cancel a given file upload
S3MP.prototype.cancel = function(key) {
  var uploadObj, i;

  uploadObj = this._returnUploadObj(key);
  i = _.indexOf(this.uploadList, uploadObj);

  this.uploadList.splice(i,i+1);
  this.onCancel(key);
  this.handler.clearProgressTimer(key);
};

// pause a given file upload
S3MP.prototype.pause = function(key) {
  var uploadObj = this._returnUploadObj(key);

  _.each(uploadObj.parts, function(part, key, list) {
    if (part.status == "active") {
      part.pause();
    }
  });

  this.onPause(key);
  this.handler.clearProgressTimer(key);
};

// resume a given file upload
S3MP.prototype.resume = function(key) {
  var uploadObj = this._returnUploadObj(key);

  _.each(uploadObj.parts, function(part, key, list) {
    if (part.status == "paused") {
      part.activate();
    }
  });
  this.handler.startProgressTimer(key);
  this.onResume(key);
};

// Upload constructor
function Upload(file, o, key) {
  function Upload() {
    var upload, id, parts, part, segs, chunk_segs, chunk_lens, pipes, blob;

    upload = this;

    this.key = key;
    this.file = file;
    this.name = file.name;
    this.size = file.size;
    this.type = file.type;
    this.Etags = [];
    this.inprogress = [];
    this.uploaded = 0;
    this.status = "";

    // Break the file into an appropriate amount of chunks
    // This needs to be optimized for various browsers types/versions
    if (this.size > 1000000000) { // size greater than 1gb
      num_segs = 200;
      pipes = 5;
    } else if (this.size > 500000000) { // greater than 500mb
      num_segs = 50;
      pipes = 5;
    } else if (this.size > 100000000) { // greater than 100 mb
      num_segs = 16;
      pipes = 5;
    } else if (this.size > 50000000) { // greater than 50 mb
      num_segs = 5;
      pipes = 2;
    } else if (this.size > 10000000) { // greater than 10 mb
      num_segs = 1;
      pipes = 1;
    } else { // greater than 5 mb (S3 does not allow multipart uploads < 5 mb)
      num_segs = 1;
      pipes = 1;
    }

    chunk_segs = _.range(num_segs + 1);
    chunk_lens = _.map(chunk_segs, function(seg) {
      return Math.round(seg * (file.size/num_segs));
    });

    if (upload.sliceBlob == "Unsupported") {
      this.parts = [new UploadPart(file, 0, upload)];
    } else {
      this.parts = _.map(chunk_lens, function(len, i) {
        blob = upload.sliceBlob(file, len, chunk_lens[i+1]);
        return new UploadPart(blob, i+1, upload);
      });
      this.parts.pop(); // Remove the empty blob at the end of the array
    }

    // init function will initiate the multipart upload, sign all the parts, and
    // start uploading some parts in parallel
    this.init = function() {
      upload.initiateMultipart(upload, function(obj) {
        var id = upload.id = obj.id
          , upload_id = upload.upload_id = obj.upload_id
          , object_name = upload.object_name = obj.key // uuid generated by the server, different from name
          , parts = upload.parts;

        //upload.signPartRequests(id, object_name, upload_id, parts, function(response) {
        //  _.each(parts, function(part, key) {
        //    part.date = response.uploads[key].date;
        //    part.auth = response.uploads[key].authorization;
        //
        //    // Notify handler that an xhr request has been opened
        //    upload.handler.beginUpload(pipes, upload);
        //  });
        //});
        upload.handler.beginUpload(pipes, upload);
      });
    }
  };
  // Inherit the properties and prototype methods of the passed in S3MP instance object
  Upload.prototype = o;
  return new Upload();
}

// Upload part constructor
function UploadPart(blob, key, upload) {
  var part, xhr;

  part = this;

  this.size = blob.size;
  this.blob = blob;
  this.num = key;
  this.upload = upload;

  this.xhr = xhr = upload.createXhrRequest();
  xhr.onload = function() {
    if (part.xhr.getResponseHeader("ETag") === null) {
      upload.handler.onError(upload, part);
    } else {
      upload.handler.onPartSuccess(upload, part);
    }
  };
  xhr.onerror = function() {
    upload.handler.onError(upload, part);
  };
  xhr.upload.onprogress = _.throttle(function(e) {
    if (e.lengthComputable) {
      upload.inprogress[key] = e.loaded;
    }
  }, 1000);

};

UploadPart.prototype.activate = function() {
  var upload_part = this;
  this.upload.signPartRequest(this.upload.id, this.upload.object_name, this.upload.upload_id, this, function(response) {
    upload_part.xhr.open('PUT', '//'+upload_part.upload.bucket+'.s3.amazonaws.com/'+upload_part.upload.object_name+'?partNumber='+upload_part.num+'&uploadId='+upload_part.upload.upload_id, true);

    upload_part.xhr.setRequestHeader('x-amz-date', response.date);
    upload_part.xhr.setRequestHeader('Authorization', response.authorization);

    upload_part.xhr.send(upload_part.blob);
    upload_part.status = "active";
  });
};

UploadPart.prototype.pause = function() {
  this.xhr.abort();
  this.status = "paused";
};

return S3MP;

  }());

}(this));<|endoftext|>


<commit_before>import test from 'ava';
import { spy } from 'sinon';
import wait from 'wait-then';
import range from 'array-range';
import { runTrials } from '../xp-runner';

const makeTrialList = (blockCount = 2, trialCountPerBlock = 3) =>
  range(blockCount).reduce((acc, blockNumber) => {
    const block = { number: blockNumber };
    return [
      ...acc,
      ...range(trialCountPerBlock).map(number => ({ number, block }))
    ];
  }, []);

test('runTrials works as expected', async t => {
  // Will register every spy call as { type, args }
  const mainSpy = spy();
  // Create a sub spy with the provided type.
  const createSubSpy = (type, f, done = true) =>
    spy((...args) => {
      mainSpy(type, args);
      return wait().then(f && (() => f(...args))).then(r => {
        if (done) mainSpy(`* ${type}`);
        return r;
      });
    });
  // Connection fake implementation.
  const trials = makeTrialList(2, 2);
  const connection = {
    endCurrentTrial: createSubSpy('endCurrentTrial', null, false),
    getCurrentTrial: createSubSpy('getCurrentTrial', () => trials.shift()),
    flush: createSubSpy('flush')
  };
  // App fake implementation,
  const app = {
    initBlock: createSubSpy('initBlock'),
    runTrial: createSubSpy('runTrial', trial => ({
      val: `${trial.block.number}-${trial.number}`
    }))
  };
  // Run the trials.
  await runTrials(connection, app, 7);
  // Expected calls on connection and app methods.
  const expectedCalls = [
    // block 1 trial 1
    ['getCurrentTrial', []],
    ['* getCurrentTrial'],
    ['initBlock', [{ number: 0 }]],
    ['* initBlock'],
    ['flush', [7]],
    ['* flush'],
    ['runTrial', [{ number: 0, block: { number: 0 } }]],
    ['* runTrial'],
    ['endCurrentTrial', [{ val: '0-0' }]],
    // block 1 trial 2
    ['getCurrentTrial', []],
    ['* getCurrentTrial'],
    ['flush', [7]],
    ['* flush'],
    ['runTrial', [{ number: 1, block: { number: 0 } }]],
    ['* runTrial'],
    ['endCurrentTrial', [{ val: '0-1' }]],
    // block 2 trial 1
    ['getCurrentTrial', []],
    ['* getCurrentTrial'],
    ['initBlock', [{ number: 1 }]],
    ['* initBlock'],
    ['flush', [7]],
    ['* flush'],
    ['runTrial', [{ number: 0, block: { number: 1 } }]],
    ['* runTrial'],
    ['endCurrentTrial', [{ val: '1-0' }]],
    // block 2 trial 2
    ['getCurrentTrial', []],
    ['* getCurrentTrial'],
    ['flush', [7]],
    ['* flush'],
    ['runTrial', [{ number: 1, block: { number: 1 } }]],
    ['* runTrial'],
    ['endCurrentTrial', [{ val: '1-1' }]],
    // End
    ['getCurrentTrial', []],
    ['* getCurrentTrial'],
    ['flush', []],
    ['* flush']
  ];
  // Loop because that is easier to debug.
  expectedCalls.forEach((arg, i) => {
    t.deepEqual(arg, mainSpy.args[i], `Call ${i + 1} was as expected.`);
  });
  t.is(expectedCalls.length, mainSpy.args.length, 'There was no extra calls.');
});
<commit_msg>runTrials test when init block is not provided.<commit_after>import test from 'ava';
import { spy } from 'sinon';
import wait from 'wait-then';
import range from 'array-range';
import { runTrials } from '../xp-runner';

const makeTrialList = (blockCount = 2, trialCountPerBlock = 3) =>
  range(blockCount).reduce((acc, blockNumber) => {
    const block = { number: blockNumber };
    return [
      ...acc,
      ...range(trialCountPerBlock).map(number => ({ number, block }))
    ];
  }, []);

// Create a group of delayed spies, each spies create from this group is given a type
// and all spy calls can be monitored (in order) with may `all` spy.
// Also, all spies return a promise that resolves asynchronously. The resolution of the promise
// can be monitored as well.
const createDelayedSpiesGroup = () => {
  const all = spy();
  const createSpy = (type, f, done = '* ') =>
    spy((...args) => {
      all(type, args);
      return wait().then(f && (() => f(...args))).then(res => {
        if (done) all(done + type, res);
        return res;
      });
    });
  return { all, spy: createSpy };
};

test('`runTrials` works as expected when init block is provided', async t => {
  // Will register every spy call as { type, args }
  const spyGroup = createDelayedSpiesGroup();
  // Connection fake implementation.
  const trials = makeTrialList(2, 2);
  const connection = {
    endCurrentTrial: spyGroup.spy('endCurrentTrial', null, false),
    getCurrentTrial: spyGroup.spy('getCurrentTrial', () => trials.shift()),
    flush: spyGroup.spy('flush')
  };
  // App fake implementation,
  const app = {
    initBlock: spyGroup.spy('initBlock'),
    runTrial: spyGroup.spy('runTrial', trial => ({
      val: `${trial.block.number}-${trial.number}`
    }))
  };
  // Run the trials.
  await runTrials(connection, app, 7);
  // Expected calls on connection and app methods.
  const expectedCalls = [
    // block 1 trial 1
    ['getCurrentTrial', []],
    ['* getCurrentTrial', { number: 0, block: { number: 0 } }],
    ['initBlock', [{ number: 0 }]],
    ['* initBlock', undefined],
    ['flush', [7]],
    ['* flush', undefined],
    ['runTrial', [{ number: 0, block: { number: 0 } }]],
    ['* runTrial', { val: '0-0' }],
    ['endCurrentTrial', [{ val: '0-0' }]],
    // block 1 trial 2
    ['getCurrentTrial', []],
    ['* getCurrentTrial', { number: 1, block: { number: 0 } }],
    ['flush', [7]],
    ['* flush', undefined],
    ['runTrial', [{ number: 1, block: { number: 0 } }]],
    ['* runTrial', { val: '0-1' }],
    ['endCurrentTrial', [{ val: '0-1' }]],
    // block 2 trial 1
    ['getCurrentTrial', []],
    ['* getCurrentTrial', { number: 0, block: { number: 1 } }],
    ['initBlock', [{ number: 1 }]],
    ['* initBlock', undefined],
    ['flush', [7]],
    ['* flush', undefined],
    ['runTrial', [{ number: 0, block: { number: 1 } }]],
    ['* runTrial', { val: '1-0' }],
    ['endCurrentTrial', [{ val: '1-0' }]],
    // block 2 trial 2
    ['getCurrentTrial', []],
    ['* getCurrentTrial', { number: 1, block: { number: 1 } }],
    ['flush', [7]],
    ['* flush', undefined],
    ['runTrial', [{ number: 1, block: { number: 1 } }]],
    ['* runTrial', { val: '1-1' }],
    ['endCurrentTrial', [{ val: '1-1' }]],
    // End
    ['getCurrentTrial', []],
    ['* getCurrentTrial', undefined],
    ['flush', []],
    ['* flush', undefined]
  ];
  // Loop because that is easier to debug.
  expectedCalls.forEach((arg, i) => {
    t.deepEqual(arg, spyGroup.all.args[i], `Call ${i + 1} was as expected.`);
  });
  t.is(expectedCalls.length, spyGroup.all.callCount, 'There was no extra calls.');
});

test('`runTrials` works as expected when init block is not provided', async t => {
  const spyGroup = createDelayedSpiesGroup();
  // Connection fake implementation.
  const trials = makeTrialList(2, 1);
  const connection = {
    endCurrentTrial: spyGroup.spy('endCurrentTrial', null, false),
    getCurrentTrial: spyGroup.spy('getCurrentTrial', () => trials.shift()),
    flush: spyGroup.spy('flush')
  };
  // App fake implementation,
  const app = {
    runTrial: spyGroup.spy('runTrial', trial => ({
      result: `${trial.block.number}-${trial.number}`
    }))
  };
  // Run the trials.
  await runTrials(connection, app, 7);
  // Expected calls on connection and app methods.
  const expectedCalls = [
    // block 1 trial 1
    ['getCurrentTrial', []],
    ['* getCurrentTrial', { number: 0, block: { number: 0 } }],
    ['flush', [7]],
    ['* flush', undefined],
    ['runTrial', [{ number: 0, block: { number: 0 } }]],
    ['* runTrial', { result: '0-0' }],
    ['endCurrentTrial', [{ result: '0-0' }]],
    // block 2 trial 1
    ['getCurrentTrial', []],
    ['* getCurrentTrial', { number: 0, block: { number: 1 } }],
    ['flush', [7]],
    ['* flush', undefined],
    ['runTrial', [{ number: 0, block: { number: 1 } }]],
    ['* runTrial', { result: '1-0' }],
    ['endCurrentTrial', [{ result: '1-0' }]],
    // End
    ['getCurrentTrial', []],
    ['* getCurrentTrial', undefined],
    ['flush', []],
    ['* flush', undefined]
  ];
  // Loop because that is easier to debug.
  expectedCalls.forEach((arg, i) => {
    t.deepEqual(arg, spyGroup.all.args[i], `Call ${i + 1} was as expected.`);
  });
  t.is(
    spyGroup.all.callCount,
    expectedCalls.length,
    'There was no extra calls.'
  );
});
<|endoftext|>


<commit_before>import angular from "angular";
import _ from "lodash";
import { CART } from "../../utilities/events-utilities";

function CartController(cart) {
  const vm = this;
  vm.show = false;
  vm.projects = [];
  vm.count = 0;
  vm.collapsed = {};
  vm.term = "";

  /*
  This is here since this has been updated to use a standard Event,
  and not handled through angularjs.
   */
  document.addEventListener(CART.UPDATED, function() {
    getCart(false);
  });

  function getCart(collapse) {
    cart.all().then(function(data) {
      vm.count = 0;
      vm.projects = data.projects;
      _.each(vm.projects, function(p) {
        vm.count += p.samples.length;
        // Sort the samples by created date.
        p.samples.sort(function(a, b) {
          return b.createdDate - a.createdDate > 0;
        });
        if (collapse) {
          vm.collapsed[p.id] = true;
        }
      });
    });
  }

  getCart(true);
}

/**
 * Controller for functions on the cart slider
 * @param CartService The cart service to communicate with the server
 */
function CartSliderController(CartService, $uibModal) {
  const vm = this;

  vm.clear = function() {
    CartService.clear();
  };

  vm.removeProject = function(projectId) {
    CartService.removeProject(projectId);
  };

  vm.removeSample = function(projectId, sampleId) {
    CartService.removeSample(projectId, sampleId);
  };

  vm.exportToGalaxy = function() {
    CartService.all().then(function(data) {
      if (data !== null) {
        const firstProjID = data.projects[0].id;

        $uibModal.open({
          templateUrl:
            window.TL.BASE_URL + "cart/template/galaxy/project/" + firstProjID,
          controller: "GalaxyDialogCtrl as gCtrl",
          resolve: {
            openedByCart: function() {
              return true;
            },
            multiProject: function() {
              return data.length > 1;
            },
            sampleIds: function() {
              return false;
            },
            projectId: function() {
              return false;
            }
          }
        });
      }
    });
  };
}

function CartDirective() {
  return {
    restrict: "E",
    templateUrl: "/cart.html",
    replace: true,
    controllerAs: "cart",
    controller: ["CartService", CartController]
  };
}

function CartService(scope, $http) {
  const svc = this;
  const urls = {
    all: window.TL.BASE_URL + "cart",
    project: window.TL.BASE_URL + "cart/project/"
  };

  svc.all = function() {
    return $http.get(urls.all).then(function(response) {
      if (response.data) {
        return { projects: response.data.projects };
      } else {
        return [];
      }
    });
  };

  svc.clear = function() {
    //fire a DELETE to the server on the cart then broadcast the cart update event
    return $http.delete(urls.all).then(function() {
      scope.$broadcast("cart.update", {});
    });
  };

  svc.removeProject = function(projectId) {
    return $http.delete(urls.project + projectId).then(function() {
      scope.$broadcast("cart.update", {});
    });
  };

  svc.removeSample = function(projectId, sampleId) {
    return $http
      .delete(urls.project + projectId + "/samples/" + sampleId)
      .then(function() {
        scope.$broadcast("cart.update", {});
      });
  };
}

function GalaxyExportService(CartService, $http, $q) {
  const svc = this,
    samples = [];

  function addSampleFile(sampleName, sampleFilePath) {
    let sample = _.find(samples, function(sampleItr) {
      return sampleItr.name === sampleName;
    });
    if (typeof sample === "undefined") {
      sample = {
        name: sampleName,
        _links: { self: { href: "" } }, //expected by the tool
        _embedded: { sample_files: [] }
      };
      samples.push(sample);
    }
    sample._embedded.sample_files.push({
      _links: { self: { href: sampleFilePath } }
    });
  }

  function getSampleFormEntities(args) {
    const defaults = {
        addtohistory: false,
        makepairedcollection: false
      },
      p = _.extend({}, defaults, args),
      params = {
        _embedded: {
          library: { name: p.name },
          user: { email: p.email },
          addtohistory: p.addtohistory,
          makepairedcollection: p.makepairedcollection,
          oauth2: {
            code: p.authToken,
            redirect: p.redirectURI
          },
          samples: samples
        }
      };
    return [
      {
        name: "json_params",
        value: JSON.stringify(params)
      }
    ];
  }

  svc.exportFromProjSampPage = function(args, ids, projectId) {
    // Need to get an actual list of samples from the server from their ids.
    const promises = [];
    Object.keys(ids).map(function(id) {
      promises.push(
        $http
          .post(PAGE.urls.samples.idList, { sampleIds: ids[id], projectId: id })
          .then(function(result) {
            result.data.samples.forEach(function(sample) {
              addSampleFile(sample.label, sample.href);
            });
          })
      );
    });
    return $q.all(promises).then(function() {
      return getSampleFormEntities(args);
    });
  };

  svc.exportFromCart = function(args) {
    return CartService.all().then(function(data) {
      const projects = data.projects;
      _.each(projects, function(project) {
        const samples = project.samples;
        _.each(samples, function(sample) {
          addSampleFile(sample.label, sample.href);
        });
      });
      return getSampleFormEntities(args);
    });
  };
}

function GalaxyDialogCtrl(
  $uibModalInstance,
  $timeout,
  $scope,
  CartService,
  GalaxyExportService,
  openedByCart,
  multiProject,
  sampleIds,
  projectId
) {
  const vm = this;
  vm.addtohistory = true;
  vm.makepairedcollection = true;
  vm.showOauthIframe = false;
  vm.showEmailLibInput = true;
  vm.redirectURI = window.TL.BASE_URL + "galaxy/auth_code";
  vm.validation = {};

  vm.upload = function() {
    vm.validation = {};

    // Ensure email and name aren't empty
    if (vm.email === "") {
      vm.validation.email = true;
    }

    if (vm.name === "") {
      vm.validation.name = true;
    }

    // submit if no errors
    if (Object.keys(vm.validation).length === 0) {
      vm.makeOauth2AuthRequest(TL.galaxyClientID);
      vm.showEmailLibInput = false;
      vm.showOauthIframe = true;
    }
  };

  vm.makeOauth2AuthRequest = function(clientID) {
    const request = buildOauth2Request(
      clientID,
      "code",
      "read",
      vm.redirectURI
    );
    vm.iframeSrc = window.TL.BASE_URL + "api/oauth/authorize" + request;
  };

  function buildOauth2Request(clientID, responseType, scope, redirectURI) {
    return (
      "?&client_id=" +
      clientID +
      "&response_type=" +
      responseType +
      "&scope=" +
      scope +
      "&redirect_uri=" +
      redirectURI
    );
  }

  $scope.$on("galaxyAuthCode", function(e, authToken) {
    if (authToken) {
      vm.uploading = true;

      vm.showOauthIframe = false;
      vm.showEmailLibInput = true;

      if (openedByCart) {
        GalaxyExportService.exportFromCart({
          name: vm.name,
          email: vm.email,
          addtohistory: vm.addtohistory,
          makepairedcollection: vm.makepairedcollection,
          authToken: authToken,
          redirectURI: vm.redirectURI
        }).then(sendSampleForm);
      } else {
        GalaxyExportService.exportFromProjSampPage(
          {
            name: vm.name,
            email: vm.email,
            addtohistory: vm.addtohistory,
            makepairedcollection: vm.makepairedcollection,
            authToken: authToken,
            redirectURI: vm.redirectURI
          },
          sampleIds,
          projectId
        ).then(sendSampleForm);
      }
    }
  });

  function sendSampleForm(sampleFormEntities) {
    vm.sampleFormEntities = sampleFormEntities;

    if (openedByCart) {
      CartService.clear();
    }

    //$timeout is necessary because it adds a new event to the browser event queue,
    //allowing the full form to be generated before it is submitted.

    //Two timeouts are required now--this is starting to look like a real hack.
    $timeout(function() {
      $timeout(function() {
        document.getElementById("galSubFrm").submit();
        vm.close();
      });
    });
  }

  vm.setName = function(name, orgName) {
    if (multiProject) {
      vm.name = orgName;
    } else {
      vm.name = name;
    }
  };
  vm.setEmail = function(email) {
    vm.email = email;
  };
  vm.close = function() {
    $uibModalInstance.close();
  };
}

/**
 * @name cartFilter
 * @desc Filters the list of projects in the cart based on the term provided in the search input.
 * @type {Filter}
 */
function CartFilter() {
  /**
   * @param list - list to filter
   * @param term - search term to use to filter the list.
   */
  return function(list, term) {
    //filter each element in the collection
    return _.filter(list, function(item) {
      //if we have a project, check for how many samples we have left
      if (item.samples) {
        return filterList(item.samples, term).length > 0;
      }
      //if we have an individual sample, filter it
      return filterSample(item, term);
    });
  };

  function filterList(samples, term) {
    return _.filter(samples, function(s) {
      return filterSample(s, term);
    });
  }

  function filterSample(item, term) {
    term = term.toLowerCase();
    return item.label.toLowerCase().indexOf(term) > -1;
  }
}

angular
  .module("irida.cart", ["irida.notifications"])
  .service("CartService", [
    "$rootScope",
    "$http",
    CartService
  ])
  .controller("CartSliderController", [
    "CartService",
    "$uibModal",
    CartSliderController
  ])
  .controller("GalaxyDialogCtrl", [
    "$uibModalInstance",
    "$timeout",
    "$scope",
    "CartService",
    "GalaxyExportService",
    "openedByCart",
    "multiProject",
    "sampleIds",
    "projectId",
    GalaxyDialogCtrl
  ])
  .service("GalaxyExportService", [
    "CartService",
    "$http",
    "$q",
    GalaxyExportService
  ])
  .directive("cart", [CartDirective])
  .filter("cartFilter", [CartFilter]);
<commit_msg>Fixes issue with cart not displaying updated status.<commit_after>import angular from "angular";
import _ from "lodash";
import { CART } from "../../utilities/events-utilities";

function CartController(cart) {
  const vm = this;
  vm.show = false;
  vm.projects = [];
  vm.count = 0;
  vm.collapsed = {};
  vm.term = "";

  /*
  This is here since this has been updated to use a standard Event,
  and not handled through angularjs.
   */
  document.addEventListener(CART.UPDATED, function() {
    getCart(false);
  });

  function getCart(collapse) {
    cart.all().then(function(data) {
      vm.count = 0;
      vm.projects = data.projects;
      _.each(vm.projects, function(p) {
        vm.count += p.samples.length;
        // Sort the samples by created date.
        p.samples.sort(function(a, b) {
          return b.createdDate - a.createdDate > 0;
        });
        if (collapse) {
          vm.collapsed[p.id] = true;
        }
      });
    });
  }

  getCart(true);
}

/**
 * Controller for functions on the cart slider
 * @param CartService The cart service to communicate with the server
 */
function CartSliderController(CartService, $uibModal) {
  const vm = this;

  vm.clear = function() {
    CartService.clear();
  };

  vm.removeProject = function(projectId) {
    CartService.removeProject(projectId);
  };

  vm.removeSample = function(projectId, sampleId) {
    CartService.removeSample(projectId, sampleId);
  };

  vm.exportToGalaxy = function() {
    CartService.all().then(function(data) {
      if (data !== null) {
        const firstProjID = data.projects[0].id;

        $uibModal.open({
          templateUrl:
            window.TL.BASE_URL + "cart/template/galaxy/project/" + firstProjID,
          controller: "GalaxyDialogCtrl as gCtrl",
          resolve: {
            openedByCart: function() {
              return true;
            },
            multiProject: function() {
              return data.length > 1;
            },
            sampleIds: function() {
              return false;
            },
            projectId: function() {
              return false;
            }
          }
        });
      }
    });
  };
}

function CartDirective() {
  return {
    restrict: "E",
    templateUrl: "/cart.html",
    replace: true,
    controllerAs: "cart",
    controller: ["CartService", CartController]
  };
}

function CartService(scope, $http) {
  const svc = this;
  const urls = {
    all: window.TL.BASE_URL + "cart",
    project: window.TL.BASE_URL + "cart/project/"
  };

  svc.all = function() {
    return $http.get(urls.all).then(function(response) {
      if (response.data) {
        return { projects: response.data.projects };
      } else {
        return [];
      }
    });
  };

  svc.clear = function() {
    //fire a DELETE to the server on the cart then broadcast the cart update event
    return $http.delete(urls.all).then(function() {
      const event = new Event(CART.UPDATED);
      document.dispatchEvent(event);
    });
  };

  svc.removeProject = function(projectId) {
    return $http.delete(urls.project + projectId).then(function() {
      const event = new Event(CART.UPDATED);
      document.dispatchEvent(event);
    });
  };

  svc.removeSample = function(projectId, sampleId) {
    return $http
      .delete(urls.project + projectId + "/samples/" + sampleId)
      .then(function() {
        const event = new Event(CART.UPDATED);
        document.dispatchEvent(event);
      });
  };
}

function GalaxyExportService(CartService, $http, $q) {
  const svc = this,
    samples = [];

  function addSampleFile(sampleName, sampleFilePath) {
    let sample = _.find(samples, function(sampleItr) {
      return sampleItr.name === sampleName;
    });
    if (typeof sample === "undefined") {
      sample = {
        name: sampleName,
        _links: { self: { href: "" } }, //expected by the tool
        _embedded: { sample_files: [] }
      };
      samples.push(sample);
    }
    sample._embedded.sample_files.push({
      _links: { self: { href: sampleFilePath } }
    });
  }

  function getSampleFormEntities(args) {
    const defaults = {
        addtohistory: false,
        makepairedcollection: false
      },
      p = _.extend({}, defaults, args),
      params = {
        _embedded: {
          library: { name: p.name },
          user: { email: p.email },
          addtohistory: p.addtohistory,
          makepairedcollection: p.makepairedcollection,
          oauth2: {
            code: p.authToken,
            redirect: p.redirectURI
          },
          samples: samples
        }
      };
    return [
      {
        name: "json_params",
        value: JSON.stringify(params)
      }
    ];
  }

  svc.exportFromProjSampPage = function(args, ids, projectId) {
    // Need to get an actual list of samples from the server from their ids.
    const promises = [];
    Object.keys(ids).map(function(id) {
      promises.push(
        $http
          .post(PAGE.urls.samples.idList, { sampleIds: ids[id], projectId: id })
          .then(function(result) {
            result.data.samples.forEach(function(sample) {
              addSampleFile(sample.label, sample.href);
            });
          })
      );
    });
    return $q.all(promises).then(function() {
      return getSampleFormEntities(args);
    });
  };

  svc.exportFromCart = function(args) {
    return CartService.all().then(function(data) {
      const projects = data.projects;
      _.each(projects, function(project) {
        const samples = project.samples;
        _.each(samples, function(sample) {
          addSampleFile(sample.label, sample.href);
        });
      });
      return getSampleFormEntities(args);
    });
  };
}

function GalaxyDialogCtrl(
  $uibModalInstance,
  $timeout,
  $scope,
  CartService,
  GalaxyExportService,
  openedByCart,
  multiProject,
  sampleIds,
  projectId
) {
  const vm = this;
  vm.addtohistory = true;
  vm.makepairedcollection = true;
  vm.showOauthIframe = false;
  vm.showEmailLibInput = true;
  vm.redirectURI = window.TL.BASE_URL + "galaxy/auth_code";
  vm.validation = {};

  vm.upload = function() {
    vm.validation = {};

    // Ensure email and name aren't empty
    if (vm.email === "") {
      vm.validation.email = true;
    }

    if (vm.name === "") {
      vm.validation.name = true;
    }

    // submit if no errors
    if (Object.keys(vm.validation).length === 0) {
      vm.makeOauth2AuthRequest(TL.galaxyClientID);
      vm.showEmailLibInput = false;
      vm.showOauthIframe = true;
    }
  };

  vm.makeOauth2AuthRequest = function(clientID) {
    const request = buildOauth2Request(
      clientID,
      "code",
      "read",
      vm.redirectURI
    );
    vm.iframeSrc = window.TL.BASE_URL + "api/oauth/authorize" + request;
  };

  function buildOauth2Request(clientID, responseType, scope, redirectURI) {
    return (
      "?&client_id=" +
      clientID +
      "&response_type=" +
      responseType +
      "&scope=" +
      scope +
      "&redirect_uri=" +
      redirectURI
    );
  }

  $scope.$on("galaxyAuthCode", function(e, authToken) {
    if (authToken) {
      vm.uploading = true;

      vm.showOauthIframe = false;
      vm.showEmailLibInput = true;

      if (openedByCart) {
        GalaxyExportService.exportFromCart({
          name: vm.name,
          email: vm.email,
          addtohistory: vm.addtohistory,
          makepairedcollection: vm.makepairedcollection,
          authToken: authToken,
          redirectURI: vm.redirectURI
        }).then(sendSampleForm);
      } else {
        GalaxyExportService.exportFromProjSampPage(
          {
            name: vm.name,
            email: vm.email,
            addtohistory: vm.addtohistory,
            makepairedcollection: vm.makepairedcollection,
            authToken: authToken,
            redirectURI: vm.redirectURI
          },
          sampleIds,
          projectId
        ).then(sendSampleForm);
      }
    }
  });

  function sendSampleForm(sampleFormEntities) {
    vm.sampleFormEntities = sampleFormEntities;

    if (openedByCart) {
      CartService.clear();
    }

    //$timeout is necessary because it adds a new event to the browser event queue,
    //allowing the full form to be generated before it is submitted.

    //Two timeouts are required now--this is starting to look like a real hack.
    $timeout(function() {
      $timeout(function() {
        document.getElementById("galSubFrm").submit();
        vm.close();
      });
    });
  }

  vm.setName = function(name, orgName) {
    if (multiProject) {
      vm.name = orgName;
    } else {
      vm.name = name;
    }
  };
  vm.setEmail = function(email) {
    vm.email = email;
  };
  vm.close = function() {
    $uibModalInstance.close();
  };
}

/**
 * @name cartFilter
 * @desc Filters the list of projects in the cart based on the term provided in the search input.
 * @type {Filter}
 */
function CartFilter() {
  /**
   * @param list - list to filter
   * @param term - search term to use to filter the list.
   */
  return function(list, term) {
    //filter each element in the collection
    return _.filter(list, function(item) {
      //if we have a project, check for how many samples we have left
      if (item.samples) {
        return filterList(item.samples, term).length > 0;
      }
      //if we have an individual sample, filter it
      return filterSample(item, term);
    });
  };

  function filterList(samples, term) {
    return _.filter(samples, function(s) {
      return filterSample(s, term);
    });
  }

  function filterSample(item, term) {
    term = term.toLowerCase();
    return item.label.toLowerCase().indexOf(term) > -1;
  }
}

angular
  .module("irida.cart", ["irida.notifications"])
  .service("CartService", [
    "$rootScope",
    "$http",
    CartService
  ])
  .controller("CartSliderController", [
    "CartService",
    "$uibModal",
    CartSliderController
  ])
  .controller("GalaxyDialogCtrl", [
    "$uibModalInstance",
    "$timeout",
    "$scope",
    "CartService",
    "GalaxyExportService",
    "openedByCart",
    "multiProject",
    "sampleIds",
    "projectId",
    GalaxyDialogCtrl
  ])
  .service("GalaxyExportService", [
    "CartService",
    "$http",
    "$q",
    GalaxyExportService
  ])
  .directive("cart", [CartDirective])
  .filter("cartFilter", [CartFilter]);
<|endoftext|>


<commit_before>import * as rootManager from 'acceptedlanguagesui-root';
import * as localStorageManager from 'acceptedlanguagesui-localStorage';

var page = acceptedlanguages.lib.page;
var relevant = acceptedlanguages.lib.relevant;

function createButton(text, cssClass) {
  var button = document.createElement('button');
  button.setAttribute('type', 'button');
  button.className = cssClass;
  button.innerHTML = text;
  return button;
}

export function display({
  elementInsertIntoSelector = 'body',
  elementTag = 'div',
  elementId = 'acceptedlanguagesui',
  elementClass = 'acceptedlanguagesui',
  elementClassShow = 'show',
  elementClassHide = 'hide',
  buttonYesClass = 'yes',
  buttonNoClass = 'no',
  linkAttributeForMessage = 'data-message',
  linkAttributeForYes = 'data-yes',
  linkAttributeForNo = 'data-no',
  showAlways = false
} = {}) {
  var root = rootManager.getRoot();
  var localStorage = localStorageManager.getLocalStorage();

  if (!showAlways && (!localStorage || localStorage.acceptedLanguagesUIDismissedWithNo)) {
    return;
  }

  var currentLanguage = page.getCurrentLanguage();
  var relevantLanguage = relevant.getRelevantAlternateLanguages()[0];
  if (!currentLanguage || !relevantLanguage || relevantLanguage == currentLanguage) {
    return;
  }
  var href = page.getHrefForLanguage(relevantLanguage);
  var link = page.getLinkForLanguage(relevantLanguage);
  var message = link.getAttribute(linkAttributeForMessage);
  var yes = link.getAttribute(linkAttributeForYes);
  var no = link.getAttribute(linkAttributeForNo);

  var document = root.document;

  var element = document.querySelector(`#${elementId}`) || document.createElement(elementTag);
  element.setAttribute('id', elementId);
  element.className = `${elementClass} ${elementClassShow}`;
  element.innerHTML = `${message}`;

  var buttonNo = createButton(no, buttonNoClass);
  buttonNo.onclick = function() {
    element.className = `${elementClass} ${elementClassHide}`;
    localStorage.acceptedLanguagesUIDismissedWithNo = true;
  };
  element.appendChild(buttonNo);

  var buttonYes = createButton(yes, buttonYesClass);
  buttonYes.onclick = function() {
    window.location.href = href;
  };
  element.appendChild(buttonYes);

  var elementToInsertInto = document.querySelector(elementInsertIntoSelector);
  if (elementToInsertInto) {
    if (elementToInsertInto.hasChildNodes()) {
      elementToInsertInto.insertBefore(element, elementToInsertInto.firstChild);
    } else {
      elementToInsertInto.appendChild(element);
    }
  }
};
<commit_msg>Changed the option for setting the selector to `insertElementIntoSelector`.<commit_after>import * as rootManager from 'acceptedlanguagesui-root';
import * as localStorageManager from 'acceptedlanguagesui-localStorage';

var page = acceptedlanguages.lib.page;
var relevant = acceptedlanguages.lib.relevant;

function createButton(text, cssClass) {
  var button = document.createElement('button');
  button.setAttribute('type', 'button');
  button.className = cssClass;
  button.innerHTML = text;
  return button;
}

export function display({
  insertElementIntoSelector = 'body',
  elementTag = 'div',
  elementId = 'acceptedlanguagesui',
  elementClass = 'acceptedlanguagesui',
  elementClassShow = 'show',
  elementClassHide = 'hide',
  buttonYesClass = 'yes',
  buttonNoClass = 'no',
  linkAttributeForMessage = 'data-message',
  linkAttributeForYes = 'data-yes',
  linkAttributeForNo = 'data-no',
  showAlways = false
} = {}) {
  var root = rootManager.getRoot();
  var localStorage = localStorageManager.getLocalStorage();

  if (!showAlways && (!localStorage || localStorage.acceptedLanguagesUIDismissedWithNo)) {
    return;
  }

  var currentLanguage = page.getCurrentLanguage();
  var relevantLanguage = relevant.getRelevantAlternateLanguages()[0];
  if (!currentLanguage || !relevantLanguage || relevantLanguage == currentLanguage) {
    return;
  }
  var href = page.getHrefForLanguage(relevantLanguage);
  var link = page.getLinkForLanguage(relevantLanguage);
  var message = link.getAttribute(linkAttributeForMessage);
  var yes = link.getAttribute(linkAttributeForYes);
  var no = link.getAttribute(linkAttributeForNo);

  var document = root.document;

  var element = document.querySelector(`#${elementId}`) || document.createElement(elementTag);
  element.setAttribute('id', elementId);
  element.className = `${elementClass} ${elementClassShow}`;
  element.innerHTML = `${message}`;

  var buttonNo = createButton(no, buttonNoClass);
  buttonNo.onclick = function() {
    element.className = `${elementClass} ${elementClassHide}`;
    localStorage.acceptedLanguagesUIDismissedWithNo = true;
  };
  element.appendChild(buttonNo);

  var buttonYes = createButton(yes, buttonYesClass);
  buttonYes.onclick = function() {
    window.location.href = href;
  };
  element.appendChild(buttonYes);

  var elementToInsertInto = document.querySelector(insertElementIntoSelector);
  if (elementToInsertInto) {
    if (elementToInsertInto.hasChildNodes()) {
      elementToInsertInto.insertBefore(element, elementToInsertInto.firstChild);
    } else {
      elementToInsertInto.appendChild(element);
    }
  }
};
<|endoftext|>


<commit_before>/**
 * @overview An Accordion module comprised of sections that toggle open and close
 * @module Accordion.js
*/

import * as velocity from 'velocity-animate';

export const Accordion = {

  accordionSection : `.js-accordion-section`,
  accordionSectionContent : `.js-accordion-section-content`,
  accordionSectionTrigger: `.js-accordion-section-toggle`,
  openClass: `is-accordion-open`,

  /**
   * Inits accordion elements
   * @param {string} accordionEl Accordion DOM Element
   * @param {integer} [time=300] Duration for open/close transition in the Accordion
   * @returns {void}
  */
  init(accordionEl, time = 300) {
    this.accordion = document.querySelector(accordionEl);
    this.transitionDuration = time;
    this.accordionSections = this.accordion.querySelectorAll(this.accordionSection);

    [...this.accordionSections].forEach((el) => {
      const trigger = el.querySelector(this.accordionSectionTrigger);

      trigger.setAttribute(`touch-action`, `none`);
      el.setAttribute(`aria-expanded`, false);

      trigger.addEventListener(`pointerup`, (e) => {
        e.stopPropagation();

        const sectionContent = el.querySelector(this.accordionSectionContent);

        if (el.classList.contains(this.openClass)) {
          this.closeAccordionSection(el, sectionContent);
        } else {
          this.openAccordionSection(el, sectionContent);
        }
      });
    });
  },

  /**
   * Opens the given Accordion section
   * @param {object} section DOM element to toggle state class on
   * @param {object} sectionContent DOM element to toggle animation on
   * @returns {void}
  */
  openAccordionSection(section, sectionContent) {
    section.setAttribute(`aria-expanded`, true);
    section.classList.add(this.openClass);
    velocity(sectionContent, `slideDown`, this.transitionDuration);
  },

  /**
   * Closes the given Accordion
   * @param {object} section DOM element to toggle state class on
   * @param {object} sectionContent DOM element to toggle animation on
   * @returns {void}
  */
  closeAccordionSection(section, sectionContent) {
    section.setAttribute(`aria-expanded`, false);
    section.classList.remove(this.openClass);
    velocity(sectionContent, `slideUp`, this.transitionDuration);
  },
};
<commit_msg>Fix velocity import<commit_after>/**
 * @overview An Accordion module comprised of sections that toggle open and close
 * @module Accordion.js
*/

import velocity from 'velocity-animate';

export const Accordion = {

  accordionSection : `.js-accordion-section`,
  accordionSectionContent : `.js-accordion-section-content`,
  accordionSectionTrigger: `.js-accordion-section-toggle`,
  openClass: `is-accordion-open`,

  /**
   * Inits accordion elements
   * @param {string} accordionEl Accordion DOM Element
   * @param {integer} [time=300] Duration for open/close transition in the Accordion
   * @returns {void}
  */
  init(accordionEl, time = 300) {
    this.accordion = document.querySelector(accordionEl);
    this.transitionDuration = time;
    this.accordionSections = this.accordion.querySelectorAll(this.accordionSection);

    [...this.accordionSections].forEach((el) => {
      const trigger = el.querySelector(this.accordionSectionTrigger);

      trigger.setAttribute(`touch-action`, `none`);
      el.setAttribute(`aria-expanded`, false);

      trigger.addEventListener(`pointerup`, (e) => {
        e.stopPropagation();

        const sectionContent = el.querySelector(this.accordionSectionContent);

        if (el.classList.contains(this.openClass)) {
          this.closeAccordionSection(el, sectionContent);
        } else {
          this.openAccordionSection(el, sectionContent);
        }
      });
    });
  },

  /**
   * Opens the given Accordion section
   * @param {object} section DOM element to toggle state class on
   * @param {object} sectionContent DOM element to toggle animation on
   * @returns {void}
  */
  openAccordionSection(section, sectionContent) {
    section.setAttribute(`aria-expanded`, true);
    section.classList.add(this.openClass);
    velocity(sectionContent, `slideDown`, this.transitionDuration);
  },

  /**
   * Closes the given Accordion
   * @param {object} section DOM element to toggle state class on
   * @param {object} sectionContent DOM element to toggle animation on
   * @returns {void}
  */
  closeAccordionSection(section, sectionContent) {
    section.setAttribute(`aria-expanded`, false);
    section.classList.remove(this.openClass);
    velocity(sectionContent, `slideUp`, this.transitionDuration);
  },
};
<|endoftext|>